plezi 0.14.4 → 0.14.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,55 +1,54 @@
1
- require 'securerandom'
2
1
  module Plezi
3
- module Base
4
- module MessageDispatch
5
- module RedisDriver
6
- @redis_locker ||= Mutex.new
7
- @redis = @redis_sub_thread = nil
2
+ module Base
3
+ module MessageDispatch
4
+ module RedisDriver
5
+ @redis_locker ||= Mutex.new
6
+ @redis = @redis_sub_thread = nil
8
7
 
9
- module_function
8
+ module_function
10
9
 
11
- def connect
12
- return false unless ENV['PL_REDIS_URL'] && defined?(::Redis)
13
- return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis
14
- @redis_locker.synchronize do
15
- return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis # repeat the test inside syncing, things change.
16
- @redis.quit if @redis
17
- @redis = ::Redis.new(url: ENV['PL_REDIS_URL'])
18
- raise "Redis connction failed for: #{ENV['PL_REDIS_URL']}" unless @redis
19
- @redis_sub_thread = Thread.new do
20
- begin
21
- ::Redis.new(url: ENV['PL_REDIS_URL']).subscribe(::Plezi.app_name, ::Plezi::Base::MessageDispatch.pid) do |on|
22
- on.message do |_channel, msg|
23
- ::Plezi::Base::MessageDispatch << msg
10
+ def connect
11
+ return false unless ENV['PL_REDIS_URL'] && defined?(::Redis)
12
+ return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis
13
+ @redis_locker.synchronize do
14
+ return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis # repeat the test inside syncing, things change.
15
+ @redis.quit if @redis
16
+ @redis = ::Redis.new(url: ENV['PL_REDIS_URL'])
17
+ raise "Redis connction failed for: #{ENV['PL_REDIS_URL']}" unless @redis
18
+ @redis_sub_thread = Thread.new do
19
+ begin
20
+ ::Redis.new(url: ENV['PL_REDIS_URL']).subscribe(::Plezi.app_name, ::Plezi::Base::MessageDispatch.pid) do |on|
21
+ on.message do |_channel, msg|
22
+ ::Plezi::Base::MessageDispatch << msg
23
+ end
24
+ end
25
+ rescue => e
26
+ puts e.message, e.backtrace
27
+ retry
28
+ end
24
29
  end
25
- end
26
- rescue => e
27
- puts e.message, e.backtrace
28
- retry
29
- end
30
+ @redis
31
+ end
30
32
  end
31
- @redis
32
- end
33
- end
34
33
 
35
- # Get the current redis connection.
36
- def redis
37
- @redis || connect
38
- end
34
+ # Get the current redis connection.
35
+ def redis
36
+ @redis || connect
37
+ end
39
38
 
40
- def push(channel, message)
41
- return unless connect
42
- return if away?(channel)
43
- redis.publish(channel, message)
44
- end
39
+ def push(channel, message)
40
+ return unless connect
41
+ return if away?(channel)
42
+ redis.publish(channel, message)
43
+ end
45
44
 
46
- def away?(server)
47
- return true unless connect
48
- @redis.pubsub('CHANNELS', server).empty?
49
- end
45
+ def away?(server)
46
+ return true unless connect
47
+ @redis.pubsub('CHANNELS', server).empty?
48
+ end
49
+ end
50
50
  end
51
- end
52
- end
51
+ end
53
52
  end
54
53
 
55
54
  ::Plezi::Base::MessageDispatch.drivers << ::Plezi::Base::MessageDispatch::RedisDriver
@@ -27,12 +27,12 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
 
30
- spec.add_dependency 'iodine', '~> 0.2', '>= 0.2.7'
30
+ spec.add_dependency 'iodine', '~> 0.2', '>= 0.2.14'
31
31
  spec.add_dependency 'rack', '>= 2.0.0'
32
- spec.add_dependency 'bundler', '~> 1.13'
32
+ spec.add_dependency 'bundler', '~> 1.14'
33
33
  # spec.add_dependency 'redcarpet', '> 3.3.0'
34
34
  # spec.add_dependency 'slim', '> 3.0.0'
35
35
 
36
- spec.add_development_dependency 'rake', '~> 10.0'
36
+ spec.add_development_dependency 'rake', '~> 11.0'
37
37
  spec.add_development_dependency 'minitest', '~> 5.0'
38
38
  end
@@ -7,16 +7,20 @@
7
7
  //
8
8
  // var client = new PleziClient()
9
9
  //
10
- // To open a connection to a different path for the original server (SSL will be preserved when in use), use:
10
+ // To open a connection to a different path for the original server (SSL will be
11
+ // preserved when in use), use:
11
12
  //
12
13
  // var client = new PleziClient(PleziClient.origin + "/path")
13
14
  //
14
- // To automatically renew the connection when disconnections are reported by the browser, use:
15
+ // To automatically renew the connection when disconnections are reported by the
16
+ // browser, use:
15
17
  //
16
18
  // client.autoreconnect = true
17
- // client.reconnect_interval = 250 // sets how long to wait before reconnection attempts. default is 250 ms.
19
+ // client.reconnect_interval = 250 // sets how long to wait before
20
+ // reconnection attempts. default is 250 ms.
18
21
  //
19
- // To set up event handling, directly set an `<event name>` callback. i.e., for an event called `chat`:
22
+ // To set up event handling, directly set an `<event name>` callback. i.e., for
23
+ // an event called `chat`:
20
24
  //
21
25
  // client.chat = function(event) { "..." }
22
26
  //
@@ -25,229 +29,250 @@
25
29
  // client.emit({event: "chat", data: "the message"})
26
30
  //
27
31
  function PleziClient(url, autoreconnect) {
28
- // Set URL
29
- if (url) {
30
- this.url = url;
31
- } else {
32
- this.url = PleziClient.origin + self.location.pathname;
33
- }
34
- // Connect Websocket
35
- this.reconnect();
36
- // Setup AJAJ
37
- this.ajaj = {};
38
- this.ajaj.client = this;
39
- this.ajaj.url = this.url.replace(/^ws:\/\//i, "http://").replace(/^wss:\/\//i, "https://");
40
- this.ajaj.add = {};
41
- this.ajaj.emit = this.___ajaj__emit;
42
- this.ajaj.auto = false;
43
- // auto-reconnection
44
- this.autoreconnect = false;
45
- this.reconnect_interval = 200;
46
- // dump data to console?
47
- this.log_events = false;
48
- // the timeout for a message ack receipt
49
- this.emit_timeout = false;
50
- // Set the autoreconnect property
51
- if (autoreconnect) {
52
- this.autoreconnect = true;
53
- }
32
+ // Set URL
33
+ if (url) {
34
+ this.url = url;
35
+ } else {
36
+ this.url = PleziClient.origin + self.location.pathname;
37
+ }
38
+ // Connect Websocket
39
+ this.reconnect();
40
+ // Setup AJAJ
41
+ this.ajaj = {};
42
+ this.ajaj.client = this;
43
+ this.ajaj.url = this.url.replace(/^ws:\/\//i, "http://")
44
+ .replace(/^wss:\/\//i, "https://");
45
+ this.ajaj.add = {};
46
+ this.ajaj.emit = this.___ajaj__emit;
47
+ this.ajaj.auto = false;
48
+ // auto-reconnection
49
+ this.autoreconnect = false;
50
+ this.reconnect_interval = 200;
51
+ // dump data to console?
52
+ this.log_events = false;
53
+ // the timeout for a message ack receipt
54
+ this.emit_timeout = false;
55
+ // Set the autoreconnect property
56
+ if (autoreconnect) {
57
+ this.autoreconnect = true;
58
+ }
54
59
  }
55
60
  // The Websocket onopen callback
56
- PleziClient.prototype.___on_open = function(e) {
57
- this.owner.connected = true;
58
- if (this.owner.onopen) {
59
- this.owner.onopen(e);
60
- }
61
- }
61
+ PleziClient.prototype.___on_open =
62
+ function(e) {
63
+ this.owner.connected = true;
64
+ if (this.owner.onopen) {
65
+ this.owner.onopen(e);
66
+ }
67
+ }
62
68
  // The Websocket onclose callback
63
- PleziClient.prototype.___on_close = function(e) {
64
- this.owner.connected = false;
65
- if (this.owner.onclose) {
66
- this.owner.onclose(e);
67
- }
68
- if (this.owner.autoreconnect) {
69
- setTimeout(function(obj) {
70
- obj.reconnect();
71
- }, this.owner.reconnect_interval, this.owner);
72
- }
73
- }
74
- // The Websocket onerror callback
75
- PleziClient.prototype.___on_error = function(e) {
76
- if (this.owner.onerror) {
77
- this.owner.onerror(e);
78
- }
69
+ PleziClient.prototype.___on_close =
70
+ function(e) {
71
+ this.owner.connected = false;
72
+ if (this.owner.onclose) {
73
+ this.owner.onclose(e);
74
+ }
75
+ if (this.owner.autoreconnect) {
76
+ setTimeout(function(obj) { obj.reconnect(); },
77
+ this.owner.reconnect_interval, this.owner);
78
+ }
79
+ }
80
+ // The Websocket onerror callback
81
+ PleziClient.prototype.___on_error =
82
+ function(e) {
83
+ if (this.owner.onerror) {
84
+ this.owner.onerror(e);
85
+ }
86
+ }
87
+ // The Websocket onmessage callback
88
+ PleziClient.prototype.___on_message = function(e) {
89
+ try {
90
+ var msg = JSON.parse(e.data);
91
+ this.owner.___dispatch(msg);
92
+ } catch (err) {
93
+ console.error(
94
+ "PleziClient experienced an error parsing the following data (not JSON):",
95
+ err, e);
96
+ }
97
+ };
98
+
99
+ PleziClient.prototype.___dispatch =
100
+ function(msg) {
101
+ try {
102
+ if (this.log_events) {
103
+ console.log(msg);
79
104
  }
80
- // The Websocket onmessage callback
81
- PleziClient.prototype.___on_message = function(e) {
82
- try {
83
- var msg = JSON.parse(e.data);
84
- this.owner.___dispatch(msg);
85
- } catch (err) {
86
- console.error("PleziClient experienced an error parsing the following data (not JSON):",
87
- err, e);
105
+ if (msg.event == '_ack_') {
106
+ clearTimeout(msg._EID_);
107
+ if (this[msg._EID_] && this[msg._EID_].callback) {
108
+ this[msg._EID_].callback(this[msg._EID_].event, this);
109
+ }
110
+ delete this[msg._EID_];
88
111
  }
89
- }
90
- PleziClient.prototype.___dispatch = function(msg) {
91
- try {
92
- if (this.log_events) {
93
- console.log(msg);
94
- }
95
- if (msg.event == '_ack_') {
96
- clearTimeout(msg._EID_);
97
- if (this[msg._EID_] && this[msg._EID_].callback) {
98
- this[msg._EID_].callback(this[msg._EID_].event, this);
99
- }
100
- delete this[msg._EID_];
101
- }
102
- if ((msg.event) && (this[msg.event])) {
103
- this[msg.event](msg);
104
- } else if ((msg.event) && (this['on' + msg.event])) {
105
- console.warn('PleziClient: use a callback called "' + msg.event +
106
- '" instead of of "on' + msg.event + '"');
107
- this['on' + msg.event](msg);
108
- } else {
109
- if (this['unknown'] && (msg.event != '_ack_')) {
110
- this['unknown'](msg);
111
- };
112
- }
113
- } catch (err) {
114
- console.error("PleziClient experienced an error while responding to the following onmessage event",
115
- err, msg);
112
+ if ((msg.event) && (this[msg.event])) {
113
+ this[msg.event](msg);
114
+ } else if ((msg.event) && (this['on' + msg.event])) {
115
+ console.warn('PleziClient: use a callback called "' + msg.event +
116
+ '" instead of of "on' + msg.event + '"');
117
+ this['on' + msg.event](msg);
118
+ } else {
119
+ if (this['unknown'] && (msg.event != '_ack_')) {
120
+ this['unknown'](msg);
121
+ };
116
122
  }
123
+ } catch (err) {
124
+ console.error(
125
+ "PleziClient experienced an error while responding to the following onmessage event",
126
+ err, msg);
127
+ }
117
128
  }
118
129
 
119
- // Clears meta timeout data
120
- PleziClient.prototype.___perform_timeout_callback = function(event, pl_client, callback) {
121
- delete pl_client[event._EID_];
122
- callback(event, pl_client);
130
+ // Clears meta timeout data
131
+ PleziClient.prototype.___perform_timeout_callback =
132
+ function(event, pl_client, callback) {
133
+ delete pl_client[event._EID_];
134
+ callback(event, pl_client);
123
135
  }
124
136
 
125
- // Sets a timeout for the websocket message
126
- PleziClient.prototype.___set_failed_timeout = function(event, callback, timeout) {
127
- if (event._EID_) {
128
- return event;
129
- };
130
- if (!timeout) {
131
- timeout = this.emit_timeout;
132
- };
133
- if (!callback) {
134
- callback = this.___on_timeout;
135
- };
136
- if (!timeout) {
137
- return event;
138
- };
139
- event._EID_ = setTimeout(this.___perform_timeout_callback, timeout, event, this, callback);
140
- return event;
141
- }
142
- // Removes the _client_ property from the event and calls
143
- // the ontimeout callback within the correct scope
144
- PleziClient.prototype.___on_timeout = function(event, client) {
145
- if (client.ajaj.auto) {
146
- if (client.log_events) {
147
- console.log("falling back on AJAJ for the event:", event);
148
- }
149
- client.ajaj.emit(event, client.ontimeout);
150
- } else {
151
- client.ontimeout(event);
152
- }
137
+ // Sets a timeout for the websocket message
138
+ PleziClient.prototype.___set_failed_timeout =
139
+ function(event, callback, timeout) {
140
+ if (event._EID_) {
141
+ return event;
142
+ };
143
+ if (!timeout) {
144
+ timeout = this.emit_timeout;
145
+ };
146
+ if (!callback) {
147
+ callback = this.___on_timeout;
148
+ };
149
+ if (!timeout) {
150
+ return event;
151
+ };
152
+ event._EID_ = setTimeout(this.___perform_timeout_callback, timeout, event,
153
+ this, callback);
154
+ return event;
155
+ }
156
+ // Removes the _client_ property from the event and
157
+ // calls
158
+ // the ontimeout callback within the correct scope
159
+ PleziClient.prototype.___on_timeout =
160
+ function(event, client) {
161
+ if (client.ajaj.auto) {
162
+ if (client.log_events) {
163
+ console.log("falling back on AJAJ for the event:", event);
153
164
  }
154
- // The timeout callback
155
- PleziClient.prototype.ontimeout = function(event) {
156
- console.warn("Timeout reached - it's assumed the connection was lost " +
157
- "and the following event was ignored by the server:", event);
158
- console.log(this);
165
+ client.ajaj.emit(event, client.ontimeout);
166
+ } else {
167
+ client.ontimeout(event);
168
+ }
159
169
  }
160
-
161
- PleziClient.prototype.reconnect = function() {
162
- this.connected = NaN;
163
- this.ws = new WebSocket(this.url);
164
- // lets us access the client from the callbacks
165
- this.ws.owner = this;
166
- // The Websocket onopen callback
167
- this.ws.onopen = this.___on_open;
168
- // The Websocket onclose callback
169
- this.ws.onclose = this.___on_close;
170
- // The Websocket onerror callback
171
- this.ws.onerror = this.___on_error;
172
- // The Websocket onmessage callback
173
- this.ws.onmessage = this.___on_message;
170
+ // The timeout callback
171
+ PleziClient.prototype.ontimeout =
172
+ function(event) {
173
+ console.warn("Timeout reached - it's assumed the connection was lost " +
174
+ "and the following event was ignored by the server:",
175
+ event);
176
+ console.log(this);
174
177
  }
175
178
 
176
- PleziClient.prototype.close = function() {
177
- this.autoreconnect = false;
178
- this.ws.close();
179
+ PleziClient.prototype.reconnect =
180
+ function() {
181
+ this.connected = NaN;
182
+ this.ws = new WebSocket(this.url);
183
+ // lets us access the client from the callbacks
184
+ this.ws.owner = this;
185
+ // The Websocket onopen callback
186
+ this.ws.onopen = this.___on_open;
187
+ // The Websocket onclose callback
188
+ this.ws.onclose = this.___on_close;
189
+ // The Websocket onerror callback
190
+ this.ws.onerror = this.___on_error;
191
+ // The Websocket onmessage callback
192
+ this.ws.onmessage = this.___on_message;
179
193
  }
180
194
 
181
- PleziClient.origin = (self.location.protocol.match(/https/) ? 'wws' : 'ws') + '://' + self.location.hostname + (self.location.port == '' ? '' : (':' + self.location.port));
182
-
183
- PleziClient.prototype.sendraw = function(data) {
184
- if (this.ws.readyState != 1) {
185
- return false;
186
- }
187
- this.ws.send(data);
188
- if (this.ws.readyState != 1) {
189
- return false;
190
- }
191
- return true;
195
+ PleziClient.prototype.close =
196
+ function() {
197
+ this.autoreconnect = false;
198
+ this.ws.close();
192
199
  }
193
200
 
194
- PleziClient.prototype.emit = function(event, callback, timeout_callback, timeout) {
195
- if (!timeout && callback && !this.emit_timeout)
196
- timeout = 10;
197
- this.___set_failed_timeout(event, timeout_callback, timeout)
198
- if (callback) {
199
- this[event._EID_] = {
200
- callback: callback,
201
- event: event
202
- };
203
- }
204
- return this.sendraw(JSON.stringify(event));
201
+ PleziClient.origin =
202
+ (self.location.protocol.match(/https/) ? 'wws'
203
+ : 'ws') +
204
+ '://' + self.location.hostname +
205
+ (self.location.port == ''
206
+ ? ''
207
+ : (':' + self.location.port));
208
+
209
+ PleziClient.prototype.sendraw =
210
+ function(data) {
211
+ if (this.ws.readyState != 1) {
212
+ return false;
213
+ }
214
+ this.ws.send(data);
215
+ if (this.ws.readyState != 1) {
216
+ return false;
217
+ }
218
+ return true;
205
219
  }
206
220
 
207
- PleziClient.prototype.readyState = function() {
208
- return this.ws.readyState;
221
+ PleziClient.prototype.emit =
222
+ function(event, callback, timeout_callback, timeout) {
223
+ if (!timeout && callback && !this.emit_timeout)
224
+ timeout = 10;
225
+ this.___set_failed_timeout(event, timeout_callback, timeout);
226
+ if (callback) {
227
+ this[event._EID_] = {callback : callback, event : event};
228
+ }
229
+ return this.sendraw(JSON.stringify(event));
209
230
  }
210
231
 
211
- PleziClient.prototype.___ajaj__emit = function(event, callback) {
212
- var combined = {}
213
- for (var k in this.add) {
214
- combined[k] = this.add[k];
215
- };
216
- for (var k in event) {
217
- combined[k] = event[k];
218
- };
219
- if (!combined.id) {
220
- combined.id = event.event;
221
- };
222
- var req = new XMLHttpRequest();
223
- req.client = this.client;
224
- req.json = combined;
225
- req.callback = callback;
226
- // if(!req.callback) req.callback = this.failed
227
- req.onreadystatechange = function() {
228
- if (this.readyState != 4) {
229
- return;
230
- }
231
- if (this.status == 200) {
232
- try {
233
- var res = JSON.parse(this.responseText);
234
- this.client.___dispatch(res);
235
- } catch (err) {
236
- console.error("PleziClient experienced an error parsing the following data (not JSON):",
237
- err, this.responseText);
238
- }
232
+ PleziClient.prototype.readyState =
233
+ function() { return this.ws.readyState; }
239
234
 
240
- } else {
241
- if (this.callback) {
242
- this.callback(this.json);
243
- }
244
- }
235
+ PleziClient.prototype.___ajaj__emit = function(event, callback) {
236
+ var combined = {};
237
+ for (var k in this.add) {
238
+ combined[k] = this.add[k];
239
+ };
240
+ for (var k in event) {
241
+ combined[k] = event[k];
242
+ };
243
+ if (!combined.id) {
244
+ combined.id = event.event;
245
+ };
246
+ var req = new XMLHttpRequest();
247
+ req.client = this.client;
248
+ req.json = combined;
249
+ req.callback = callback;
250
+ // if(!req.callback) req.callback = this.failed
251
+ req.onreadystatechange = function() {
252
+ if (this.readyState != 4) {
253
+ return;
245
254
  }
246
- req.open("POST", this.url, true);
247
- req.setRequestHeader("Content-type", "application/json");
248
- try {
249
- req.send(JSON.stringify(combined));
250
- } catch (err) {
251
- callback(event);
255
+ if (this.status == 200) {
256
+ try {
257
+ var res = JSON.parse(this.responseText);
258
+ this.client.___dispatch(res);
259
+ } catch (err) {
260
+ console.error(
261
+ "PleziClient experienced an error parsing the following data (not JSON):",
262
+ err, this.responseText);
263
+ }
264
+
265
+ } else {
266
+ if (this.callback) {
267
+ this.callback(this.json);
268
+ }
252
269
  }
270
+ };
271
+ req.open("POST", this.url, true);
272
+ req.setRequestHeader("Content-type", "application/json");
273
+ try {
274
+ req.send(JSON.stringify(combined));
275
+ } catch (err) {
276
+ callback(event);
277
+ }
253
278
  }