pubnub-picklive 3.3.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []