pubnub 3.3.0.7 → 3.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of pubnub might be problematic. Click here for more details.

Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.yardoc/checksums +13 -0
  4. data/.yardoc/object_types +0 -0
  5. data/.yardoc/objects/root.dat +0 -0
  6. data/.yardoc/proxy_types +0 -0
  7. data/LICENSE +27 -0
  8. data/README.md +259 -0
  9. data/Rakefile +7 -0
  10. data/VERSION +1 -0
  11. data/examples/demo_console.rb +198 -0
  12. data/examples/error_server.rb +28 -0
  13. data/examples/pubnub_livestream/.gitignore +16 -0
  14. data/examples/pubnub_livestream/Gemfile +51 -0
  15. data/examples/pubnub_livestream/Gemfile.lock +191 -0
  16. data/examples/pubnub_livestream/README.rdoc +28 -0
  17. data/examples/pubnub_livestream/Rakefile +6 -0
  18. data/examples/pubnub_livestream/app/assets/images/.keep +0 -0
  19. data/examples/pubnub_livestream/app/assets/javascripts/application.js +16 -0
  20. data/examples/pubnub_livestream/app/assets/javascripts/streamer.js.coffee +42 -0
  21. data/examples/pubnub_livestream/app/assets/stylesheets/application.css.sass +22 -0
  22. data/examples/pubnub_livestream/app/assets/stylesheets/streamer.css.scss +3 -0
  23. data/examples/pubnub_livestream/app/controllers/application_controller.rb +5 -0
  24. data/examples/pubnub_livestream/app/controllers/concerns/.keep +0 -0
  25. data/examples/pubnub_livestream/app/controllers/streamer_controller.rb +38 -0
  26. data/examples/pubnub_livestream/app/helpers/application_helper.rb +2 -0
  27. data/examples/pubnub_livestream/app/helpers/streamer_helper.rb +2 -0
  28. data/examples/pubnub_livestream/app/mailers/.keep +0 -0
  29. data/examples/pubnub_livestream/app/models/.keep +0 -0
  30. data/examples/pubnub_livestream/app/models/concerns/.keep +0 -0
  31. data/examples/pubnub_livestream/app/models/message.rb +11 -0
  32. data/examples/pubnub_livestream/app/views/layouts/application.html.erb +14 -0
  33. data/examples/pubnub_livestream/app/views/streamer/index.haml +22 -0
  34. data/examples/pubnub_livestream/bin/bundle +3 -0
  35. data/examples/pubnub_livestream/bin/rails +4 -0
  36. data/examples/pubnub_livestream/bin/rake +4 -0
  37. data/examples/pubnub_livestream/config.ru +4 -0
  38. data/examples/pubnub_livestream/config/application.rb +23 -0
  39. data/examples/pubnub_livestream/config/boot.rb +4 -0
  40. data/examples/pubnub_livestream/config/database.yml +25 -0
  41. data/examples/pubnub_livestream/config/environment.rb +5 -0
  42. data/examples/pubnub_livestream/config/environments/development.rb +29 -0
  43. data/examples/pubnub_livestream/config/environments/production.rb +80 -0
  44. data/examples/pubnub_livestream/config/environments/test.rb +36 -0
  45. data/examples/pubnub_livestream/config/initializers/backtrace_silencers.rb +7 -0
  46. data/examples/pubnub_livestream/config/initializers/filter_parameter_logging.rb +4 -0
  47. data/examples/pubnub_livestream/config/initializers/inflections.rb +16 -0
  48. data/examples/pubnub_livestream/config/initializers/mime_types.rb +5 -0
  49. data/examples/pubnub_livestream/config/initializers/pubnub.rb +12 -0
  50. data/examples/pubnub_livestream/config/initializers/secret_token.rb +12 -0
  51. data/examples/pubnub_livestream/config/initializers/session_store.rb +3 -0
  52. data/examples/pubnub_livestream/config/initializers/wrap_parameters.rb +14 -0
  53. data/examples/pubnub_livestream/config/locales/en.yml +23 -0
  54. data/examples/pubnub_livestream/config/routes.rb +62 -0
  55. data/examples/pubnub_livestream/db/migrate/20130826110322_create_messages.rb +11 -0
  56. data/examples/pubnub_livestream/db/schema.rb +24 -0
  57. data/examples/pubnub_livestream/db/seeds.rb +7 -0
  58. data/examples/pubnub_livestream/lib/assets/.keep +0 -0
  59. data/examples/pubnub_livestream/lib/tasks/.keep +0 -0
  60. data/examples/pubnub_livestream/log/.keep +0 -0
  61. data/examples/pubnub_livestream/public/404.html +58 -0
  62. data/examples/pubnub_livestream/public/422.html +58 -0
  63. data/examples/pubnub_livestream/public/500.html +57 -0
  64. data/examples/pubnub_livestream/public/assets/application-22a604196dfb65fd0d602eb1eb65f9b7.js +4 -0
  65. data/examples/pubnub_livestream/public/assets/application-22a604196dfb65fd0d602eb1eb65f9b7.js.gz +0 -0
  66. data/examples/pubnub_livestream/public/assets/application-3fac0c014bbdf9ee7b3986ff615d5da0.css +5019 -0
  67. data/examples/pubnub_livestream/public/assets/application-3fac0c014bbdf9ee7b3986ff615d5da0.css.gz +0 -0
  68. data/examples/pubnub_livestream/public/assets/application-f06834e402639ad43230e3859b9bdd78.css +1 -0
  69. data/examples/pubnub_livestream/public/assets/application-f06834e402639ad43230e3859b9bdd78.css.gz +0 -0
  70. data/examples/pubnub_livestream/public/assets/application-f91b87f490140d86003c46b4d06b6c70.js +10682 -0
  71. data/examples/pubnub_livestream/public/assets/application-f91b87f490140d86003c46b4d06b6c70.js.gz +0 -0
  72. data/examples/pubnub_livestream/public/assets/manifest-c129e1f5ec52d8b661ebfa902554a2e2.json +1 -0
  73. data/examples/pubnub_livestream/public/assets/twitter/glyphicons-halflings-regular-0bc0341283e3bb8ec518375794cc7c28.eot +0 -0
  74. data/examples/pubnub_livestream/public/assets/twitter/glyphicons-halflings-regular-24dfb40c91db789b8b8faba6886ac1ef.svg +228 -0
  75. data/examples/pubnub_livestream/public/assets/twitter/glyphicons-halflings-regular-4b2130768da98222338d1519f9179528.ttf +0 -0
  76. data/examples/pubnub_livestream/public/assets/twitter/glyphicons-halflings-regular-7a07f26f72466361ac9671de2d33fd1c.woff +0 -0
  77. data/examples/pubnub_livestream/public/assets/twitter/glyphicons-halflings-regular-9f75212cf9fca594cee7e0e3587db9d1.svg +228 -0
  78. data/examples/pubnub_livestream/public/assets/twitter/glyphicons-halflings-regular-ab2f6984951c07fd89e6afdefabd93c7.eot +0 -0
  79. data/examples/pubnub_livestream/public/assets/twitter/glyphicons-halflings-regular-c21928f7d46b397b0af6b9ee4a7bd0dd.ttf +0 -0
  80. data/examples/pubnub_livestream/public/assets/twitter/glyphicons-halflings-regular-fa1d7f79d80d03f8a598822bd9df79bf.woff +0 -0
  81. data/examples/pubnub_livestream/public/favicon.ico +0 -0
  82. data/examples/pubnub_livestream/public/robots.txt +5 -0
  83. data/examples/pubnub_livestream/test/controllers/.keep +0 -0
  84. data/examples/pubnub_livestream/test/controllers/streamer_controller_test.rb +7 -0
  85. data/examples/pubnub_livestream/test/fixtures/.keep +0 -0
  86. data/examples/pubnub_livestream/test/fixtures/messages.yml +9 -0
  87. data/examples/pubnub_livestream/test/helpers/.keep +0 -0
  88. data/examples/pubnub_livestream/test/helpers/streamer_helper_test.rb +4 -0
  89. data/examples/pubnub_livestream/test/integration/.keep +0 -0
  90. data/examples/pubnub_livestream/test/mailers/.keep +0 -0
  91. data/examples/pubnub_livestream/test/models/.keep +0 -0
  92. data/examples/pubnub_livestream/test/models/message_test.rb +7 -0
  93. data/examples/pubnub_livestream/test/test_helper.rb +15 -0
  94. data/examples/pubnub_livestream/vendor/assets/javascripts/.keep +0 -0
  95. data/examples/pubnub_livestream/vendor/assets/stylesheets/.keep +0 -0
  96. data/examples/serial_publish.rb +46 -0
  97. data/examples/sinatra/.sass-cache/65d837cc121fc62381bb76d93e5bd081356aa3f9/application.sassc +0 -0
  98. data/examples/sinatra/.sass-cache/d1525a8542f6e7fb2ecd3275251283768779b344/main.rbc +0 -0
  99. data/examples/sinatra/.sass-cache/d35765d68c1df11fa3368aa802b3d38109cba214/application.sassc +0 -0
  100. data/examples/sinatra/main.rb +54 -0
  101. data/examples/sinatra/public/bootstrap-responsive.min.css +9 -0
  102. data/examples/sinatra/public/bootstrap.css +5909 -0
  103. data/examples/sinatra/public/bootstrap.min.css +845 -0
  104. data/examples/sinatra/public/jquery-1.10.2.min.js +5 -0
  105. data/examples/sinatra/views/application.sass +6 -0
  106. data/examples/sinatra/views/index.slim +16 -0
  107. data/examples/sinatra/views/layout.slim +12 -0
  108. data/examples/sinatra/views/streamer.coffee +41 -0
  109. data/examples/sub_and_unsub_1.rb +56 -0
  110. data/examples/translator.rb +129 -0
  111. data/lib/pubnub.rb +31 -375
  112. data/lib/pubnub/client.rb +527 -0
  113. data/lib/pubnub/configuration.rb +25 -0
  114. data/lib/pubnub/crypto.rb +53 -0
  115. data/lib/pubnub/error.rb +23 -0
  116. data/lib/pubnub/request.rb +288 -0
  117. data/lib/pubnub/response.rb +126 -0
  118. data/lib/pubnub/subscription.rb +24 -0
  119. data/lib/tasks/examples.rake +39 -0
  120. data/lib/version.rb +1 -0
  121. data/pubnub.gemspec +26 -0
  122. data/spec/lib/client_spec.rb +346 -0
  123. data/spec/lib/crypto_spec.rb +89 -0
  124. data/spec/lib/history_integration_spec.rb +0 -0
  125. data/spec/lib/presence_integration_spec.rb +16 -0
  126. data/spec/lib/publish_integration_spec.rb +994 -0
  127. data/spec/lib/pubnub_spec.rb +12 -0
  128. data/spec/lib/request_spec.rb +151 -0
  129. data/spec/lib/subscribe_integration_spec.rb +944 -0
  130. data/spec/lib/time_integration_spec.rb +0 -0
  131. data/spec/spec_helper.rb +15 -0
  132. metadata +158 -45
  133. data/lib/pubnub_crypto.rb +0 -53
  134. data/lib/pubnub_request.rb +0 -310
@@ -0,0 +1,527 @@
1
+ require 'pubnub/configuration.rb'
2
+ require 'pubnub/subscription.rb'
3
+ require 'em-http-request'
4
+ require 'httparty'
5
+ require 'persistent_httparty'
6
+ require 'timeout'
7
+
8
+ module Pubnub
9
+ class PubNubHTTParty
10
+ include HTTParty
11
+ default_timeout 310
12
+
13
+ def first_run?
14
+ @first_run ? true : false
15
+ end
16
+
17
+ def send_request(path, options={}, &block)
18
+ if @first_run.nil?
19
+ @first_run = true
20
+ else
21
+ @first_run = false
22
+ end
23
+ self.class.get path, options
24
+
25
+ end
26
+ end
27
+
28
+ class Client
29
+ include Configuration
30
+
31
+ attr_accessor :uuid, :cipher_key, :host, :query, :response, :timetoken, :url, :operation, :callback, :publish_key, :subscribe_key, :secret_key, :channel, :jsonp, :message, :ssl, :port
32
+ attr_accessor :close_connection, :history_limit, :history_count, :history_start, :history_end, :history_reverse, :session_uuid, :last_timetoken, :origin, :error
33
+
34
+
35
+ DEFAULT_CONNECT_CALLBACK = lambda { |msg| $log.info "CONNECTED: #{msg}" }
36
+ DEFAULT_ERROR_CALLBACK = lambda { |msg| $log.error "AN ERROR OCCURRED: #{msg}" }
37
+
38
+ def initialize(options = {})
39
+ $log = options[:logger]
40
+ $log = Logger.new('pubnub.log', 0, 100 * 1024 * 1024) unless $log
41
+
42
+ @subscriptions = Array.new
43
+
44
+ @subscription_request = nil
45
+ @retry = true
46
+ @retry_count = 0
47
+ @callback = options[:callback]
48
+ @error_callback = options[:error_callback]
49
+ @error_callback = DEFAULT_ERROR_CALLBACK unless @error_callback
50
+ @connect_callback = options[:connect_callback]
51
+ @connect_callback = DEFAULT_CONNECT_CALLBACK unless @connect_callback
52
+ @cipher_key = options[:cipher_key]
53
+ @publish_key = options[:publish_key] || DEFAULT_PUBLISH_KEY
54
+ @subscribe_key = options[:subscribe_key] || DEFAULT_SUBSCRIBE_KEY
55
+ @channel = options[:channel] || DEFAULT_CHANNEL
56
+ @message = options[:message]
57
+ @ssl = options[:ssl]
58
+ @secret_key = options[:secret_key]
59
+ @timetoken = options[:timetoken]
60
+ @session_uuid = options[:uuid] || options[:session_uuid] || UUID.new.generate
61
+
62
+ @history_count = options[:count]
63
+ @history_start = options[:start]
64
+ @history_end = options[:end]
65
+ @history_reverse = options[:reverse]
66
+
67
+ @port = options[:port]
68
+ @url = options[:url]
69
+ @origin = options[:origin]
70
+ @origin = DEFAULT_ORIGIN unless @origin
71
+ @query = options[:query]
72
+
73
+ @http_sync = options[:http_sync]
74
+
75
+ @max_retries = options[:max_retries]
76
+ @max_retries = MAX_RETRIES unless @max_retries
77
+
78
+ @non_subscribe_timeout = options[:non_subscribe_timeout]
79
+ @non_subscribe_timeout = 5 unless @non_subscribe_timeout
80
+
81
+ @reconnect_max_attempts = options[:reconnect_max_attempts]
82
+ @reconnect_max_attempts = 60 unless @reconnect_max_attempts
83
+
84
+ @reconnect_retry_interval = options[:reconnect_retry_interval]
85
+ @reconnect_retry_interval = 5 unless @reconnect_retry_interval
86
+
87
+ @reconnect_response_timeout = options[:reconnect_response_timeout]
88
+ @reconnect_response_timeout = 5 unless @reconnect_response_timeout
89
+
90
+ @sync_connection_sub = Pubnub::PubNubHTTParty.new
91
+ @sync_connection = Pubnub::PubNubHTTParty.new
92
+
93
+ @pause_subscribe = false
94
+ end
95
+
96
+ def publish(options = {}, &block)
97
+ options[:callback] = block if block_given?
98
+ options = merge_options(options, 'publish')
99
+ verify_operation('publish', options)
100
+ start_request options
101
+
102
+ end
103
+
104
+ def subscribe(options = {}, &block)
105
+ options[:callback] = block if block_given?
106
+ options = merge_options(options, 'subscribe')
107
+ verify_operation('subscribe', options)
108
+ @error_callback.call 'YOU ARE ALREADY SUBSCRIBED TO THAT CHANNEL' if get_channels_for_subscription.include? options[:channel]
109
+ $log.error 'YOU ARE ALREADY SUBSCRIBED TO THAT CHANNEL' if get_channels_for_subscription.include? options[:channel]
110
+ start_request options
111
+ end
112
+
113
+ def presence(options = {}, &block)
114
+ options[:callback] = block if block_given?
115
+ options = merge_options(options, 'presence')
116
+ verify_operation('presence', options)
117
+ start_request options
118
+ end
119
+
120
+ def history(options = {}, &block)
121
+ options[:callback] = block if block_given?
122
+ options = merge_options(options, 'history')
123
+ verify_operation('history', options)
124
+ options[:params].merge!({:count => options[:count]})
125
+ options[:params].merge!({:start => options[:start]}) unless options[:start].nil?
126
+ options[:params].merge!({:end => options[:end]}) unless options[:end].nil?
127
+ options[:params].merge!({:reverse => 'true'}) if options[:reverse]
128
+ start_request options
129
+ end
130
+
131
+ def leave(options = {}, &block)
132
+ options[:callback] = block if block_given?
133
+ options = merge_options(options, 'leave')
134
+ verify_operation('leave', options)
135
+ return false unless get_channels_for_subscription.include? options[:channel]
136
+ remove_from_subscription options[:channel]
137
+ if @subscriptions.empty?
138
+ @timetoken = 0
139
+ @subscription_request.timetoken = 0
140
+ @subscribe_connection.close
141
+ @wait_for_response = false
142
+ end
143
+ start_request options
144
+
145
+ end
146
+
147
+ alias_method :unsubscribe, :leave
148
+
149
+ def here_now(options = {}, &block)
150
+ options[:callback] = block if block_given?
151
+ options = merge_options(options, 'here_now')
152
+ verify_operation('here_now', options)
153
+ start_request options
154
+ end
155
+
156
+ def time(options = {}, &block)
157
+ options[:callback] = block if block_given?
158
+ options = merge_options(options, 'time')
159
+ verify_operation('time', options)
160
+ start_request options
161
+ end
162
+
163
+ def subscription_running?
164
+ @subscription_running
165
+ end
166
+
167
+ def active_subscriptions
168
+ @subscription_request
169
+ end
170
+
171
+ private
172
+
173
+ def remove_from_subscription(channel)
174
+ @subscriptions.delete_if { |s| s.channel.to_s == channel.to_s }
175
+ end
176
+
177
+ def merge_options(options = {}, operation = '')
178
+ options[:channel] = compile_channel_parameter(options[:channel],options[:channels]) if options[:channel] || options[:channels]
179
+ return {
180
+ :ssl => @ssl,
181
+ :cipher_key => @cipher_key,
182
+ :publish_key => @publish_key,
183
+ :subscribe_key => @subscribe_key,
184
+ :secret_key => @secret_key,
185
+ :origin => @origin,
186
+ :operation => operation,
187
+ :params => { :uuid => @session_uuid },
188
+ :timetoken => @timetoken,
189
+ :error_callback=> @error_callback
190
+ }.merge(options)
191
+ end
192
+
193
+ def start_em_if_not_running
194
+ Thread.new do
195
+ EM.run
196
+ end unless EM.reactor_running?
197
+
198
+ until EM.reactor_running? do end
199
+ end
200
+
201
+ def get_channels_for_subscription
202
+ @subscriptions.map do |sub|
203
+ sub.channel
204
+ end
205
+ end
206
+
207
+ def fire_subscriptions_callback_for(envelope)
208
+ @subscriptions.each do |subscription|
209
+ subscription.fire_callback_for envelope
210
+ end
211
+ end
212
+
213
+ def start_request(options)
214
+ request = Pubnub::Request.new(options)
215
+ unless options[:http_sync]
216
+ start_em_if_not_running
217
+
218
+ if %w(subscribe presence).include? request.operation
219
+ options[:channel].split(',').each do |channel|
220
+ @subscriptions << Subscription.new(:channel => channel, :callback => options[:callback], :error_callback => options[:error_callback]) unless get_channels_for_subscription.include? channel
221
+ end
222
+
223
+ @subscription_request = request unless @subscription_request
224
+
225
+ if @subscription_request.channel != get_channels_for_subscription.join(',') && @subscription_running
226
+ @subscribe_connection.close
227
+ @timetoken = 0
228
+ @subscription_request.timetoken = 0
229
+ @wait_for_response = false
230
+ end
231
+
232
+ @subscription_request.channel = get_channels_for_subscription.join(',')
233
+
234
+ @subscription_running = EM.add_periodic_timer(PERIODIC_TIMER) do
235
+
236
+ unless @wait_for_response || get_channels_for_subscription.empty?
237
+ @wait_for_response = true
238
+ $log.debug 'SETTING CHANNELS'
239
+ @subscription_request.channel = get_channels_for_subscription.join(',')
240
+ $log.debug 'SENDING SUBSCRIBE REQUEST'
241
+ http = send_request(@subscription_request)
242
+
243
+ http.callback do
244
+ $log.debug 'GOT SUBSCRIBE RESPONSE'
245
+ @wait_for_response = false
246
+ if http.response_header.status.to_i == 200
247
+ if is_valid_json?(http.response)
248
+ $log.debug 'GOT VALID JSON'
249
+ @subscription_request.handle_response(http)
250
+ $log.debug 'HANDLED RESPONSE'
251
+ if is_update?(@subscription_request.timetoken)
252
+ $log.debug 'TIMETOKEN UPDATED'
253
+ @subscription_request.envelopes.each do |envelope|
254
+ fire_subscriptions_callback_for envelope
255
+ end
256
+ else
257
+ $log.debug 'TIMETOKEN NOT UPDATED'
258
+ end
259
+ end
260
+ else
261
+ if request.error_callback
262
+ request.error_callback.call Pubnub::Response.new(
263
+ :error_init => true,
264
+ :message => [0, "Bad server response: #{http.response_header.status.to_i}"].to_json,
265
+ :response => [0, "Bad server response: #{http.response_header.status.to_i}"].to_json
266
+ )
267
+ else
268
+ fire_subscriptions_callback_for Pubnub::Response.new(
269
+ :error_init => true,
270
+ :message => [0, "Bad server response: #{http.response_header.status.to_i}"].to_json,
271
+ :response => [0, "Bad server response: #{http.response_header.status.to_i}"].to_json
272
+ )
273
+ end
274
+
275
+ end
276
+ end
277
+ http.errback do
278
+ $log.error 'GOT SUBSCRIBE ERROR'
279
+ @error_callback.call [0, http.error]
280
+ end
281
+ end
282
+ end unless @subscription_running
283
+ else
284
+ EM.next_tick do
285
+ $log.debug 'SENDING OTHER REQUEST'
286
+
287
+ http = send_request(request)
288
+
289
+ http.errback do
290
+ @error_callback.call [0, http.error]
291
+ end
292
+
293
+ http.callback do
294
+ $log.debug 'GOT OTHER RESPONSE'
295
+ #byebug
296
+ if http.response_header.status.to_i == 200
297
+ if is_valid_json?(http.response)
298
+ request.handle_response(http)
299
+ request.envelopes.each do |envelope|
300
+ $log.debug 'CALLING PARAMETER CALLBACK'
301
+ request.callback.call envelope
302
+ end
303
+ end
304
+ else
305
+ begin
306
+ request.handle_response(http)
307
+ request.envelopes.each do |envelope|
308
+ if request.error_callback
309
+ request.error_callback.call envelope
310
+ else
311
+ @error_callback.call envelope
312
+ end
313
+ end
314
+
315
+ rescue
316
+ if request.error_callback
317
+ request.error_callback.call Pubnub::Response.new(
318
+ :error_init => true,
319
+ :message => [0, "Bad server response: #{http.response_header.status.to_i}"].to_json,
320
+ :response => [0, "Bad server response: #{http.response_header.status.to_i}"].to_json
321
+ )
322
+ else
323
+ @error_callback.call Pubnub::Response.new(
324
+ :error_init => true,
325
+ :message => [0, "Bad server response: #{http.response_header.status.to_i}"].to_json,
326
+ :response => [0, "Bad server response: #{http.response_header.status.to_i}"].to_json
327
+ )
328
+ end
329
+ end
330
+ end
331
+ end
332
+ end
333
+ end
334
+ else
335
+ begin
336
+ if @timetoken.to_i == 0 && request.operation == 'subscribe'
337
+ time(:http_sync => true){|envelope| @timetoken = envelope.message.to_i }
338
+ end
339
+ begin
340
+ if request.query.to_s.empty?
341
+ if %w(subscribe presence).include? request.operation
342
+ response = @sync_connection_sub.send_request(request.origin + request.path, :timeout => 370)
343
+ else
344
+ response = @sync_connection.send_request(request.origin + request.path, :timeout => @non_subscribe_timeout)
345
+ end
346
+ else
347
+ if %w(subscribe presence).include? request.operation
348
+ response = @sync_connection_sub.send_request(request.origin + request.path, :query => request.query, :timeout => 370)
349
+ else
350
+ response = @sync_connection.send_request(request.origin + request.path, :query => request.query, :timeout => @non_subscribe_timeout)
351
+ end
352
+ end
353
+ rescue
354
+ msg = 'ERROR SENDING REQUEST'
355
+ @error_callback.call Pubnub::Response.new(
356
+ :error_init => true,
357
+ :message => [0, msg].to_s,
358
+ :response => [0, msg].to_s
359
+ )
360
+ @retries = 0 unless @retries
361
+ @retries += 1
362
+ if @retries <= @max_retries
363
+ return start_request options
364
+ else
365
+ msg = "ERROR SENDING REQUEST AFTER #{@retries} RETRIES"
366
+ @retries = 0
367
+ return Pubnub::Response.new(
368
+ :error_init => true,
369
+ :message => [0, msg].to_s,
370
+ :response => [0, msg].to_s
371
+ )
372
+ end
373
+ end
374
+
375
+ if @sync_connection_sub.first_run?
376
+ @connect_callback.call 'SYNC CONNECTION ESTABLISHED'
377
+ end
378
+ if response.response.code.to_i == 200
379
+ if is_valid_json?(response.body)
380
+ request.handle_response(response)
381
+ @timetoken = request.timetoken
382
+
383
+ if request.operation == 'leave'
384
+ Subscription.remove_from_subscription request.channel
385
+ end
386
+
387
+ if !request.callback.nil?
388
+ request.envelopes.each do |envelope|
389
+ request.callback.call envelope
390
+ end
391
+ else
392
+ if %w(publish leave here_now time).include? request.operation
393
+ return request.envelopes[0]
394
+ else
395
+ return request.envelopes
396
+ end
397
+ end
398
+ end
399
+ else
400
+ begin
401
+ request.handle_response(response)
402
+ if !request.callback.nil?
403
+ request.envelopes.each do |envelope|
404
+ request.callback.call envelope
405
+ end
406
+ else
407
+ if %w(publish leave here_now time).include? request.operation
408
+ return request.envelopes[0]
409
+ else
410
+ return request.envelopes
411
+ end
412
+ end
413
+ rescue
414
+ if request.error_callback
415
+ request.error_callback.call Pubnub::Response.new(
416
+ :error_init => true,
417
+ :message => [0, "Bad server response: #{response.response.code.to_i}"].to_json,
418
+ :response => [0, "Bad server response: #{response.response.code.to_i}"].to_json
419
+ )
420
+ else
421
+ @error_callback.call Pubnub::Response.new(
422
+ :error_init => true,
423
+ :message => [0, "Bad server response: #{response.response.code.to_i}"].to_json,
424
+ :response => [0, "Bad server response: #{response.response.code.to_i}"].to_json
425
+ )
426
+ end
427
+ end
428
+
429
+ if @sync_retries
430
+ @sync_retries += 1
431
+ else
432
+ @sync_retries = 1
433
+ end
434
+
435
+ if @sync_retries < @max_retries
436
+ start_request options
437
+ end
438
+ end
439
+ rescue Timeout::Error
440
+ if request.error_callback
441
+ request.error_callback.call [0, 'TIMEOUT']
442
+ else
443
+ @error_callback.call [0, 'TIMEOUT']
444
+ end
445
+ end
446
+ end
447
+ end
448
+
449
+ def send_request(request)
450
+ if %w(subscribe presence).include? request.operation
451
+ unless @subscribe_connection
452
+ @subscribe_connection = EM::HttpRequest.new(request.origin, :connect_timeout => 370, :inactivity_timeout => 370)
453
+ connection = @subscribe_connection.get :path => '/time/0', :keepalive => true, :query => request.query
454
+ #EM.next_tick do
455
+ connection.callback do
456
+ EM.defer do @connect_callback.call 'ASYNC SUBSCRIBE CONNECTION' end
457
+ end
458
+ #end
459
+ end
460
+
461
+ @subscribe_connection.get :path => request.path, :query => request.query, :keepalive => true
462
+ else
463
+ unless @connection
464
+ @connection = EM::HttpRequest.new request.origin
465
+ end
466
+ @connection.get :path => request.path, :query => request.query, :keepalive => true
467
+ end
468
+ end
469
+
470
+ def is_update?(timetoken)
471
+ if @timetoken.to_i < timetoken.to_i
472
+ @timetoken = timetoken
473
+ else
474
+ false
475
+ end
476
+
477
+ end
478
+
479
+ def is_valid_json?(response)
480
+ begin
481
+ JSON.parse(response)
482
+ valid = true
483
+ rescue
484
+ valid = false
485
+ end
486
+ valid
487
+ end
488
+
489
+ def verify_operation(operation, options)
490
+ case operation
491
+ when 'publish'
492
+ raise(ArgumentError, 'publish() requires :channel, :message parameters and, if async, callback parameter or block given.') unless (options[:channel] || options[:channels]) && (options[:callback] || options[:block_given] || options[:http_sync]) && options[:message]
493
+ when 'subscribe'
494
+ raise(ArgumentError, 'subscribe() requires :channel parameters and, if async, callback parameter or block given.') unless (options[:channel] || options[:channels]) && (options[:callback] || options[:block_given] || options[:http_sync])
495
+ when 'presence'
496
+ raise(ArgumentError, 'presence() requires :channel parameters and, if async, callback parameter or block given.') unless (options[:channel] || options[:channels]) && (options[:callback] || options[:block_given] || options[:http_sync])
497
+ when 'time'
498
+ raise(ArgumentError, 'time() require, if async, callback parameter or block given.') unless (options[:callback] || options[:block_given] || options[:http_sync])
499
+ when 'history'
500
+ raise(ArgumentError, 'history() requires :channel, :count parameters and, if async, callback parameter or block given.') unless (options[:channel] || options[:channels]) && (options[:callback] || options[:block_given] || options[:http_sync]) && options[:count]
501
+ when 'here_now'
502
+ raise(ArgumentError, 'here_now() requires :channel parameters and, if async, callback parameter or block given.') unless (options[:channel] || options[:channels]) && (options[:callback] || options[:block_given] || options[:http_sync])
503
+ when 'leave'
504
+ raise(ArgumentError, 'leave() requires :channel parameters and, if async, callback parameter or block given.') unless (options[:channel] || options[:channels]) && (options[:callback] || options[:block_given] || options[:http_sync])
505
+ end
506
+
507
+ unless options[:callback].nil?
508
+ raise('callback is invalid.') unless options[:callback].respond_to? 'call'
509
+ end
510
+
511
+ unless options[:error_callback].nil?
512
+ raise('error_callback is invalid.') unless options[:error_callback].respond_to? 'call'
513
+ end
514
+
515
+ end
516
+
517
+ def compile_channel_parameter(channel, channels)
518
+ raise(ArgumentError, 'Can\'t handle both :channel and :channels parameters given.') if channel && channels
519
+ channel = channels if channels
520
+ channel = channel.to_s if channel.class == Symbol
521
+ channel = channel.map! {|c| c.to_s}.join(',') if channel.class == Array
522
+ return channel
523
+ end
524
+
525
+ end
526
+ end
527
+