# AMP Routes

## Overview

Normally, an AMP connection is between two `AMP` instances; each instance receives all AMP boxes sent by the other side and handles them by interpreting them as commands, responses to commands, or in some other way. This typically means that the logic for handling boxes on each side of the connection is completely defined by a single object. Sometimes it is useful to allow multiple objects, perhaps of different types, to participate in defining this logic.

`epsilon.amprouter` implements utilities which allow an arbitrary number of objects, providers of `IBoxReceiver` (for example, instances of `AMP`), to define how received AMP boxes are interpreted. This is useful to multiplex unrelated `AMP` instances over a single TCP connection, to split up a single AMP protocol into multiple simpler protocols, and for many other purposes.

Readers should familiarize themselves with the following concepts in order to understand all sections of this document:

- Twisted TCP clients and TCP servers
- Using Deferreds
- Twisted `AMP`

## Routers

When working with routes, the object primarily of interest will be a Router instance. Each AMP client and server will have a `Router` instance which they can use to create new routes. They will use its `Router.bindRoute` method to set up whatever routes they require.

## Servers

`epsilon.amprouter` does not define a command for creating new routes because different applications have different requirements for how new routes are set up. An application may want to negotiate about the `IBoxReceiver` implementation which is associated with a route, it may want to supply initial arguments to that object, it may want to do version negotiation, and so on. The first thing an application using routes must do, then, is to define a way to create new routes. Consider the following example which allows routes to be created with a `NewRoute` AMP command and associates them with a parameterized `IBoxReceiver` implementation.

Creation of new routes

`AMPRouteServerFactory.buildProtocol` creates new `RoutingAMP` instances, each with a new `Router`. The `Router` instance will become the `RoutingAMP` instance's `boxReceiver` attribute. This is important for two reasons. First, it allows the router to work by causing all AMP boxes received from the connection to be delivered to the router to be dispatched appropriately. Second, it gives the `RoutingAMP` instance a reference to the `Router` instance; this is necessary so that new routes can be created.

After creating the `Router` and `RoutingAMP`, `buildProtocol` also sets up the `RoutingAMP` instance to be the default receiver by binding it to the `None`. All AMP boxes without routing information will be delivered to the default receiver. This is important because it allows the `NewRoute` command to be handled by the `RoutingAMP` instance.

`RoutingAMP`'s `NewRoute` responder uses `self.boxReceiver`, the `Router` instance provided by the factory, to bind the return value of `self.factory.routeProtocol()` to a new route. Then, it connects the route to the identifier specified in the `NewRoute` command. Finally, it returns the identifier of the route it has just created. Once this has happened, the route is completely set up on the server.

Finally, the `connect` function wraps up the necessary calls to routing methods and a use of the `NewRoute` command to form the client side of the setup.

First, let's look at an example of using `AMPRouteServerFactory` and `RoutingAMP` to run a server.

Routed counters server

In this example, a simple counting protocol is hooked up to the server. Each route which is created is associated with a new instance of this protocol. The protocol does just one simple thing, it keeps track of how many times the `Count` command is issued to it and returns this value in the response to that command.

Next we'll look at how a client can connect to this server, create new routes, and issue commands over them.

## Clients

Just as servers must, clients must first set up a route before they can send boxes over it. A client uses the same methods as the server, `Router.bindRoute` and `Route.connectTo`, to set up a new route. Here's an example which makes one TCP connection to an AMP server, sets up three routes, and then issues multiple commands over each of them.

Routed counters client

Note first how `main` creates an `AMP` with a `Router` instance. Note also how `makeRoutes` binds and connects the protocol to the default route. This mirrors the route setup which was done on the server and is necessary for the same reasons.

Once an AMP connection is set up and the default route is bound, `makeRoutes` uses the previously defined `connect` function to establish three new routes. Each route is associated with a `CountClient` instance which will issue several count commands and report the results. The results of each command are tracked so that when they have all been received the client can exit.