pubnub-picklive 3.3.0.7

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.
@@ -0,0 +1,413 @@
1
+ ## www.pubnub.com - PubNub realtime push service in the cloud.
2
+ ## http://www.pubnub.com/blog/ruby-push-api - Ruby Push API Blog
3
+
4
+ ## PubNub Real Time Push APIs and Notifications Framework
5
+ ## Copyright (c) 2012 PubNub
6
+ ## http://www.pubnub.com/
7
+
8
+ ## -----------------------------------
9
+ ## PubNub 3.3 Real-time Push Cloud API
10
+ ## -----------------------------------
11
+
12
+ require 'base64'
13
+ require 'open-uri'
14
+ require 'uri'
15
+
16
+ require 'pubnub_crypto'
17
+ require 'pubnub_request'
18
+
19
+ require 'eventmachine'
20
+ require 'em-http-request'
21
+ require 'yajl'
22
+ require 'json'
23
+ require 'uuid'
24
+ require 'active_support/core_ext/hash/indifferent_access'
25
+ require 'active_support/core_ext/string/inflections'
26
+ require 'active_support/core_ext/object/try'
27
+ require 'active_support/core_ext/object/blank'
28
+
29
+
30
+ class Pubnub
31
+
32
+ SUCCESS_RESPONSE = 200
33
+ MSG_TOO_LARGE_RESPONSE = 400
34
+
35
+ TIMEOUT_BAD_RESPONSE_CODE = 1
36
+ TIMEOUT_BAD_JSON_RESPONSE = 0.5
37
+ TIMEOUT_GENERAL_ERROR = 1
38
+ TIMEOUT_SUBSCRIBE = 310
39
+ TIMEOUT_NON_SUBSCRIBE = 5
40
+
41
+ class PresenceError < RuntimeError;
42
+ end
43
+ class PublishError < RuntimeError;
44
+ end
45
+ class SubscribeError < RuntimeError;
46
+ end
47
+ class InitError < RuntimeError;
48
+ end
49
+
50
+ attr_accessor :publish_key, :subscribe_key, :secret_key, :cipher_key, :ssl, :channel, :origin, :session_uuid
51
+
52
+ ORIGIN_HOST = 'pubsub.pubnub.com'
53
+ #ORIGIN_HOST = 'test.pubnub.com'
54
+
55
+ def initialize(*args)
56
+
57
+ if args.size == 5 # passing in named parameters
58
+
59
+ @publish_key = args[0].to_s
60
+ @subscribe_key = args[1].to_s
61
+ @secret_key = args[2].to_s
62
+ @cipher_key = args[3].to_s
63
+ @ssl = args[4]
64
+
65
+ elsif args.size == 1 && args[0].class == Hash # passing in an options hash
66
+
67
+ options_hash = HashWithIndifferentAccess.new(args[0])
68
+ @publish_key = options_hash[:publish_key].blank? ? nil : options_hash[:publish_key].to_s
69
+ @subscribe_key = options_hash[:subscribe_key].blank? ? nil : options_hash[:subscribe_key].to_s
70
+ @secret_key = options_hash[:secret_key].blank? ? nil : options_hash[:secret_key].to_s
71
+ @cipher_key = options_hash[:cipher_key].blank? ? nil : options_hash[:cipher_key].to_s
72
+ @ssl = options_hash[:ssl].blank? ? false : true
73
+ @logger = options_hash[:logger]
74
+
75
+ else
76
+ raise(InitError, "Initialize with either a hash of options, or exactly 5 named parameters.")
77
+ end
78
+
79
+ @session_uuid = uuid
80
+ verify_init
81
+ end
82
+
83
+ def verify_init
84
+ # publish_key and cipher_key are both optional.
85
+ raise(InitError, "subscribe_key is a mandatory parameter.") if @subscribe_key.blank?
86
+ end
87
+
88
+
89
+ def publish(options)
90
+ options = HashWithIndifferentAccess.new(options)
91
+ publish_request = PubnubRequest.new(:operation => :publish)
92
+
93
+ #TODO: refactor into initializer code on request instantiation
94
+
95
+ publish_request.ssl = @ssl
96
+ publish_request.set_origin(options)
97
+ publish_request.set_channel(options)
98
+ publish_request.set_callback(options)
99
+ publish_request.set_cipher_key(options, self.cipher_key)
100
+ publish_request.set_message(options, self.cipher_key)
101
+ publish_request.set_publish_key(options, self.publish_key)
102
+ publish_request.set_subscribe_key(options, self.subscribe_key)
103
+ publish_request.set_secret_key(options, self.secret_key)
104
+
105
+
106
+ publish_request.format_url!
107
+
108
+ check_for_em publish_request
109
+ end
110
+
111
+ def subscribe(options)
112
+ options = HashWithIndifferentAccess.new(options)
113
+
114
+ operation = options[:operation].nil? ? :subscribe : :presence
115
+
116
+ subscribe_request = PubnubRequest.new(:operation => operation, :session_uuid => @session_uuid)
117
+
118
+ #TODO: refactor into initializer code on request instantiation
119
+
120
+ subscribe_request.ssl = @ssl
121
+ subscribe_request.set_origin(options)
122
+ subscribe_request.set_channel(options)
123
+ subscribe_request.set_callback(options)
124
+ subscribe_request.set_cipher_key(options, self.cipher_key) unless subscribe_request.operation == "presence"
125
+
126
+ subscribe_request.set_subscribe_key(options, self.subscribe_key)
127
+
128
+ format_url_options = options[:override_timetoken].present? ? options[:override_timetoken] : nil
129
+ subscribe_request.format_url!(format_url_options)
130
+
131
+ check_for_em subscribe_request
132
+
133
+ end
134
+
135
+ def presence(options)
136
+ usage_error = "presence() requires :channel and :callback options."
137
+ if options.class != Hash
138
+ raise(ArgumentError, usage_error)
139
+ end
140
+
141
+ options = HashWithIndifferentAccess.new(options) unless (options == nil)
142
+
143
+ unless options[:channel] && options[:callback]
144
+ raise(ArgumentError, usage_error)
145
+ end
146
+
147
+ subscribe(options.merge(:operation => "presence"))
148
+
149
+ end
150
+
151
+
152
+ def here_now(options = nil)
153
+ usage_error = "here_now() requires :channel and :callback options."
154
+ if options.class != Hash
155
+ raise(ArgumentError, usage_error)
156
+ end
157
+
158
+ options = HashWithIndifferentAccess.new(options) unless (options == nil)
159
+
160
+ unless options[:channel] && options[:callback]
161
+ raise(ArgumentError, usage_error)
162
+ end
163
+
164
+ here_now_request = PubnubRequest.new(:operation => :here_now)
165
+
166
+ here_now_request.ssl = @ssl
167
+ here_now_request.set_channel(options)
168
+ here_now_request.set_callback(options)
169
+
170
+ here_now_request.set_subscribe_key(options, self.subscribe_key)
171
+
172
+ here_now_request.format_url!
173
+ check_for_em here_now_request
174
+
175
+ end
176
+
177
+ def detailed_history(options = nil)
178
+ usage_error = "detailed_history() requires :channel, :callback, and :count options."
179
+ if options.class != Hash
180
+ raise(ArgumentError, usage_error)
181
+ end
182
+
183
+ options = HashWithIndifferentAccess.new(options) unless (options == nil)
184
+
185
+ unless options[:count] && options[:channel] && options[:callback]
186
+ raise(ArgumentError, usage_error)
187
+ end
188
+
189
+
190
+ detailed_history_request = PubnubRequest.new(:operation => :detailed_history)
191
+
192
+ #TODO: refactor into initializer code on request instantiation
193
+
194
+ # /detailed_history/SUBSCRIBE_KEY/CHANNEL/JSONP_CALLBACK/LIMIT
195
+
196
+ detailed_history_request.ssl = @ssl
197
+ detailed_history_request.set_channel(options)
198
+ detailed_history_request.set_callback(options)
199
+ detailed_history_request.set_cipher_key(options, self.cipher_key)
200
+
201
+ detailed_history_request.set_subscribe_key(options, self.subscribe_key)
202
+
203
+ detailed_history_request.history_count = options[:count]
204
+ detailed_history_request.history_start = options[:start]
205
+ detailed_history_request.history_end = options[:end]
206
+ detailed_history_request.history_reverse = options[:reverse]
207
+
208
+ detailed_history_request.format_url!
209
+ check_for_em detailed_history_request
210
+
211
+ end
212
+
213
+ def history(options = nil)
214
+ usage_error = "history() requires :channel, :callback, and :limit options."
215
+ if options.class != Hash
216
+ raise(ArgumentError, usage_error)
217
+ end
218
+
219
+ options = HashWithIndifferentAccess.new(options) unless (options == nil)
220
+
221
+ unless options[:limit] && options[:channel] && options[:callback]
222
+ raise(ArgumentError, usage_error)
223
+ end
224
+
225
+
226
+ history_request = PubnubRequest.new(:operation => :history)
227
+
228
+ #TODO: refactor into initializer code on request instantiation
229
+
230
+ # /history/SUBSCRIBE_KEY/CHANNEL/JSONP_CALLBACK/LIMIT
231
+
232
+ history_request.ssl = @ssl
233
+ history_request.set_channel(options)
234
+ history_request.set_callback(options)
235
+ history_request.set_cipher_key(options, self.cipher_key)
236
+
237
+ history_request.set_subscribe_key(options, self.subscribe_key)
238
+ history_request.history_limit = options[:limit]
239
+
240
+ history_request.format_url!
241
+ check_for_em history_request
242
+
243
+ end
244
+
245
+ def time(options)
246
+ options = HashWithIndifferentAccess.new(options)
247
+ raise(PubNubRuntimeError, "You must supply a callback.") if options['callback'].blank?
248
+
249
+ time_request = PubnubRequest.new(:operation => :time)
250
+ time_request.set_callback(options)
251
+
252
+ time_request.format_url!
253
+ check_for_em time_request
254
+ end
255
+
256
+ def my_callback(x, quiet = false)
257
+ if quiet !=false
258
+ puts("mycallback says: #{x.to_s}")
259
+ else
260
+ ""
261
+ end
262
+
263
+ end
264
+
265
+ def uuid
266
+ UUID.new.generate
267
+ end
268
+
269
+ def check_for_em request
270
+ if EM.reactor_running?
271
+ _request(request, true)
272
+ else
273
+ EM.run do
274
+ _request(request)
275
+ end
276
+ end
277
+ end
278
+
279
+ private
280
+
281
+ def _request(request, is_reactor_running = false)
282
+ request.format_url!
283
+ EM.schedule {
284
+ begin
285
+
286
+ operation_timeout = %w(subscribe presence).include?(request.operation) ? TIMEOUT_SUBSCRIBE : TIMEOUT_NON_SUBSCRIBE
287
+ conn = EM::HttpRequest.new(request.url, :inactivity_timeout => operation_timeout) #client times out in 310s unless the server returns or timeout first
288
+ req = conn.get()
289
+
290
+ req.errback{
291
+ logAndRetryGeneralError(is_reactor_running, req, request)
292
+ }
293
+
294
+ req.callback {
295
+
296
+ if %w(subscribe presence).include?(request.operation)
297
+ if (checkForBadJSON(req) == true && request.operation == "subscribe")
298
+ logAndRetryBadJSON(is_reactor_running, req, request)
299
+ else
300
+ processGoodResponse(is_reactor_running, req, request)
301
+ end
302
+ else
303
+ if req.response_header.http_status.to_i != SUCCESS_RESPONSE
304
+
305
+ begin
306
+ server_response = Yajl.load(req.response)
307
+ request.callback.call(server_response)
308
+ rescue => e
309
+ request.callback.call([0, "Bad server response: #{req.response_header.http_status.to_i}"])
310
+ ensure
311
+ EM.stop unless is_reactor_running
312
+ end
313
+
314
+ else
315
+ processGoodResponse(is_reactor_running, req, request)
316
+ end
317
+ end
318
+
319
+ }
320
+
321
+ rescue EventMachine::ConnectionError, RuntimeError => e # RuntimeError for catching "EventMachine not initialized"
322
+ error_message = "Network Error: #{e.message}"
323
+ puts(error_message)
324
+ [0, error_message]
325
+ end
326
+ }
327
+ end
328
+
329
+ def checkForBadJSON(req)
330
+ jsonError = false
331
+ begin
332
+ JSON.parse(req.response)
333
+ rescue => e
334
+ jsonError = true
335
+ end
336
+ jsonError
337
+ end
338
+
339
+ def processGoodResponse(is_reactor_running, req, request)
340
+
341
+ if (req.response_header.http_status.to_i != SUCCESS_RESPONSE)
342
+
343
+ unless (req.response_header.http_status.to_i == MSG_TOO_LARGE_RESPONSE)
344
+ logAndRetryBadResponseCode(is_reactor_running, req, request)
345
+ end
346
+
347
+ else
348
+
349
+ request.package_response!(req.response)
350
+ cycle = request.callback.call(request.response)
351
+
352
+ if %w(subscribe presence).include?(request.operation) && (cycle != false || request.first_request?)
353
+ _request(request, is_reactor_running)
354
+ else
355
+ EM.stop unless is_reactor_running
356
+ end
357
+ end
358
+ end
359
+
360
+ def logAndRetryGeneralError(is_reactor_running, req, request)
361
+ errMsg = "#{Time.now}: Network connectivity issue while attempting to reach #{request.url}"
362
+ logError(errMsg, request.url)
363
+ retryRequest(is_reactor_running, req, request, TIMEOUT_GENERAL_ERROR)
364
+ end
365
+
366
+ def logAndRetryBadJSON(is_reactor_running, req, request)
367
+ errMsg = "#{Time.now}: Retrying from bad JSON: #{req.response.to_s}"
368
+ logError(errMsg, request.url)
369
+ retryRequest(is_reactor_running, req, request, TIMEOUT_BAD_JSON_RESPONSE)
370
+ end
371
+
372
+ def logAndRetryBadResponseCode(is_reactor_running, req, request)
373
+ errMsg = "#{Time.now}: Retrying from bad server response code: (#{req.response_header.http_status.to_i}) #{req.response.to_s}"
374
+ logError(errMsg, request.url)
375
+ retryRequest(is_reactor_running, req, request, TIMEOUT_BAD_RESPONSE_CODE)
376
+ end
377
+
378
+ def logError(errMsg, url)
379
+ logger.debug("url: #{url}")
380
+ logger.debug("#{errMsg}")
381
+ logger.debug("")
382
+ end
383
+
384
+ def retryRequest(is_reactor_running, req, request, delay)
385
+
386
+ if %w(subscribe presence).include?(request.operation)
387
+ EM::Timer.new(delay) do
388
+ _request(request, is_reactor_running)
389
+ end
390
+ else
391
+ error_msg = [0, "Request to #{request.url} failed."]
392
+
393
+ request.set_error(true)
394
+ request.callback.call(error_msg)
395
+
396
+ logger.debug(error_msg)
397
+
398
+ EM.stop unless is_reactor_running
399
+ end
400
+
401
+ end
402
+
403
+ def logger
404
+ @logger ||= init_default_logger
405
+ end
406
+
407
+ def init_default_logger
408
+ logger = Logger.new("#{Dir.tmpdir}/pubnubError.log", 10, 10000000)
409
+ logger.level = Logger::DEBUG
410
+ logger
411
+ end
412
+
413
+ end
@@ -0,0 +1,53 @@
1
+ class PubnubCrypto
2
+ require 'yajl'
3
+
4
+ def initialize(cipher_key)
5
+ @alg = "AES-256-CBC"
6
+ sha256_key = Digest::SHA256.hexdigest(cipher_key)
7
+ @key = sha256_key.slice(0,32)
8
+
9
+ #puts("\nraw sha cipher_key is: #{cipher_key}")
10
+ #puts("raw sha cipher_key is: #{sha256_key}")
11
+ #puts("padded cipher_key is: #{@key}\n")
12
+
13
+ @iv = '0123456789012345'
14
+ end
15
+
16
+
17
+ def encrypt(message)
18
+
19
+ aes = OpenSSL::Cipher::Cipher.new(@alg)
20
+ aes.encrypt
21
+ aes.key = @key
22
+ aes.iv = @iv
23
+
24
+ json_message = Yajl.dump(message)
25
+ cipher = aes.update(json_message)
26
+ cipher << aes.final
27
+
28
+ Base64.strict_encode64(cipher)
29
+
30
+ end
31
+
32
+
33
+ def decrypt(cipher_text)
34
+ decode_cipher = OpenSSL::Cipher::Cipher.new(@alg)
35
+ decode_cipher.decrypt
36
+ decode_cipher.key = @key
37
+ decode_cipher.iv = @iv
38
+
39
+ plain_text = ""
40
+
41
+ begin
42
+ undecoded_text = Base64.decode64(cipher_text)
43
+ plain_text = decode_cipher.update(undecoded_text)
44
+ plain_text << decode_cipher.final
45
+ rescue => e
46
+
47
+ return "DECRYPTION_ERROR"
48
+
49
+ end
50
+
51
+ return Yajl.load(plain_text)
52
+ end
53
+ end
@@ -0,0 +1,310 @@
1
+ class PubnubRequest
2
+ attr_accessor :cipher_key, :host, :query, :response, :timetoken, :url, :operation, :callback, :publish_key, :subscribe_key, :secret_key, :channel, :jsonp, :message, :ssl, :port
3
+ attr_accessor :history_limit, :history_count, :history_start, :history_end, :history_reverse, :session_uuid, :last_timetoken, :origin, :error
4
+
5
+ class RequestError < RuntimeError;
6
+ end
7
+
8
+ def initialize(args = {})
9
+ args = HashWithIndifferentAccess.new(args)
10
+
11
+ @operation = args[:operation].to_s
12
+ @callback = args[:callback]
13
+ @cipher_key = args[:cipher_key]
14
+ @session_uuid = args[:session_uuid]
15
+ @publish_key = args[:publish_key]
16
+ @subscribe_key = args[:subscribe_key]
17
+ @channel = args[:channel]
18
+ @jsonp = args[:jsonp].present? ? "1" : "0"
19
+ @message = args[:message]
20
+ @secret_key = args[:secret_key] || "0"
21
+ @timetoken = args[:timetoken] || "0"
22
+ @ssl = args[:ssl]
23
+
24
+ @port = args[:port]
25
+ @url = args[:url]
26
+ @host = args[:host]
27
+ @query = args[:query]
28
+ end
29
+
30
+ def op_exception
31
+ if @operation.present?
32
+ ("Pubnub::" + @operation.to_s.capitalize + "Error").constantize
33
+ else
34
+ PubnubRequest::RequestError
35
+ end
36
+ end
37
+
38
+ def ==(another)
39
+ self.operation == another.operation && self.callback == another.callback &&
40
+ self.channel == another.channel && self.message == another.message
41
+ end
42
+
43
+ def set_error(options)
44
+ options = HashWithIndifferentAccess.new(options)
45
+
46
+ if options[:error].present?
47
+ self.error = true
48
+ end
49
+ self
50
+ end
51
+
52
+ def set_origin(options)
53
+ options = HashWithIndifferentAccess.new(options)
54
+
55
+ if options[:origin].present?
56
+ self.origin = options[:origin].to_s
57
+ self
58
+ end
59
+ end
60
+
61
+ def set_channel(options)
62
+ options = HashWithIndifferentAccess.new(options)
63
+
64
+ if options[:channel].blank?
65
+ raise(op_exception, "channel is a required parameter.")
66
+ else
67
+ self.channel = options[:channel].to_s
68
+ self
69
+ end
70
+ end
71
+
72
+ def set_callback(options)
73
+ options = HashWithIndifferentAccess.new(options)
74
+
75
+ if options[:callback].blank?
76
+ raise(op_exception, "callback is a required parameter.")
77
+ elsif !options[:callback].try(:respond_to?, "call")
78
+ raise(op_exception, "callback is invalid.")
79
+ else
80
+ self.callback = options[:callback]
81
+ self
82
+ end
83
+ end
84
+
85
+
86
+ def set_cipher_key(options, self_cipher_key)
87
+ options = HashWithIndifferentAccess.new(options)
88
+
89
+ if self_cipher_key.present? && options['cipher_key'].present?
90
+ raise(op_exception, "existing cipher_key #{self_cipher_key} cannot be overridden at publish-time.")
91
+
92
+ elsif (self_cipher_key.present? && options[:cipher_key].blank?) || (self_cipher_key.blank? && options[:cipher_key].present?)
93
+
94
+ this_cipher_key = self_cipher_key || options[:cipher_key]
95
+ raise(Pubnub::PublishError, "secret key must be a string.") if this_cipher_key.class != String
96
+ self.cipher_key = this_cipher_key
97
+ end
98
+ end
99
+
100
+ def set_secret_key(options, self_secret_key)
101
+ options = HashWithIndifferentAccess.new(options)
102
+
103
+ if self_secret_key.present? && options['secret_key'].present?
104
+ raise(Pubnub::PublishError, "existing secret_key #{self_secret_key} cannot be overridden at publish-time.")
105
+
106
+ elsif (self_secret_key.present? && options[:secret_key].blank?) || (self_secret_key.blank? && options[:secret_key].present?)
107
+
108
+ my_secret_key = self_secret_key || options[:secret_key]
109
+ raise(Pubnub::PublishError, "secret key must be a string.") if my_secret_key.class != String
110
+
111
+ signature = "{ @publish_key, @subscribe_key, @secret_key, channel, message}"
112
+ digest = OpenSSL::Digest.new("sha256")
113
+ key = [my_secret_key]
114
+ hmac = OpenSSL::HMAC.hexdigest(digest, key.pack("H*"), signature)
115
+ self.secret_key = hmac
116
+ else
117
+ self.secret_key = "0"
118
+ end
119
+ end
120
+
121
+ def set_message(options, self_cipher_key)
122
+ options = HashWithIndifferentAccess.new(options)
123
+
124
+ if options[:message].blank? && options[:message] != ""
125
+ raise(op_exception, "message is a required parameter.")
126
+ else
127
+ my_cipher_key = options[:cipher_key] || self_cipher_key
128
+
129
+ if my_cipher_key.present?
130
+ self.message = Yajl.dump(aes_encrypt(my_cipher_key, options, self))
131
+ else
132
+ self.message = Yajl.dump(options[:message])
133
+ end
134
+ end
135
+ end
136
+
137
+ def set_publish_key(options, self_publish_key)
138
+ options = HashWithIndifferentAccess.new(options)
139
+
140
+ if options[:publish_key].blank? && self_publish_key.blank?
141
+ raise(Pubnub::PublishError, "publish_key is a required parameter.")
142
+ elsif self_publish_key.present? && options['publish_key'].present?
143
+ raise(Pubnub::PublishError, "existing publish_key #{self_publish_key} cannot be overridden at publish-time.")
144
+ else
145
+ self.publish_key = (self_publish_key || options[:publish_key]).to_s
146
+ end
147
+ end
148
+
149
+ def set_subscribe_key(options, self_subscribe_key)
150
+ options = HashWithIndifferentAccess.new(options)
151
+
152
+ if options[:subscribe_key].blank? && self_subscribe_key.blank?
153
+ raise(op_exception, "subscribe_key is a required parameter.")
154
+ elsif self_subscribe_key.present? && options['subscribe_key'].present?
155
+ raise(op_exception, "existing subscribe_key #{self_subscribe_key} cannot be overridden at subscribe-time.")
156
+ else
157
+ self.subscribe_key = (self_subscribe_key || options[:subscribe_key]).to_s
158
+ end
159
+ end
160
+
161
+ def package_response!(response_data)
162
+ self.response = response_data.respond_to?(:content) ? Yajl.load(response_data.content) : Yajl.load(response_data)
163
+ self.last_timetoken = self.timetoken
164
+ self.timetoken = self.response[1] unless self.operation == "time"
165
+
166
+ if self.cipher_key.present? && %w(subscribe history detailed_history).include?(self.operation)
167
+
168
+ myarr = Array.new
169
+ pc = PubnubCrypto.new(@cipher_key)
170
+
171
+ case @operation
172
+ when "publish"
173
+ iterate = self.response.first
174
+ when "subscribe"
175
+ iterate = self.response.first
176
+ when "history"
177
+ iterate = self.response
178
+ when "detailed_history"
179
+ iterate = self.response.first
180
+
181
+ else
182
+ raise(RequestError, "Don't know how to iterate on this operation.")
183
+ end
184
+
185
+ iterate.each do |message|
186
+ message = pc.decrypt(message)
187
+ myarr.push(message)
188
+ end
189
+
190
+ if %w(publish subscribe).include?(@operation)
191
+ self.response[0] = myarr
192
+ elsif @operation == "detailed_history"
193
+ json_response_data = Yajl.load(response_data)
194
+ self.response = [myarr, json_response_data[1], json_response_data[2]]
195
+ else
196
+ self.response = myarr
197
+ end
198
+
199
+ end
200
+ end
201
+
202
+ def format_url!(override_timetoken = nil)
203
+
204
+ raise(Pubnub::PublishError, "Missing .operation in PubnubRequest object") if self.operation.blank?
205
+
206
+ if @ssl.present?
207
+ origin = 'https://' + (self.origin.present? ? self.origin : Pubnub::ORIGIN_HOST)
208
+ @port = 443
209
+ else
210
+ origin = 'http://' + (self.origin.present? ? self.origin : Pubnub::ORIGIN_HOST)
211
+ @port = 80
212
+ end
213
+
214
+ if override_timetoken.present?
215
+ self.timetoken = override_timetoken.to_s
216
+ end
217
+
218
+ case self.operation.to_s
219
+ when "publish"
220
+ url_array = [self.operation.to_s, self.publish_key.to_s, self.subscribe_key.to_s,
221
+ self.secret_key.to_s, self.channel.to_s, "0", self.message]
222
+
223
+ when "subscribe"
224
+ url_array = [self.operation.to_s, self.subscribe_key.to_s, self.channel.to_s, "0", @timetoken]
225
+
226
+ when "presence"
227
+ url_array = ["subscribe", self.subscribe_key.to_s, ((self.channel.to_s) + "-pnpres"), "0", @timetoken]
228
+
229
+ when "time"
230
+ url_array = [self.operation.to_s, "0"]
231
+
232
+ when "history"
233
+ url_array = [self.operation.to_s, self.subscribe_key.to_s, self.channel.to_s, "0", self.history_limit.to_s]
234
+
235
+ when "detailed_history"
236
+ url_array = ["v2", "history", "sub-key", self.subscribe_key.to_s, "channel", self.channel.to_s]
237
+
238
+ when "here_now"
239
+ url_array = ["v2", "presence", "sub-key", self.subscribe_key.to_s, "channel", self.channel.to_s]
240
+
241
+ else
242
+
243
+ raise(PubnubRequest::RequestError, "I can't create that URL for you due to unknown operation type.")
244
+ end
245
+
246
+ self.url = origin + encode_URL(url_array)
247
+
248
+ uri = URI.parse(self.url)
249
+
250
+ self.host = uri.host
251
+ url_params = ""
252
+
253
+ if %w(subscribe presence).include?(@operation)
254
+ uri.query = uri.query.blank? ? "uuid=#{@session_uuid}" : (uri.query + "uuid=#{@session_uuid}")
255
+
256
+ elsif @operation == "detailed_history"
257
+ url_sep = "?"
258
+
259
+ if @history_count || @history_start || @history_end || @history_reverse
260
+
261
+ if @history_count
262
+ url_params += url_sep + "count=" + @history_count.to_s
263
+ url_sep = "&"
264
+ end
265
+
266
+ if @history_start
267
+ url_params += url_sep + "start=" + @history_start.to_s
268
+ url_sep = "&"
269
+ end
270
+
271
+ if @history_end
272
+ url_params += url_sep + "end=" + @history_end.to_s
273
+ url_sep = "&"
274
+ end
275
+
276
+ if @history_reverse
277
+ url_params += url_sep + "reverse=true"
278
+ url_sep = "&"
279
+ end
280
+ end
281
+ end
282
+
283
+ self.query = uri.path + (uri.query.present? ? ("?" + uri.query) : "") + url_params
284
+ self.url += url_params
285
+ self
286
+
287
+ end
288
+
289
+ def aes_encrypt(cipher_key, options, publish_request)
290
+ options = HashWithIndifferentAccess.new(options)
291
+
292
+ pc = PubnubCrypto.new(cipher_key)
293
+ publish_request.message = pc.encrypt(options[:message])
294
+
295
+ end
296
+
297
+ def encode_URL(request)
298
+ ## Construct Request URL
299
+ url = '/' + request.map { |bit| bit.split('').map { |ch|
300
+ ' ~`!@#$%^&*()+=[]\\{}|;\':",./<>?'.index(ch) ?
301
+ '%' + ch.unpack('H2')[0].to_s.upcase : URI.encode(ch)
302
+ }.join('') }.join('/')
303
+ return url
304
+ end
305
+
306
+ def first_request?
307
+ @last_timetoken == "0"
308
+ end
309
+
310
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pubnub-picklive
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 3.3.0.7
6
+ platform: ruby
7
+ authors:
8
+ - PubNub
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ type: :runtime
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ! '>='
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
29
+ name: activesupport
30
+ - !ruby/object:Gem::Dependency
31
+ type: :runtime
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ name: eventmachine
46
+ - !ruby/object:Gem::Dependency
47
+ type: :runtime
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ prerelease: false
55
+ version_requirements: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ name: em-http-request
62
+ - !ruby/object:Gem::Dependency
63
+ type: :runtime
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.3.5
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 2.3.5
77
+ name: uuid
78
+ - !ruby/object:Gem::Dependency
79
+ type: :runtime
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ name: yajl-ruby
94
+ - !ruby/object:Gem::Dependency
95
+ type: :runtime
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ prerelease: false
103
+ version_requirements: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ name: json
110
+ description: Ruby anywhere in the world in 250ms with PubNub!
111
+ email: support@pubnub.com
112
+ executables: []
113
+ extensions: []
114
+ extra_rdoc_files: []
115
+ files:
116
+ - lib/pubnub.rb
117
+ - lib/pubnub_crypto.rb
118
+ - lib/pubnub_request.rb
119
+ homepage: http://github.com/pubnub/pubnub-api
120
+ licenses:
121
+ - MIT
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubyforge_project:
140
+ rubygems_version: 1.8.24
141
+ signing_key:
142
+ specification_version: 3
143
+ summary: PubNub Official Ruby gem
144
+ test_files: []