-
Notifications
You must be signed in to change notification settings - Fork 5
Tutorial
"router" is a Go package for remote channel communication based on peer-peer pub/sub model. Basically we attach a send channel to an id in router to send msgs, and attach a recv channel to an id to recv msgs. If these 2 ids match, the msgs from send channel will be "routed" to recv channel, e.g.
rot := router.New(...) chan1 := make(chan string) chan2 := make(chan string) chan3 := make(chan string) rot.AttachSendChan(PathID("/sports/basketball"), chan1) rot.AttachRecvChan(PathID("/sports/basketball"), chan2) rot.AttachRecvChan(PathID("/sports/*"), chan3)
We can use integers, strings, pathnames, or structs as Ids in router (maybe regex ids and tuple id in future).
we can connect two routers so that channels attached to routerA can communicate with channels attached to routerB transparently.
type Router interface { //---- core api ---- //Attach chans to id in router, with an optional argument (chan *BindEvent) //When specified, the optional argument will serve two purposes: //1. used to tell when the remote peers connecting/disconn //2. in AttachRecvChan, used as a flag to ask router to keep recv chan open when all senders close //the returned RoutedChan object can be used to find the number of bound peers: routCh.NumPeers() AttachSendChan(Id, interface{}, ...interface{}) (*RoutedChan, os.Error) //3. When attaching recv chans, an optional integer can specify the internal buffering size AttachRecvChan(Id, interface{}, ...interface{}) (*RoutedChan, os.Error) //Detach sendChan/recvChan from router DetachChan(Id, interface{}) os.Error //Shutdown router Close() //Connect this router to another router. //1. internally it calls Proxy.Connect(...) to do the real job //2. The connection can be disconnected by calling Proxy.Close() on returned proxy object //3. for more compilcated connection setup (such as setting IdFilter and IdTranslator), use Proxy.Connect() instead //Connect to a local router Connect(Router) (Proxy, Proxy, os.Error) //Connect to a remote router thru io conn //1. io.ReadWriteCloser: transport connection //2. MarshalingPolicy: gob or json marshaling //3. bool flag: turn on flow control on connection ConnectRemote(io.ReadWriteCloser, MarshalingPolicy, ...bool) (Proxy, os.Error) //--- other utils --- //return pre-created SysIds according to the router's id-type, with ScopeGlobal / MemberLocal SysID(idx int) Id //create a new SysId with "args..." specifying scope/membership NewSysID(idx int, args ...int) Id //return all ids and their ChanTypes from router's namespace which satisfy predicate IdsForSend(predicate func(id Id) bool) map[interface{}]*IdChanInfo IdsForRecv(predicate func(id Id) bool) map[interface{}]*IdChanInfo } func router.New(seedId Id, bufSize int, disp DispatchPolicy, args ...) Router
Here is a sample showing various usage: http://code.google.com/p/go-router/source/browse/trunk/samples/test.go
Each id contains three pieces of data:
- Val - used as key in routing
- Scope - the scope to send/recv msgs
- Membership - local/remote peer, identifying if peers are inside same router or not
- Scope Scope defines the range of send/recv operations. there are three scopes:
- ScopeLocal`:` send msgs to local peers in the same router, or recv msgs from local peers
- ScopeRemote: send msgs to remote peers in connected routers, or recv msgs from remote peers
- ScopeGlobal: send msgs to all local/remote peers, or recv msgs from all local / remote peers the default attributes of id is ScopeGlobal (and Membership = MemberLocal)
- matching algorithm different types of ids use diff matching algorithms:
- exact match: for int/string/struct ids
- prefix match: for pathname ids
- assoc match: for regex ids or tuple ids (future)
- binding When send/recv chans are attached to router, their ids are matched against ids of chans which are already attached, and their bindings will be decided:
- For send chan, its bindings is the set of recv chans with matched id.
- For recv chan, its bindings is the set of send chans with matched id.
router is created with the following constructor:
rot := router.New(SeedId, chanBufSize, dispatchPolicy, ...)
dispatchPolicy defines how the values from a send chan are dispatched to its bound recv chans. Three simple dispatchers can be used now: broadcast/round-robin/random.
When making changes to router's namespace (Attach/Detach/Connect), the types of ids and chans are checked during runtime
- type checking inside a single router when attaching/detaching chans to ids in router, verify that id is of same type of router's id type, and if id is already inside router, verify added chan is of same type as chans already attached to this id
- type checking during router connection when two routers are connected, verify they have the same id type, and if they have matching ids, verify matching ids have the same chan type in both routers
there are eight system ids:
ConnId DisconnId ErrorId ReadyId PubId UnPubId SubId UnSubId
user code can subscribe (attach recv chan to) to the above ids to learn system state changes and react accordingly
- namespace monitoring user code can track router's namespace change by subscribing `(attach recv [chan IdChanInfo] to)` these four system ids: PubId/UnPubId/SubId/UnSubId. then user code will recv msgs when new chans are attached or existing chans are detached to router. There is a sample "chat" client/server in package and the chat server learns about new subjects clients are publishing by subscribing to "PubId": http://code.google.com/p/go-router/source/browse/trunk/samples/chatsrv.go
user code can call `router.IdsForSend(predicate)/IdsForRecv(predicate)` to get a snapshot of current router namespace
- connection monitoring user code can track the connection status of its router to remote routers by subscribing `(attach recv [chan ConnInfoMsg])` to these four system ids: ConnId/DisconnId/ErrorId/ReadyId
- logging and Logger
- besides the above eight core system ids, there are two other ids: RouterLogId and RouterFaultId. They are normal ids and are predefined so that we can have logging and fault-reporting for router's internal implementation. Applications can define their own ids for app specific logging and fault reporting
- to add logging to app code, embed Logger and use its two methods `Log()/LogError()`.
- to recv log msgs, attach a recv `[chan *LogRecord]` to RouterLogId or app log ids. If attached to LogId with ScopeLocal, recv chan will recv log msgs from local router. If attached with ScopeGlobal, recv chan will also recv/pull log msgs from connected remote routers.
- If no recv chan is attached to LogId, logging is disabled without any log msgs buffered
- fault handling and FaultReporter
- raising fault is basically sending FaultRecord msgs to RouterFaultId, or app specific fault ids.
- to add fault reporting to app code, embed FaultRaiser and use its method `Raise()`.
- to handle/manage faults, attach a recv `[chan *FaultRecord]` to FaultId. If attached to FaultId with ScopeLocal, recv chan will recv FaultRecord msgs from local router. If attached with ScopeGlobal, recv chan will also recv/pull FaultRecord msgs from connected remote routers.
- If no recv chan is attached to FaultId, there is no fault handling. calling `Raise()` will crash app.
- marshaling marshaling/demarshaling are exposed thru three interfaces: MarshalingPolicy/Marshaler/Demarshaler. there are two implemetations: GobMarshaling using "gob" and JsonMarshaling using "json"
- name-sapce merge protocol. when two routers are connected, their namespaces are merged as following to enable chans in one router to communicate to chans in the other router transparently:
- Ids merging from router2 to router1: all ids in the intersection of router1's input interface (its set of recv ids with global / remote scope) and router2's output interface (its set of send ids with global / remote scope)
- Ids merging from router1 to router2: all ids in the intersection of router2's input interface (its set of recv ids with global / remote scope) and router1's output interface (its set of send ids with global / remote scope)
- new ids are propagated automatically to connected routers according to its id / membership / scope.
- when routers are disconnected, routers' namespaces will be updated automatically so that all publications and subscriptions from remote routers will be removed.