Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 201 lines (140 sloc) 9.059 kb
9d51e2c Kris Zyp Started on docs
kriszyp authored
1 [Tunguska](http://en.wikipedia.org/wiki/Tunguska_event) is a comet-based
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
2 distributed publish/subscribe hub for server side JavaScript (NodeJS, Rhino/RingoJS).
3c1b2f7 Kris Zyp Updated docs to talk about complex topologies.
kriszyp authored
3 Tunguska is publish subscribe framework for building applications around a
4 publish-subscribe system with real-time message delivery
5 to browsers. An introduction to Tunguska can be [found here](http://www.sitepen.com/blog/2010/07/19/real-time-comet-applications-on-node-with-tunguska/).
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
6 Tunguska can be installed as NPM package using:
7
8 npm install tunguska
9
3c1b2f7 Kris Zyp Updated docs to talk about complex topologies.
kriszyp authored
10 Tunguska consists of several modules:
9d51e2c Kris Zyp Started on docs
kriszyp authored
11
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
12 ## hub
9d51e2c Kris Zyp Started on docs
kriszyp authored
13
14 This is the actual publish-subscribe hub. The hub is a simple, easy to use set of channels
15 for publishing and listening for events, but includes some powerful features. To use the
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
16 hub, simply require the hub.js module to get the hub object. If you installed Tunguska, you can do:
9d51e2c Kris Zyp Started on docs
kriszyp authored
17
18 var hub = require("tunguska/hub");
19
20 Now to subscribe to a channel:
21
22 hub.subscribe("name/of/channel", function listenerFunction(message){
23 // do something with the messages that are received
24 });
25
26 To publish to a channel:
27
28 hub.publish("name/of/channel", {foo:"bar"});
29
30 And to unsubscribe:
31
32 hub.unsubscribe("name/of/channel", listenerFunction);
33
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
34 ### Return Values
e32c610 Kris Zyp Updated docs
kriszyp authored
35
36 Calls to publish, subscribe, and unsubscribe will return an array of promises that
37 represent the eventual return value from each subscriber. One can therefore determine
38 when all the messages have been delivered, and if there was failures. In a distributed
39 environment, the return value from subscription requests can be monitored to determine when the subscription
40 has been distributed to all hubs.
41
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
42 ### Globbing/Wildcards
e32c610 Kris Zyp Updated docs
kriszyp authored
43
9d51e2c Kris Zyp Started on docs
kriszyp authored
44 Tunguska supports wildcarding/globbing for subscriptions. We can subscribe to a set
45 of channels like:
46
47 hub.subscribe("name/of/*", listenerFunction);
48
49 or we can use double asterisk for recursive wildcard, to subscribe to everything:
50
51 hub.subscribe("**", listenerFunction);
52
2f4e084 Allow publishing and subscribing to tagged messages
David Starke authored
53 In addition, we can use tagged subscriptions to subscribe to a subset of tagged messages on a channel:
54
55 hub.subscribe("name/of/*:tagname", listenerFunction);
56
57 Using tags requires that objects are published with a tag:
58
59 hub.publish("name/of/channel:tagname", {foo:"bar"});
60
61 Messages that are published with a tag will be sent to all subscribers that are subscribed to a matching tag, or that are subscribed to the base channel without a tag.
62
b8c4cfc Kris Zyp Updated docs
kriszyp authored
63 Tunguska also supports named event sub-types within each channel. The subscribe
64 function takes an optional second parameter for specifying a specific event type
65 to listen for. For example,
9d51e2c Kris Zyp Started on docs
kriszyp authored
66 we could choose to only listen to the "system" messages on a channel:
67
68 hub.subscribe("name/of/channel", "system", systemListener);
69
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
70 ### Named Events
e32c610 Kris Zyp Updated docs
kriszyp authored
71
72 And we can define name of the type of events with the "type" property in our published
9d51e2c Kris Zyp Started on docs
kriszyp authored
73 messages. For example:
74
e32c610 Kris Zyp Updated docs
kriszyp authored
75 hub.publish("name/of/channel", {type:"system"}); // will fire systemListener
76 hub.publish("name/of/channel", {type:"chat"}); // will not fire systemListener
9d51e2c Kris Zyp Started on docs
kriszyp authored
77
78 Tunguska itself fires a special "monitored" event whenever a channel has one or more subscribers, and
79 whenever a channel becomes free of any subscribers. For example:
80
81 hub.subscribe("name/of/channel", "monitored", function(message){
82 if(message.monitored){
83 // name/of/channel has at least one subscriber now
84 }else{
85 // name/of/channel has no subscribers now
86 }
87 });
88
e32c610 Kris Zyp Updated docs
kriszyp authored
89 (This is used by the connectors)
90
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
91 ### Client Identity/Echo Suppression
9d51e2c Kris Zyp Started on docs
kriszyp authored
92
93 Tunguska provides echo suppression by defining client identities. This is an important
94 feature for distributed pubsub because it allows you to define efficient message routing
b8c4cfc Kris Zyp Updated docs
kriszyp authored
95 without messages bouncing back and forth. To define a client identity, you can call
e32c610 Kris Zyp Updated docs
kriszyp authored
96 fromClient with a client id, which will return a new hub interface which will
b8c4cfc Kris Zyp Updated docs
kriszyp authored
97 suppress all messages from this client. :
9d51e2c Kris Zyp Started on docs
kriszyp authored
98
b8c4cfc Kris Zyp Updated docs
kriszyp authored
99
100 hub.fromClient("client-1").subscribe("name/of/channel", function listenerFunction(message){
9d51e2c Kris Zyp Started on docs
kriszyp authored
101 // do something with the messages that are received
b8c4cfc Kris Zyp Updated docs
kriszyp authored
102 });
9d51e2c Kris Zyp Started on docs
kriszyp authored
103
87d5f40 Kris Zyp Fixed spacing
kriszyp authored
104 The clientId property may be an array if there are a list of client of client identities that
105 should be excluded.
106
e32c610 Kris Zyp Updated docs
kriszyp authored
107 The hub interface returned from the fromClient call can also be used to publish messages.
b8c4cfc Kris Zyp Updated docs
kriszyp authored
108 A message with a from a client will be withheld from any listener defined through that
109 client. For example:
9d51e2c Kris Zyp Started on docs
kriszyp authored
110
b8c4cfc Kris Zyp Updated docs
kriszyp authored
111 hub.fromClient("client-1").publish("name/of/channel", {name:"msg-1"}); // will not fire the listenerFunction above
112 hub.fromClient("client-2").publish("name/of/channel", {name:"msg-2"}); // will fire the listenerFunction
9d51e2c Kris Zyp Started on docs
kriszyp authored
113
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
114 ### jsgi/comet
9d51e2c Kris Zyp Started on docs
kriszyp authored
115
116 This module consists of several JSGI appliances.
117
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
118 #### Connections
119
120 require("tunguska/jsgi/comet").Connections(nextApp)
121
122 This a middleware appliance for creating and
b8c4cfc Kris Zyp Updated docs
kriszyp authored
123 using a pool of client connection entities that can be shared across requests. This can
124 be useful to use directly if non-comet requests may add or alter subscriptions for
125 another comet connection that shares the same virtual connection entity. Connections
126 are defined by including a "Client-Id" header in a request. All requests that share the
127 same Client-Id share the same connection object. The nextApp is called after connection
128 handling.
129
130 Connections are available within downstream JSGI applications from
131 request.clientConnection. The connection queue object has the following properties/methods:
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
132 * send(message) - This can be called to send a message to any connected client
133 * onclose() - This event is called/triggered when a connection is closed
134
135 #### Broadcaster
b8c4cfc Kris Zyp Updated docs
kriszyp authored
136
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
137 require("tunguska/jsgi/comet").Broadcaster(path, subscriptionApp, nextApp)
138
139 This provides a comet end-point. A request that matches the path will be handled by the
b8c4cfc Kris Zyp Updated docs
kriszyp authored
140 Broadcaster and any messages in the client connection queue will be sent to the client,
141 or if the connection queue is empty, it will wait until a message is sent to the connection
142 and the broadcaster will deliver the message to the client. When the path is matched,
143 the subscriptionApp will be called next and can handle defining any subscriptions that
144 should be made (to the hub) and routing received messages to the connection queue.
145 If the path is not matched, the nextApp is called.
146
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
147 #### Subscriber
148
149 require("tunguska/jsgi/comet").Subscriber(subscriptions, nextApp)
150
151 This is a subscription handling appliance that will either use list of subscriptions provided in the
b8c4cfc Kris Zyp Updated docs
kriszyp authored
152 setup argument, or if the subscriptions argument is omitted, any subscriptions
153 provided in the request, and subscribes to given channels on the hub, and forwards any received messages
154 to the connection queue object.
155
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
156 #### Notifications
157
158 require("tunguska/jsgi/comet").Notifications(path, subscriptions, nextApp)
159
160 This combines all three middleware appliance above into a single middleware appliance. The path defines
b8c4cfc Kris Zyp Updated docs
kriszyp authored
161 the comet end-point. The subscriptions parameter is optional and can specify the set
162 of channels to subscribe to. The nextApp is called for requests that don't match the path.
163
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
164 ### connector
b8c4cfc Kris Zyp Updated docs
kriszyp authored
165
6bbf4f3 Kris Zyp Updated docs
kriszyp authored
166 require("tunguska/connector").Connector(connectionId, stream);
167
b8c4cfc Kris Zyp Updated docs
kriszyp authored
168 Connectors provide a means for connecting hubs in different processes and on
169 different machines, thus allowing for distributed publish/subscribe systems. Connectors
3c1b2f7 Kris Zyp Updated docs to talk about complex topologies.
kriszyp authored
170 are provided for worker-based communication, WebSocket communication
171 (and in the future, HTTP-based communication) between hubs. The connectors
172 communicate through a framed stream, following the
173 WebSocket API. One can easily use a WebSocket connection or one can use the
174 framed stream connection provided by multi-node for connecting processes. Here
175 is an example of connecting the processes initiated by multi-node for distributed
176 pub/sub across all the processes:
177
8787219 Kris Zyp Get the spacing right for code snippets
kriszyp authored
178 var multiNode = require("multi-node/multi-node"),
179 Connector = require("tunguska/connector").Connector;
180 // start the multiple processes
181 var nodes = multiNode.listen({port: 80, nodes: 4}, serverObject);
182 // add a listener for each connection to the other sibling process
183 nodes.addListener("node", function(stream){
184 // create a new connector using the framed WS stream
185 Connector("local-workers", multiNode.frameStream(stream));
186 });
3c1b2f7 Kris Zyp Updated docs to talk about complex topologies.
kriszyp authored
187
188 The Connection constructor takes two arguments:
189
8787219 Kris Zyp Get the spacing right for code snippets
kriszyp authored
190 Connector(connectionId, framedWebSocketStream);
3c1b2f7 Kris Zyp Updated docs to talk about complex topologies.
kriszyp authored
191
192 The connectionId identifies the source of the messages, and utilizes echo suppression
193 to route messages properly. A message that is broadcast from one connection won't
194 get rerouted back to the same connector/client causing duplicate messages. The
195 second argument is the framed stream that follows the WebSocket API.
196
197 One can utilize different connectionIds to connect different networks for more sophisticated
198 topologies. For example, one could have a set of connectors for local processes with one id ("local-workers"),
199 and a connector for a remote server with another id ("servers"). A message received the other
200 server would not be echoed back to that server, but it would properly get routed to
201 the local worker processes.
Something went wrong with that request. Please try again.