face-faye 0.8.9

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.
Files changed (73) hide show
  1. data/History.txt +304 -0
  2. data/README.rdoc +83 -0
  3. data/lib/faye-browser-min.js +2 -0
  4. data/lib/faye-browser-min.js.map +8 -0
  5. data/lib/faye-browser.js +2194 -0
  6. data/lib/faye.rb +122 -0
  7. data/lib/faye/adapters/rack_adapter.rb +216 -0
  8. data/lib/faye/adapters/static_server.rb +56 -0
  9. data/lib/faye/engines/connection.rb +60 -0
  10. data/lib/faye/engines/memory.rb +112 -0
  11. data/lib/faye/engines/proxy.rb +121 -0
  12. data/lib/faye/error.rb +49 -0
  13. data/lib/faye/mixins/logging.rb +47 -0
  14. data/lib/faye/mixins/publisher.rb +30 -0
  15. data/lib/faye/mixins/timeouts.rb +22 -0
  16. data/lib/faye/protocol/channel.rb +124 -0
  17. data/lib/faye/protocol/client.rb +376 -0
  18. data/lib/faye/protocol/extensible.rb +43 -0
  19. data/lib/faye/protocol/grammar.rb +58 -0
  20. data/lib/faye/protocol/publication.rb +5 -0
  21. data/lib/faye/protocol/server.rb +293 -0
  22. data/lib/faye/protocol/socket.rb +23 -0
  23. data/lib/faye/protocol/subscription.rb +24 -0
  24. data/lib/faye/transport/http.rb +76 -0
  25. data/lib/faye/transport/local.rb +22 -0
  26. data/lib/faye/transport/transport.rb +116 -0
  27. data/lib/faye/transport/web_socket.rb +92 -0
  28. data/lib/faye/util/namespace.rb +20 -0
  29. data/spec/browser.html +45 -0
  30. data/spec/encoding_helper.rb +7 -0
  31. data/spec/install.sh +78 -0
  32. data/spec/javascript/channel_spec.js +15 -0
  33. data/spec/javascript/client_spec.js +729 -0
  34. data/spec/javascript/engine/memory_spec.js +7 -0
  35. data/spec/javascript/engine_spec.js +417 -0
  36. data/spec/javascript/faye_spec.js +34 -0
  37. data/spec/javascript/grammar_spec.js +66 -0
  38. data/spec/javascript/node_adapter_spec.js +307 -0
  39. data/spec/javascript/publisher_spec.js +27 -0
  40. data/spec/javascript/server/connect_spec.js +168 -0
  41. data/spec/javascript/server/disconnect_spec.js +121 -0
  42. data/spec/javascript/server/extensions_spec.js +60 -0
  43. data/spec/javascript/server/handshake_spec.js +145 -0
  44. data/spec/javascript/server/integration_spec.js +131 -0
  45. data/spec/javascript/server/publish_spec.js +85 -0
  46. data/spec/javascript/server/subscribe_spec.js +247 -0
  47. data/spec/javascript/server/unsubscribe_spec.js +245 -0
  48. data/spec/javascript/server_spec.js +121 -0
  49. data/spec/javascript/transport_spec.js +135 -0
  50. data/spec/node.js +55 -0
  51. data/spec/phantom.js +17 -0
  52. data/spec/ruby/channel_spec.rb +17 -0
  53. data/spec/ruby/client_spec.rb +741 -0
  54. data/spec/ruby/engine/memory_spec.rb +7 -0
  55. data/spec/ruby/engine_examples.rb +427 -0
  56. data/spec/ruby/faye_spec.rb +30 -0
  57. data/spec/ruby/grammar_spec.rb +68 -0
  58. data/spec/ruby/publisher_spec.rb +27 -0
  59. data/spec/ruby/rack_adapter_spec.rb +236 -0
  60. data/spec/ruby/server/connect_spec.rb +170 -0
  61. data/spec/ruby/server/disconnect_spec.rb +120 -0
  62. data/spec/ruby/server/extensions_spec.rb +68 -0
  63. data/spec/ruby/server/handshake_spec.rb +143 -0
  64. data/spec/ruby/server/integration_spec.rb +133 -0
  65. data/spec/ruby/server/publish_spec.rb +81 -0
  66. data/spec/ruby/server/subscribe_spec.rb +247 -0
  67. data/spec/ruby/server/unsubscribe_spec.rb +247 -0
  68. data/spec/ruby/server_spec.rb +121 -0
  69. data/spec/ruby/transport_spec.rb +136 -0
  70. data/spec/spec_helper.rb +11 -0
  71. data/spec/testswarm +42 -0
  72. data/spec/thin_proxy.rb +37 -0
  73. metadata +441 -0
@@ -0,0 +1,121 @@
1
+ JS.ENV.Server.DisconnectSpec = JS.Test.describe("Server disconnect", function() { with(this) {
2
+ before(function() { with(this) {
3
+ this.engine = {}
4
+ stub(Faye.Engine, "get").returns(engine)
5
+ this.server = new Faye.Server()
6
+ }})
7
+
8
+ describe("#disconnect", function() { with(this) {
9
+ before(function() { with(this) {
10
+ this.clientId = "fakeclientid"
11
+ this.message = {channel: "/meta/disconnect",
12
+ clientId: "fakeclientid"}
13
+ }})
14
+
15
+ describe("with valid parameters", function() { with(this) {
16
+ before(function() { with(this) {
17
+ expect(engine, "clientExists").given(clientId).yielding([true])
18
+ }})
19
+
20
+ it("destroys the client", function() { with(this) {
21
+ expect(engine, "destroyClient").given(clientId)
22
+ server.disconnect(message, false, function() {})
23
+ }})
24
+
25
+ it("returns a successful response", function() { with(this) {
26
+ stub(engine, "destroyClient")
27
+ server.disconnect(message, false, function(response) {
28
+ assertEqual({
29
+ channel: "/meta/disconnect",
30
+ successful: true,
31
+ clientId: clientId
32
+ }, response)
33
+ })
34
+ }})
35
+
36
+ describe("with a message id", function() { with(this) {
37
+ before(function() { this.message.id = "foo" })
38
+
39
+ it("returns the same id", function() { with(this) {
40
+ stub(engine, "destroyClient")
41
+ server.disconnect(message, false, function(response) {
42
+ assertEqual({
43
+ channel: "/meta/disconnect",
44
+ successful: true,
45
+ clientId: clientId,
46
+ id: "foo"
47
+ }, response)
48
+ })
49
+ }})
50
+ }})
51
+ }})
52
+
53
+ describe("with an unknown client", function() { with(this) {
54
+ before(function() { with(this) {
55
+ expect(engine, "clientExists").given(clientId).yielding([false])
56
+ }})
57
+
58
+ it("does not destroy the client", function() { with(this) {
59
+ expect(engine, "destroyClient").exactly(0)
60
+ server.disconnect(message, false, function() {})
61
+ }})
62
+
63
+ it("returns an unsuccessful response", function() { with(this) {
64
+ stub(engine, "destroyClient")
65
+ server.disconnect(message, false, function(response) {
66
+ assertEqual({
67
+ channel: "/meta/disconnect",
68
+ successful: false,
69
+ error: "401:fakeclientid:Unknown client"
70
+ }, response)
71
+ })
72
+ }})
73
+ }})
74
+
75
+ describe("missing clientId", function() { with(this) {
76
+ before(function() { with(this) {
77
+ delete message.clientId
78
+ expect(engine, "clientExists").given(undefined).yielding([false])
79
+ }})
80
+
81
+ it("does not destroy the client", function() { with(this) {
82
+ expect(engine, "destroyClient").exactly(0)
83
+ server.disconnect(message, false, function() {})
84
+ }})
85
+
86
+ it("returns an unsuccessful response", function() { with(this) {
87
+ stub(engine, "destroyClient")
88
+ server.disconnect(message, false, function(response) {
89
+ assertEqual({
90
+ channel: "/meta/disconnect",
91
+ successful: false,
92
+ error: "402:clientId:Missing required parameter"
93
+ }, response)
94
+ })
95
+ }})
96
+ }})
97
+
98
+ describe("with an error", function() { with(this) {
99
+ before(function() { with(this) {
100
+ message.error = "invalid"
101
+ expect(engine, "clientExists").given(clientId).yielding([true])
102
+ }})
103
+
104
+ it("does not destroy the client", function() { with(this) {
105
+ expect(engine, "destroyClient").exactly(0)
106
+ server.disconnect(message, false, function() {})
107
+ }})
108
+
109
+ it("returns an unsuccessful response", function() { with(this) {
110
+ stub(engine, "destroyClient")
111
+ server.disconnect(message, false, function(response) {
112
+ assertEqual({
113
+ channel: "/meta/disconnect",
114
+ successful: false,
115
+ error: "invalid"
116
+ }, response)
117
+ })
118
+ }})
119
+ }})
120
+ }})
121
+ }})
@@ -0,0 +1,60 @@
1
+ JS.ENV.Server.ExtensionsSpec = JS.Test.describe("Server extensions", function() { with(this) {
2
+ before(function() { with(this) {
3
+ this.engine = {}
4
+ stub(Faye.Engine, "get").returns(engine)
5
+ this.server = new Faye.Server()
6
+ }})
7
+
8
+ describe("with an incoming extension installed", function() { with(this) {
9
+ before(function() { with(this) {
10
+ var extension = {
11
+ incoming: function(message, callback) {
12
+ message.ext = {auth: "password"}
13
+ callback(message)
14
+ }
15
+ }
16
+ server.addExtension(extension)
17
+ this.message = {channel: "/foo", data: "hello"}
18
+ }})
19
+
20
+ it("passes incoming messages through the extension", function() { with(this) {
21
+ expect(engine, "publish").given({channel: "/foo", data: "hello", ext: {auth: "password"}})
22
+ server.process(message, false, function() {})
23
+ }})
24
+
25
+ it("does not pass outgoing messages through the extension", function() { with(this) {
26
+ stub(server, "handshake").yields([message])
27
+ stub(engine, "publish")
28
+ var response = null
29
+ server.process({channel: "/meta/handshake"}, false, function(r) { response = r })
30
+ assertEqual( [{channel: "/foo", data: "hello"}], response )
31
+ }})
32
+ }})
33
+
34
+ describe("with an outgoing extension installed", function() { with(this) {
35
+ before(function() { with(this) {
36
+ var extension = {
37
+ outgoing: function(message, callback) {
38
+ message.ext = {auth: "password"}
39
+ callback(message)
40
+ }
41
+ }
42
+ server.addExtension(extension)
43
+ this.message = {channel: "/foo", data: "hello"}
44
+ }})
45
+
46
+ it("does not pass incoming messages through the extension", function() { with(this) {
47
+ expect(engine, "publish").given({channel: "/foo", data: "hello"})
48
+ server.process(message, false, function() {})
49
+ }})
50
+
51
+ it("passes outgoing messages through the extension", function() { with(this) {
52
+ stub(server, "handshake").yields([message])
53
+ stub(engine, "publish")
54
+ var response = null
55
+ server.process({channel: "/meta/handshake"}, false, function(r) { response = r })
56
+ assertEqual( [{channel: "/foo", data: "hello", ext: {auth: "password"}}], response )
57
+ }})
58
+ }})
59
+ }})
60
+
@@ -0,0 +1,145 @@
1
+ JS.ENV.Server.HandshakeSpec = JS.Test.describe("Server handshake", function() { with(this) {
2
+ before(function() { with(this) {
3
+ this.engine = {}
4
+ stub(Faye.Engine, "get").returns(engine)
5
+ this.server = new Faye.Server()
6
+
7
+ this.connectionTypes = ["long-polling", "cross-origin-long-polling",
8
+ "callback-polling","websocket",
9
+ "eventsource","in-process"]
10
+ }})
11
+
12
+ describe("#handshake", function() { with(this) {
13
+ before(function() { with(this) {
14
+ this.message = {channel: "/meta/handshake",
15
+ version: "1.0",
16
+ supportedConnectionTypes: ["long-polling"]}
17
+ }})
18
+
19
+ describe("with valid parameters", function() { with(this) {
20
+ it("creates a client", function() { with(this) {
21
+ expect(engine, "createClient")
22
+ server.handshake(message, false, function() {})
23
+ }})
24
+
25
+ it("returns a successful response", function() { with(this) {
26
+ stub(engine, "createClient").yields(["clientid"])
27
+ server.handshake(message, false, function(response) {
28
+ assertEqual({
29
+ channel: "/meta/handshake",
30
+ successful: true,
31
+ version: "1.0",
32
+ supportedConnectionTypes: connectionTypes,
33
+ clientId: "clientid"
34
+ }, response)
35
+ })
36
+ }})
37
+
38
+ describe("with a message id", function() { with(this) {
39
+ before(function() { this.message.id = "foo" })
40
+
41
+ it("returns the same id", function() { with(this) {
42
+ stub(engine, "createClient").yields(["clientid"])
43
+ server.handshake(message, false, function(response) {
44
+ assertEqual({
45
+ channel: "/meta/handshake",
46
+ successful: true,
47
+ version: "1.0",
48
+ supportedConnectionTypes: connectionTypes,
49
+ clientId: "clientid",
50
+ id: "foo"
51
+ }, response)
52
+ })
53
+ }})
54
+ }})
55
+ }})
56
+
57
+ describe("missing version", function() { with(this) {
58
+ before(function() { delete this.message.version })
59
+
60
+ it("does not create a client", function() { with(this) {
61
+ expect(engine, "createClient").exactly(0)
62
+ server.handshake(message, false, function() {})
63
+ }})
64
+
65
+ it("returns an unsuccessful response", function() { with(this) {
66
+ server.handshake(message, false, function(response) {
67
+ assertEqual({
68
+ channel: "/meta/handshake",
69
+ successful: false,
70
+ error: "402:version:Missing required parameter",
71
+ version: "1.0",
72
+ supportedConnectionTypes: connectionTypes
73
+ }, response)
74
+ })
75
+ }})
76
+ }})
77
+
78
+ describe("missing supportedConnectionTypes", function() { with(this) {
79
+ before(function() { delete this.message.supportedConnectionTypes })
80
+
81
+ it("does not create a client", function() { with(this) {
82
+ expect(engine, "createClient").exactly(0)
83
+ server.handshake(message, false, function() {})
84
+ }})
85
+
86
+ it("returns an unsuccessful response", function() { with(this) {
87
+ server.handshake(message, false, function(response) {
88
+ assertEqual({
89
+ channel: "/meta/handshake",
90
+ successful: false,
91
+ error: "402:supportedConnectionTypes:Missing required parameter",
92
+ version: "1.0",
93
+ supportedConnectionTypes: connectionTypes
94
+ }, response)
95
+ })
96
+ }})
97
+ }})
98
+
99
+ describe("with no matching supportedConnectionTypes", function() { with(this) {
100
+ before(function() { with(this) {
101
+ message.supportedConnectionTypes = ["iframe", "flash"]
102
+ }})
103
+
104
+ it("does not create a client", function() { with(this) {
105
+ expect(engine, "createClient").exactly(0)
106
+ server.handshake(message, false, function() {})
107
+ }})
108
+
109
+ it("returns an unsuccessful response", function() { with(this) {
110
+ server.handshake(message, false, function(response) {
111
+ assertEqual({
112
+ channel: "/meta/handshake",
113
+ successful: false,
114
+ error: "301:iframe,flash:Connection types not supported",
115
+ version: "1.0",
116
+ supportedConnectionTypes: connectionTypes
117
+ }, response)
118
+ })
119
+ }})
120
+ }})
121
+
122
+ describe("with an error", function() { with(this) {
123
+ before(function() { with(this) {
124
+ message.error = "invalid"
125
+ }})
126
+
127
+ it("does not create a client", function() { with(this) {
128
+ expect(engine, "createClient").exactly(0)
129
+ server.handshake(message, false, function() {})
130
+ }})
131
+
132
+ it("returns an unsuccessful response", function() { with(this) {
133
+ server.handshake(message, false, function(response) {
134
+ assertEqual({
135
+ channel: "/meta/handshake",
136
+ successful: false,
137
+ error: "invalid",
138
+ version: "1.0",
139
+ supportedConnectionTypes: connectionTypes
140
+ }, response)
141
+ })
142
+ }})
143
+ }})
144
+ }})
145
+ }})
@@ -0,0 +1,131 @@
1
+ JS.ENV.IntegrationSteps = JS.Test.asyncSteps({
2
+ server: function(port, ssl, callback) {
3
+ var shared = __dirname + '/../../../examples/shared',
4
+
5
+ options = ssl
6
+ ? { key: shared + '/server.key', cert: shared + '/server.crt' }
7
+ : null
8
+
9
+ this._adapter = new Faye.NodeAdapter({mount: "/bayeux", timeout: 2})
10
+ this._adapter.addExtension({
11
+ outgoing: function(message, callback) {
12
+ if (message.data) message.data.tagged = true
13
+ callback(message)
14
+ }
15
+ })
16
+
17
+ this._port = port
18
+ this._secure = ssl
19
+ this._adapter.listen(port, options, callback)
20
+ },
21
+
22
+ stop: function(callback) {
23
+ for (var id in this._clients) this._clients[id].disconnect()
24
+ var self = this
25
+ setTimeout(function() { self._adapter.stop(callback) }, 100)
26
+ },
27
+
28
+ client: function(name, channels, callback) {
29
+ var scheme = this._secure ? "https" : "http"
30
+ this._clients = this._clients || {}
31
+ this._inboxes = this._inboxes || {}
32
+ this._clients[name] = new Faye.Client(scheme + "://0.0.0.0:" + this._port + "/bayeux")
33
+ this._inboxes[name] = {}
34
+
35
+ var n = channels.length
36
+ if (n === 0) return this._clients[name].connect(callback)
37
+
38
+ for (var i = 0; i < n; i++)
39
+ (function(channel) {
40
+ var subscription = this._clients[name].subscribe(channel, function(message) {
41
+ this._inboxes[name][channel] = this._inboxes[name][channel] || []
42
+ this._inboxes[name][channel].push(message)
43
+ }, this)
44
+ subscription.callback(function() {
45
+ n -= 1
46
+ if (n === 0) callback()
47
+ })
48
+ }).call(this, channels[i]);
49
+ },
50
+
51
+ publish: function(name, channel, message, callback) {
52
+ this._clients[name].publish(channel, message)
53
+ setTimeout(callback, 100)
54
+ },
55
+
56
+ check_inbox: function(name, channel, messages, callback) {
57
+ var inbox = this._inboxes[name][channel] || []
58
+ this.assertEqual(messages, inbox)
59
+ callback()
60
+ }
61
+ })
62
+
63
+ JS.ENV.Server.IntegrationSpec = JS.Test.describe("Server integration", function() { with(this) {
64
+ include(IntegrationSteps)
65
+
66
+ sharedExamplesFor("message bus", function() { with(this) {
67
+ before(function() { with(this) {
68
+ server(8000, serverOptions.ssl)
69
+ client("alice", [])
70
+ client("bob", ["/foo"])
71
+ }})
72
+
73
+ after(function() { this.stop() })
74
+
75
+ it("delivers a message between clients", function() { with(this) {
76
+ publish("alice", "/foo", {hello: "world", extra: null})
77
+ check_inbox("bob", "/foo", [{hello: "world", extra: null, tagged: true}])
78
+ }})
79
+
80
+ it("does not deliver messages for unsubscribed channels", function() { with(this) {
81
+ publish("alice", "/bar", {hello: "world"})
82
+ check_inbox("bob", "/foo", [])
83
+ }})
84
+
85
+ it("delivers multiple messages", function() { with(this) {
86
+ publish("alice", "/foo", {hello: "world"})
87
+ publish("alice", "/foo", {hello: "world"})
88
+ check_inbox("bob", "/foo", [{hello: "world", tagged: true}, {hello: "world", tagged: true}])
89
+ }})
90
+
91
+ it("delivers multibyte strings", function() { with(this) {
92
+ publish("alice", "/foo", {hello: "Apple = "})
93
+ check_inbox("bob", "/foo", [{hello: "Apple = ", tagged: true}])
94
+ }})
95
+ }})
96
+
97
+ sharedExamplesFor("network transports", function() { with(this) {
98
+ describe("with HTTP transport", function() { with(this) {
99
+ before(function() { with(this) {
100
+ stub(Faye.Transport.WebSocket, "isUsable").yields([false])
101
+ }})
102
+
103
+ itShouldBehaveLike("message bus")
104
+ }})
105
+
106
+ describe("with WebSocket transport", function() { with(this) {
107
+ before(function() { with(this) {
108
+ stub(Faye.Transport.WebSocket, "isUsable").yields([true])
109
+ }})
110
+
111
+ itShouldBehaveLike("message bus")
112
+ }})
113
+ }})
114
+
115
+ describe("with HTTP server", function() { with(this) {
116
+ before(function() { with(this) {
117
+ this.serverOptions = {ssl: false}
118
+ }})
119
+
120
+ itShouldBehaveLike("network transports")
121
+ }})
122
+
123
+ describe("with HTTPS server", function() { with(this) {
124
+ before(function() { with(this) {
125
+ this.serverOptions = {ssl: true}
126
+ }})
127
+
128
+ itShouldBehaveLike("network transports")
129
+ }})
130
+ }})
131
+