faye 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +11 -0
- data/Manifest.txt +7 -0
- data/README.txt +116 -34
- data/Rakefile +6 -1
- data/build/faye-client-min.js +1 -1
- data/build/faye.js +515 -103
- data/examples/node/app.js +4 -4
- data/examples/node/client.js +23 -0
- data/examples/node/faye-client-min.js +1 -1
- data/examples/node/faye.js +515 -103
- data/examples/rack/client.rb +25 -0
- data/examples/shared/public/index.html +0 -2
- data/jake.yml +5 -2
- data/lib/faye-client-min.js +1 -1
- data/lib/faye.rb +2 -3
- data/lib/faye/channel.rb +14 -13
- data/lib/faye/client.rb +246 -0
- data/lib/faye/connection.rb +18 -17
- data/lib/faye/namespace.rb +16 -0
- data/lib/faye/rack_adapter.rb +12 -2
- data/lib/faye/server.rb +19 -20
- data/lib/faye/transport.rb +103 -0
- data/test/scenario.js +99 -0
- data/test/test_channel.rb +19 -13
- data/test/test_clients.js +177 -0
- data/test/test_server.rb +42 -0
- metadata +23 -6
data/lib/faye/rack_adapter.rb
CHANGED
|
@@ -9,6 +9,7 @@ module Faye
|
|
|
9
9
|
ASYNC_RESPONSE = [-1, {}, []].freeze
|
|
10
10
|
|
|
11
11
|
DEFAULT_ENDPOINT = '/bayeux'
|
|
12
|
+
SCRIPT_PATH = File.join(ROOT, 'faye-client-min.js')
|
|
12
13
|
|
|
13
14
|
TYPE_JSON = {'Content-Type' => 'text/json'}
|
|
14
15
|
TYPE_SCRIPT = {'Content-Type' => 'text/javascript'}
|
|
@@ -23,6 +24,15 @@ module Faye
|
|
|
23
24
|
@server = Server.new(@options)
|
|
24
25
|
end
|
|
25
26
|
|
|
27
|
+
def get_client
|
|
28
|
+
@client ||= Client.new(@server)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def run(port)
|
|
32
|
+
handler = Rack::Handler.get('thin')
|
|
33
|
+
handler.run(self, :Port => port)
|
|
34
|
+
end
|
|
35
|
+
|
|
26
36
|
def call(env)
|
|
27
37
|
request = Rack::Request.new(env)
|
|
28
38
|
case request.path_info
|
|
@@ -40,11 +50,11 @@ module Faye
|
|
|
40
50
|
response
|
|
41
51
|
end
|
|
42
52
|
rescue
|
|
43
|
-
[400,
|
|
53
|
+
[400, TYPE_TEXT, 'Bad request']
|
|
44
54
|
end
|
|
45
55
|
|
|
46
56
|
when @script then
|
|
47
|
-
[200, TYPE_SCRIPT, File.new(
|
|
57
|
+
[200, TYPE_SCRIPT, File.new(SCRIPT_PATH)]
|
|
48
58
|
|
|
49
59
|
else
|
|
50
60
|
env['faye.server'] = @server
|
data/lib/faye/server.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
module Faye
|
|
2
2
|
class Server
|
|
3
3
|
def initialize(options = {})
|
|
4
|
-
@options
|
|
5
|
-
@channels
|
|
6
|
-
@clients
|
|
4
|
+
@options = options
|
|
5
|
+
@channels = Channel::Tree.new
|
|
6
|
+
@clients = {}
|
|
7
|
+
@namespace = Namespace.new
|
|
7
8
|
end
|
|
8
9
|
|
|
9
10
|
# Notifies the server of stale connections that should be deleted
|
|
@@ -39,12 +40,6 @@ module Faye
|
|
|
39
40
|
|
|
40
41
|
private
|
|
41
42
|
|
|
42
|
-
def generate_id
|
|
43
|
-
id = Faye.random
|
|
44
|
-
id = Faye.random while @clients.has_key?(id)
|
|
45
|
-
connection(id).id
|
|
46
|
-
end
|
|
47
|
-
|
|
48
43
|
def connection(id)
|
|
49
44
|
return @clients[id] if @clients.has_key?(id)
|
|
50
45
|
client = Connection.new(id, @options)
|
|
@@ -62,6 +57,8 @@ module Faye
|
|
|
62
57
|
client_id = message['clientId']
|
|
63
58
|
channel = message['channel']
|
|
64
59
|
|
|
60
|
+
@channels.glob(channel).each { |c| c << message }
|
|
61
|
+
|
|
65
62
|
if Channel.meta?(channel)
|
|
66
63
|
response = __send__(Channel.parse(channel)[1], message, local)
|
|
67
64
|
|
|
@@ -82,8 +79,6 @@ module Faye
|
|
|
82
79
|
|
|
83
80
|
return callback[[]] if message['clientId'].nil? or Channel.service?(channel)
|
|
84
81
|
|
|
85
|
-
@channels.glob(channel).each { |c| c << message }
|
|
86
|
-
|
|
87
82
|
callback[ { 'channel' => channel,
|
|
88
83
|
'successful' => true,
|
|
89
84
|
'id' => message['id'] } ]
|
|
@@ -97,23 +92,27 @@ module Faye
|
|
|
97
92
|
def handshake(message, local = false)
|
|
98
93
|
response = { 'channel' => Channel::HANDSHAKE,
|
|
99
94
|
'version' => BAYEUX_VERSION,
|
|
100
|
-
'supportedConnectionTypes' => CONNECTION_TYPES,
|
|
101
95
|
'id' => message['id'] }
|
|
102
96
|
|
|
103
97
|
response['error'] = Error.parameter_missing('version') if message['version'].nil?
|
|
104
98
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
99
|
+
unless local
|
|
100
|
+
response['supportedConnectionTypes'] = CONNECTION_TYPES
|
|
101
|
+
|
|
102
|
+
client_conns = message['supportedConnectionTypes']
|
|
103
|
+
if client_conns
|
|
104
|
+
common_conns = client_conns.select { |c| CONNECTION_TYPES.include?(c) }
|
|
105
|
+
response['error'] = Error.conntype_mismatch(*client_conns) if common_conns.empty?
|
|
106
|
+
else
|
|
107
|
+
response['error'] = Error.parameter_missing('supportedConnectionTypes')
|
|
108
|
+
end
|
|
111
109
|
end
|
|
112
110
|
|
|
113
111
|
response['successful'] = response['error'].nil?
|
|
114
112
|
return response unless response['successful']
|
|
115
113
|
|
|
116
|
-
|
|
114
|
+
client_id = @namespace.generate
|
|
115
|
+
response['clientId'] = connection(client_id).id
|
|
117
116
|
response
|
|
118
117
|
end
|
|
119
118
|
|
|
@@ -184,7 +183,7 @@ module Faye
|
|
|
184
183
|
|
|
185
184
|
subscription.each do |channel|
|
|
186
185
|
next if response['error']
|
|
187
|
-
response['error'] = Error.channel_forbidden(channel) unless Channel.subscribable?(channel)
|
|
186
|
+
response['error'] = Error.channel_forbidden(channel) unless local or Channel.subscribable?(channel)
|
|
188
187
|
response['error'] = Error.channel_invalid(channel) unless Channel.valid?(channel)
|
|
189
188
|
|
|
190
189
|
next if response['error']
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'em-http'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Faye
|
|
5
|
+
|
|
6
|
+
class Transport
|
|
7
|
+
def initialize(client, endpoint)
|
|
8
|
+
@client = client
|
|
9
|
+
@endpoint = endpoint
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def connection_type
|
|
13
|
+
self.class.connection_type
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def send(message, &block)
|
|
17
|
+
if message.is_a?(Hash) and not message.has_key?('id')
|
|
18
|
+
message['id'] = @client.namespace.generate
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
request(message) { |responses|
|
|
22
|
+
if block_given?
|
|
23
|
+
[responses].flatten.each do |response|
|
|
24
|
+
|
|
25
|
+
if message.is_a?(Hash) and response['id'] == message['id']
|
|
26
|
+
block.call(response)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if response['advice']
|
|
30
|
+
@client.handle_advice(response['advice'])
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if response['data'] and response['channel']
|
|
34
|
+
@client.send_to_subscribers(response)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
@transports = {}
|
|
43
|
+
|
|
44
|
+
class << self
|
|
45
|
+
attr_accessor :connection_type
|
|
46
|
+
|
|
47
|
+
def get(client, connection_types = nil)
|
|
48
|
+
endpoint = client.endpoint
|
|
49
|
+
connection_types ||= supported_connection_types
|
|
50
|
+
|
|
51
|
+
candidate_class = @transports.find do |type, klass|
|
|
52
|
+
connection_types.include?(type) and
|
|
53
|
+
klass.usable?(endpoint)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
unless candidate_class
|
|
57
|
+
raise "Could not find a usable connection type for #{ endpoint }"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
candidate_class.last.new(client, endpoint)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def register(type, klass)
|
|
64
|
+
@transports[type] = klass
|
|
65
|
+
klass.connection_type = type
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def supported_connection_types
|
|
69
|
+
@transports.keys
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
class HttpTransport < Transport
|
|
75
|
+
def self.usable?(endpoint)
|
|
76
|
+
endpoint.is_a?(String)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def request(message, &block)
|
|
80
|
+
params = {:message => JSON.unparse(message)}
|
|
81
|
+
request = EventMachine::HttpRequest.new(@endpoint).post(:body => params, :timeout => -1)
|
|
82
|
+
request.callback do
|
|
83
|
+
block.call(JSON.parse(request.response))
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
Transport.register 'long-polling', HttpTransport
|
|
88
|
+
|
|
89
|
+
class LocalTransport < Transport
|
|
90
|
+
def self.usable?(endpoint)
|
|
91
|
+
endpoint.is_a?(Server)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def request(message, &block)
|
|
95
|
+
@endpoint.process(message, true) do |response|
|
|
96
|
+
block.call(response)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
Transport.register 'in-process', LocalTransport
|
|
101
|
+
|
|
102
|
+
end
|
|
103
|
+
|
data/test/scenario.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
var sys = require('sys'),
|
|
2
|
+
path = require('path'),
|
|
3
|
+
http = require('http'),
|
|
4
|
+
assert = require('assert'),
|
|
5
|
+
faye = require('../build/faye');
|
|
6
|
+
|
|
7
|
+
Scenario = Faye.Class({
|
|
8
|
+
initialize: function(name, block) {
|
|
9
|
+
this._name = name;
|
|
10
|
+
this._block = block;
|
|
11
|
+
this._clients = {};
|
|
12
|
+
this._inbox = {};
|
|
13
|
+
this._pool = 0;
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
run: function() {
|
|
17
|
+
sys.puts('\n' + this._name);
|
|
18
|
+
sys.puts('----------------------------------------------------------------');
|
|
19
|
+
this._block.call(this);
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
server: function(port) {
|
|
23
|
+
sys.puts('Starting server on port ' + port);
|
|
24
|
+
this._endpoint = 'http://0.0.0.0:' + port + '/comet';
|
|
25
|
+
var comet = this._comet = new faye.NodeAdapter({mount: '/comet', timeout: 30});
|
|
26
|
+
this._server = http.createServer(function(request, response) {
|
|
27
|
+
comet.call(request, response);
|
|
28
|
+
});
|
|
29
|
+
this._server.listen(port);
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
httpClient: function(name, channels) {
|
|
33
|
+
this._setupClient(new faye.Client(this._endpoint), name, channels);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
localClient: function(name, channels) {
|
|
37
|
+
this._setupClient(this._comet.getClient(), name, channels);
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
_setupClient: function(client, name, channels) {
|
|
41
|
+
Faye.each(channels, function(channel) {
|
|
42
|
+
sys.puts('Client ' + name + ' subscribing to ' + channel);
|
|
43
|
+
client.subscribe(channel, function(message) {
|
|
44
|
+
var box = this._inbox[name];
|
|
45
|
+
box[channel] = box[channel] || [];
|
|
46
|
+
box[channel].push(message);
|
|
47
|
+
}, this);
|
|
48
|
+
}, this);
|
|
49
|
+
this._clients[name] = client;
|
|
50
|
+
this._inbox[name] = {};
|
|
51
|
+
this._pool += 1;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
send: function(from, channel, message) {
|
|
55
|
+
var self = this;
|
|
56
|
+
setTimeout(function() {
|
|
57
|
+
var displayMessage = JSON.stringify(message);
|
|
58
|
+
sys.puts('Client ' + from + ' publishing ' + displayMessage + ' to ' + channel);
|
|
59
|
+
self._clients[from].publish(channel, message);
|
|
60
|
+
}, 500);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
checkInbox: function(expectedInbox) {
|
|
64
|
+
var self = this;
|
|
65
|
+
setTimeout(function() {
|
|
66
|
+
self._checkInbox(expectedInbox);
|
|
67
|
+
sys.puts('Shutting down server\n');
|
|
68
|
+
Faye.each(this._clients, function(name, client) { client.disconnect() });
|
|
69
|
+
self._server.close();
|
|
70
|
+
Scenario.runNext();
|
|
71
|
+
}, 1000);
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
_checkInbox: function(expectedInbox) {
|
|
75
|
+
sys.puts(JSON.stringify(this._inbox));
|
|
76
|
+
assert.deepEqual(this._inbox, expectedInbox);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
Faye.extend(Scenario, {
|
|
81
|
+
_queue: [],
|
|
82
|
+
|
|
83
|
+
enqueue: function(name, block) {
|
|
84
|
+
this._queue.push(new this(name, block));
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
runNext: function() {
|
|
88
|
+
this.running = true;
|
|
89
|
+
var scenario = this._queue.shift();
|
|
90
|
+
if (!scenario) return;
|
|
91
|
+
scenario.run();
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
exports.run = function(name, block) {
|
|
96
|
+
Scenario.enqueue(name, block);
|
|
97
|
+
if (!Scenario.running) Scenario.runNext();
|
|
98
|
+
};
|
|
99
|
+
|
data/test/test_channel.rb
CHANGED
|
@@ -16,19 +16,25 @@ class TestChannel < Test::Unit::TestCase
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def test_globbing
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
tree = Channel::Tree.new
|
|
20
|
+
tree['/foo/bar'] = 1
|
|
21
|
+
tree['/foo/boo'] = 2
|
|
22
|
+
tree['/foo'] = 3
|
|
23
|
+
tree['/foobar'] = 4
|
|
24
|
+
tree['/foo/bar/boo'] = 5
|
|
25
|
+
tree['/foobar/boo'] = 6
|
|
26
|
+
tree['/foo/*'] = 7
|
|
27
|
+
tree['/foo/**'] = 8
|
|
28
|
+
|
|
29
|
+
assert_equal [1,2,7,8], tree.glob('/foo/*').sort
|
|
30
|
+
assert_equal [1,7,8], tree.glob('/foo/bar').sort
|
|
31
|
+
assert_equal [1,2,5,7,8], tree.glob('/foo/**').sort
|
|
32
|
+
assert_equal [5,8], tree.glob('/foo/bar/boo').sort
|
|
33
|
+
|
|
34
|
+
tree['/channels/hello'] = 'A'
|
|
35
|
+
tree['/channels/name'] = 'B'
|
|
36
|
+
tree['/channels/nested/hello'] = 'C'
|
|
28
37
|
|
|
29
|
-
assert_equal
|
|
30
|
-
assert_equal [1,7,8], globber.glob('/foo/bar').sort
|
|
31
|
-
assert_equal [1,2,5,7,8], globber.glob('/foo/**').sort
|
|
32
|
-
assert_equal [5,8], globber.glob('/foo/bar/boo').sort
|
|
38
|
+
assert_equal %w[A B C], tree.glob('/channels/**').sort
|
|
33
39
|
end
|
|
34
40
|
end
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
var Scenario = require('./scenario'),
|
|
2
|
+
faye = require('../build/faye'),
|
|
3
|
+
assert = require('assert');
|
|
4
|
+
|
|
5
|
+
(function() {
|
|
6
|
+
var tree = new Faye.Channel.Tree();
|
|
7
|
+
var list = '/foo/bar /foo/boo /foo /foobar /foo/bar/boo /foobar/boo /foo/* /foo/**'.split(' ');
|
|
8
|
+
|
|
9
|
+
Faye.each(list, function(c, i) { tree.set(c, i + 1) });
|
|
10
|
+
|
|
11
|
+
assert.deepEqual(tree.glob('/foo/*').sort(), [1,2,7,8]);
|
|
12
|
+
assert.deepEqual(tree.glob('/foo/bar').sort(), [1,7,8]);
|
|
13
|
+
assert.deepEqual(tree.glob('/foo/**').sort(), [1,2,5,7,8]);
|
|
14
|
+
assert.deepEqual(tree.glob('/foo/bar/boo').sort(), [5,8]);
|
|
15
|
+
|
|
16
|
+
tree.set('/channels/hello', 'A');
|
|
17
|
+
tree.set('/channels/name', 'B');
|
|
18
|
+
tree.set('/channels/nested/hello', 'C');
|
|
19
|
+
|
|
20
|
+
assert.deepEqual(tree.glob('/channels/**').sort(), ['A','B','C']);
|
|
21
|
+
})();
|
|
22
|
+
|
|
23
|
+
Scenario.run("Two HTTP clients, no messages delivered",
|
|
24
|
+
function() { with(this) {
|
|
25
|
+
server(8000);
|
|
26
|
+
httpClient('A', ['/channels/a']);
|
|
27
|
+
httpClient('B', []);
|
|
28
|
+
send('B', '/channels/b', {hello: 'world'});
|
|
29
|
+
checkInbox({
|
|
30
|
+
A: {},
|
|
31
|
+
B: {}
|
|
32
|
+
});
|
|
33
|
+
}});
|
|
34
|
+
|
|
35
|
+
Scenario.run("Two HTTP clients, single subscription",
|
|
36
|
+
function() { with(this) {
|
|
37
|
+
server(8000);
|
|
38
|
+
httpClient('A', ['/channels/a']);
|
|
39
|
+
httpClient('B', []);
|
|
40
|
+
send('B', '/channels/a', {hello: 'world'});
|
|
41
|
+
checkInbox({
|
|
42
|
+
A: {
|
|
43
|
+
'/channels/a': [{hello: 'world'}]
|
|
44
|
+
},
|
|
45
|
+
B: {}
|
|
46
|
+
});
|
|
47
|
+
}});
|
|
48
|
+
|
|
49
|
+
Scenario.run("Two HTTP clients, multiple subscriptions",
|
|
50
|
+
function() { with(this) {
|
|
51
|
+
server(8000);
|
|
52
|
+
httpClient('A', ['/channels/a', '/channels/*']);
|
|
53
|
+
httpClient('B', []);
|
|
54
|
+
send('B', '/channels/a', {hello: 'world'});
|
|
55
|
+
checkInbox({
|
|
56
|
+
A: {
|
|
57
|
+
'/channels/a': [{hello: 'world'}],
|
|
58
|
+
'/channels/*': [{hello: 'world'}]
|
|
59
|
+
},
|
|
60
|
+
B: {}
|
|
61
|
+
});
|
|
62
|
+
}});
|
|
63
|
+
|
|
64
|
+
Scenario.run("Three HTTP clients, single receiver",
|
|
65
|
+
function() { with(this) {
|
|
66
|
+
server(8000);
|
|
67
|
+
httpClient('A', ['/channels/a']);
|
|
68
|
+
httpClient('B', []);
|
|
69
|
+
httpClient('C', ['/channels/c']);
|
|
70
|
+
send('B', '/channels/a', {chunky: 'bacon'});
|
|
71
|
+
checkInbox({
|
|
72
|
+
A: {
|
|
73
|
+
'/channels/a': [{chunky: 'bacon'}]
|
|
74
|
+
},
|
|
75
|
+
B: {},
|
|
76
|
+
C: {}
|
|
77
|
+
});
|
|
78
|
+
}});
|
|
79
|
+
|
|
80
|
+
Scenario.run("Three HTTP clients, multiple receivers",
|
|
81
|
+
function() { with(this) {
|
|
82
|
+
server(8000);
|
|
83
|
+
httpClient('A', ['/channels/shared']);
|
|
84
|
+
httpClient('B', []);
|
|
85
|
+
httpClient('C', ['/channels/shared']);
|
|
86
|
+
send('B', '/channels/shared', {chunky: 'bacon'});
|
|
87
|
+
checkInbox({
|
|
88
|
+
A: {
|
|
89
|
+
'/channels/shared': [{chunky: 'bacon'}]
|
|
90
|
+
},
|
|
91
|
+
B: {},
|
|
92
|
+
C: {
|
|
93
|
+
'/channels/shared': [{chunky: 'bacon'}]
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}});
|
|
97
|
+
|
|
98
|
+
Scenario.run("Two HTTP clients, single wildcard on receiver",
|
|
99
|
+
function() { with(this) {
|
|
100
|
+
server(8000);
|
|
101
|
+
httpClient('A', ['/channels/*']);
|
|
102
|
+
httpClient('B', []);
|
|
103
|
+
send('B', '/channels/anything', {msg: 'hey'});
|
|
104
|
+
checkInbox({
|
|
105
|
+
A: {
|
|
106
|
+
'/channels/*': [{msg: 'hey'}]
|
|
107
|
+
},
|
|
108
|
+
B: {}
|
|
109
|
+
});
|
|
110
|
+
}});
|
|
111
|
+
|
|
112
|
+
Scenario.run("Two HTTP clients, single wildcard on sender",
|
|
113
|
+
function() { with(this) {
|
|
114
|
+
server(8000);
|
|
115
|
+
httpClient('A', ['/channels/name', '/channels/hello', '/channels/nested/hello']);
|
|
116
|
+
httpClient('B', []);
|
|
117
|
+
send('B', '/channels/*', {msg: 'hey'});
|
|
118
|
+
checkInbox({
|
|
119
|
+
A: {
|
|
120
|
+
'/channels/name': [{msg: 'hey'}],
|
|
121
|
+
'/channels/hello': [{msg: 'hey'}]
|
|
122
|
+
},
|
|
123
|
+
B: {}
|
|
124
|
+
});
|
|
125
|
+
}});
|
|
126
|
+
|
|
127
|
+
Scenario.run("Two HTTP clients, single wildcard on both",
|
|
128
|
+
function() { with(this) {
|
|
129
|
+
server(8000);
|
|
130
|
+
httpClient('A', ['/channels/*']);
|
|
131
|
+
httpClient('B', []);
|
|
132
|
+
send('B', '/channels/*', {msg: 'hey'});
|
|
133
|
+
checkInbox({
|
|
134
|
+
A: {
|
|
135
|
+
'/channels/*': [{msg: 'hey'}]
|
|
136
|
+
},
|
|
137
|
+
B: {}
|
|
138
|
+
});
|
|
139
|
+
}});
|
|
140
|
+
|
|
141
|
+
Scenario.run("Two local clients, double wildcard on sender",
|
|
142
|
+
function() { with(this) {
|
|
143
|
+
server(8000);
|
|
144
|
+
localClient('A', ['/channels/name', '/channels/hello', '/channels/nested/hello']);
|
|
145
|
+
localClient('B', []);
|
|
146
|
+
send('B', '/channels/**', {msg: 'hey'});
|
|
147
|
+
checkInbox({
|
|
148
|
+
A: {
|
|
149
|
+
'/channels/name': [{msg: 'hey'}],
|
|
150
|
+
'/channels/hello': [{msg: 'hey'}],
|
|
151
|
+
'/channels/nested/hello': [{msg: 'hey'}]
|
|
152
|
+
},
|
|
153
|
+
B: {}
|
|
154
|
+
});
|
|
155
|
+
}});
|
|
156
|
+
|
|
157
|
+
Scenario.run("Two local clients, one HTTP, double wildcard on sender and one subscription",
|
|
158
|
+
function() { with(this) {
|
|
159
|
+
server(8000);
|
|
160
|
+
localClient('A', ['/channels/hello', '/channels/nested/hello']);
|
|
161
|
+
localClient('B', []);
|
|
162
|
+
httpClient('C', ['/channels/name', '/channels/foo/**']);
|
|
163
|
+
send('B', '/channels/**', {msg: 'hey'});
|
|
164
|
+
checkInbox({
|
|
165
|
+
A: {
|
|
166
|
+
'/channels/hello': [{msg: 'hey'}],
|
|
167
|
+
'/channels/nested/hello': [{msg: 'hey'}]
|
|
168
|
+
},
|
|
169
|
+
B: {},
|
|
170
|
+
C: {
|
|
171
|
+
'/channels/name': [{msg: 'hey'}],
|
|
172
|
+
'/channels/foo/**': [{msg: 'hey'}],
|
|
173
|
+
'/channels/name': [{msg: 'hey'}],
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}});
|
|
177
|
+
|