pubnub 5.3.4 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubnub
4
+ # Holds functionality to fetch:
5
+ # - batch messages (for multiple channels)
6
+ # - messages with message actions.
7
+ class FetchMessages < SingleEvent
8
+ include Concurrent::Async
9
+ include Pubnub::Validator::FetchMessages
10
+
11
+ def initialize(options, app)
12
+ @telemetry_name = :l_hist
13
+ @include_custom_message_type = options.fetch(:include_custom_message_type, false)
14
+ @include_message_actions = options.fetch(:include_message_actions, false)
15
+ @include_message_type = options.fetch(:include_message_type, true)
16
+ @include_uuid = options.fetch(:include_uuid, true)
17
+ @include_meta = options.fetch(:include_meta, false)
18
+ @start = options[:start] if options.key?(:start)
19
+ @end = options[:end] if options.key?(:end)
20
+
21
+ channel = options[:channel] if options.key?(:channel) && !options[:channel].empty?
22
+ @channels = options[:channels] if options.key?(:channels) && !options[:channels].empty?
23
+ if @include_message_actions
24
+ @channel = channel
25
+ elsif @channels.nil? && !channel.nil?
26
+ @channels = [channel]
27
+ @channel = nil
28
+ options.delete :channel
29
+ end
30
+
31
+ maximum = @include_message_actions || @channels&.size == 1 ? 100 : 25
32
+ @max = [options[:max], maximum].min unless options[:max].nil?
33
+
34
+ @event = current_operation
35
+
36
+ # Override crypto module if custom cipher key has been used.
37
+ random_iv = options.key?(:random_iv) ? options[:random_iv] : true
38
+ options[:crypto_module] = Crypto::CryptoModule.new_legacy(options[:cipher_key], random_iv) if options[:cipher_key]
39
+
40
+ super
41
+ end
42
+
43
+ private
44
+
45
+ def current_operation
46
+ @include_message_actions ? Pubnub::Constants::OPERATION_FETCH_MESSAGES_WITH_ACTIONS : Pubnub::Constants::OPERATION_FETCH_MESSAGES
47
+ end
48
+
49
+ def parameters(signature: false)
50
+ parameters = super(signature)
51
+ parameters[:include_meta] = 'true' if @include_meta
52
+ parameters[:include_uuid] = 'true' if @include_uuid
53
+ parameters[:include_custom_message_type] = 'true' if @include_custom_message_type
54
+ parameters[:include_message_type] = 'true' if @include_message_type
55
+ parameters[:start] = @start unless @start.nil?
56
+ parameters[:end] = @end unless @end.nil?
57
+ parameters[:max] = @max unless @max.nil?
58
+
59
+ parameters
60
+ end
61
+
62
+ def path
63
+ storage_endpoint = @include_message_actions ? 'history-with-actions' : 'history'
64
+ "/v3/#{storage_endpoint}/sub-key/#{@subscribe_key}/channel/#{Pubnub::Formatter.channels_for_url((
65
+ unless @channel.nil?
66
+ [@channel]
67
+ end) || @channels)}"
68
+ end
69
+
70
+ def enable_format_channels?
71
+ false
72
+ end
73
+
74
+ def decrypt_history(crypto, message)
75
+ encrypted_message = Base64.strict_decode64(message['message'])
76
+ message['message'] = JSON.parse(crypto.decrypt(encrypted_message), quirks_mode: true)
77
+ message
78
+ rescue StandardError => e
79
+ puts "Pubnub :: DECRYPTION ERROR: #{e}"
80
+ message['decrypt_error'] = true
81
+ message
82
+ end
83
+
84
+ def valid_envelope(parsed_response, req_res_objects)
85
+ channels = parsed_response['channels'] unless parsed_response['error']
86
+ more = parsed_response['more'].transform_keys(&:to_sym) if parsed_response.key?('more')
87
+ more&.delete :url
88
+
89
+ if crypto_module && channels
90
+ crypto = crypto_module
91
+ channels.transform_values! do |channel_messages|
92
+ channel_messages.map(&method(:decrypt_history).curry[crypto])
93
+ end
94
+ end
95
+
96
+ Pubnub::Envelope.new(
97
+ event: @event,
98
+ event_options: @given_options,
99
+ timetoken: nil,
100
+ status: {
101
+ code: req_res_objects[:response].code,
102
+ client_request: req_res_objects[:request],
103
+ server_response: req_res_objects[:response],
104
+
105
+ category: Pubnub::Constants::STATUS_ACK,
106
+ error: false,
107
+ auto_retried: false,
108
+
109
+ data: nil,
110
+ current_timetoken: nil,
111
+ last_timetoken: nil,
112
+ subscribed_channels: nil,
113
+ subscribed_channel_groups: nil,
114
+
115
+ config: get_config
116
+ },
117
+ result: {
118
+ code: req_res_objects[:response].code,
119
+ operation: @event,
120
+ client_request: req_res_objects[:request],
121
+ server_response: req_res_objects[:response],
122
+
123
+ data: { channels: channels }.merge!(more.nil? ? {} : { more: more })
124
+ }
125
+ )
126
+ end
127
+ end
128
+ end
@@ -52,6 +52,7 @@ module Pubnub
52
52
  params = super
53
53
 
54
54
  empty_if_blank = {
55
+ custom_message_type: @custom_message_type,
55
56
  store: @store,
56
57
  meta: @meta,
57
58
  ttl: @ttl
@@ -26,6 +26,10 @@ module Pubnub
26
26
  def parameters(*_args)
27
27
  params = super
28
28
 
29
+ empty_if_blank = { custom_message_type: @custom_message_type }
30
+ empty_if_blank.delete_if { |_k, v| v.blank? }
31
+
32
+ params = params.merge(empty_if_blank)
29
33
  params = params.merge(seqn: @sequence_number,
30
34
  ortt: { t: @origination_time_token })
31
35
  params
@@ -60,6 +60,7 @@ module Pubnub
60
60
  end
61
61
 
62
62
  def plain_envelope(req_res_objects, timetoken)
63
+ operation = get_operation
63
64
  Pubnub::Envelope.new(
64
65
  event: @event,
65
66
  event_options: @given_options,
@@ -82,7 +83,7 @@ module Pubnub
82
83
  },
83
84
  result: {
84
85
  code: req_res_objects[:response].code,
85
- operation: get_operation,
86
+ operation: operation,
86
87
  client_request: req_res_objects[:request],
87
88
  server_response: req_res_objects[:response],
88
89
 
@@ -92,6 +93,20 @@ module Pubnub
92
93
  end
93
94
 
94
95
  def encrypted_envelope(req_res_objects, message, timetoken)
96
+ operation = get_operation(message)
97
+ data = {
98
+ message: decipher_payload(message),
99
+ subscribed_channel: message[:subscription_match] || message[:channel],
100
+ actual_channel: message[:channel],
101
+ publish_time_object: message[:publish_timetoken],
102
+ message_meta_data: message[:user_meta_data],
103
+ presence_event: get_presence_event(message),
104
+ presence: get_presence_data(message)
105
+ }
106
+ if !data[:actual_channel].end_with?('-pnpres') && (message[:type].nil? || [1, 4].include?(message[:type]))
107
+ data[:custom_message_type] = message[:custom_message_type]
108
+ end
109
+
95
110
  Pubnub::Envelope.new(
96
111
  event: @event,
97
112
  event_options: @given_options,
@@ -114,19 +129,11 @@ module Pubnub
114
129
  },
115
130
  result: {
116
131
  code: req_res_objects[:response].code,
117
- operation: get_operation(message),
132
+ operation: operation,
118
133
  client_request: req_res_objects[:request],
119
134
  server_response: req_res_objects[:response],
120
135
 
121
- data: {
122
- message: decipher_payload(message),
123
- subscribed_channel: message[:subscription_match] || message[:channel],
124
- actual_channel: message[:channel],
125
- publish_time_object: message[:publish_timetoken],
126
- message_meta_data: message[:user_meta_data],
127
- presence_event: get_presence_event(message),
128
- presence: get_presence_data(message)
129
- }
136
+ data: data
130
137
  }
131
138
  )
132
139
  end
@@ -142,10 +149,10 @@ module Pubnub
142
149
  Pubnub::Schemas::Envelope::StatusSchema.new.call status
143
150
  end
144
151
 
145
- if (results_validation + statuses_validation).map(&:failure?).index(true)
146
- Pubnub.logger.error('Pubnub::SubscribeEvent::Formatter') { 'Invalid formatted envelope.' }
147
- raise Exception, 'Invalid formatted envelope.'
148
- end
152
+ return unless (results_validation + statuses_validation).map(&:failure?).index(true)
153
+
154
+ Pubnub.logger.error('Pubnub::SubscribeEvent::Formatter') { 'Invalid formatted envelope.' }
155
+ raise Exception, 'Invalid formatted envelope.'
149
156
  end
150
157
 
151
158
  def format_envelopes(response, request)
@@ -216,6 +223,7 @@ module Pubnub
216
223
 
217
224
  def get_presence_data(message)
218
225
  return nil unless get_operation(message) == Pubnub::Constants::OPERATION_PRESENCE
226
+
219
227
  {
220
228
  uuid: message[:payload]['uuid'],
221
229
  timestamp: message[:payload]['timestamp'],
@@ -226,6 +234,7 @@ module Pubnub
226
234
 
227
235
  def get_presence_event(message)
228
236
  return nil unless get_operation(message) == Pubnub::Constants::OPERATION_PRESENCE
237
+
229
238
  message[:payload]['action']
230
239
  rescue StandardError
231
240
  nil
@@ -233,7 +242,7 @@ module Pubnub
233
242
 
234
243
  def expand_messages_keys(messages)
235
244
  messages.map do |m|
236
- {
245
+ envelope = {
237
246
  shard: m['a'],
238
247
  channel: m['c'],
239
248
  subscription_match: m['b'],
@@ -250,11 +259,15 @@ module Pubnub
250
259
  origination_time_token: expand_timetoken(m['o']),
251
260
  publish_timetoken: expand_timetoken(m['p'])
252
261
  }
262
+ envelope[:custom_message_type] = m['cmt'] if !m['c'].end_with?('-pnpres') && (envelope[:type].nil? || [1, 4].include?(envelope[:type]))
263
+
264
+ envelope
253
265
  end
254
266
  end
255
267
 
256
268
  def expand_timetoken(timetoken)
257
269
  return nil unless timetoken
270
+
258
271
  {
259
272
  timetoken: timetoken['t'],
260
273
  region_code: timetoken['r']
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubnub
4
+ # Validator module that holds all validators modules.
5
+ module Validator
6
+ # Validator for FetchMessages event.
7
+ module FetchMessages
8
+ include CommonValidator
9
+
10
+ def validate!
11
+ return if @skip_validate
12
+
13
+ validate_subscribe_key!
14
+ validate_channel_or_channels!
15
+ end
16
+
17
+ private
18
+
19
+ def validate_subscribe_key!
20
+ return unless @subscribe_key.nil?
21
+
22
+ raise(
23
+ ArgumentError.new(object: self, message: ':subscribe_key is required for fetch messages event'),
24
+ ':subscribe_key is required for fetch messages event'
25
+ )
26
+ end
27
+
28
+ def validate_channel_or_channels!
29
+ error_message = nil
30
+ if @include_message_actions
31
+ error_message = ":channels can't be used with :include_custom_message_type set to 'true'" unless @channels.nil?
32
+ error_message = ":channel is required with :include_custom_message_type set to 'true'" if @channel.nil?
33
+ elsif @channels.nil? || @channels.empty?
34
+ error_message = ':channels is required for fetch message event'
35
+ end
36
+
37
+ raise(ArgumentError.new(object: self, message: error_message), error_message) unless error_message.nil?
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,4 +1,4 @@
1
1
  # Toplevel Pubnub module.
2
2
  module Pubnub
3
- VERSION = '5.3.4'.freeze
3
+ VERSION = '5.4.0'.freeze
4
4
  end
data/pubnub.gemspec CHANGED
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.required_ruby_version = '>= 3.0.0'
20
20
 
21
21
  spec.add_dependency 'addressable', '>= 2.0.0'
22
- spec.add_dependency 'concurrent-ruby', '~> 1.1.5'
23
- spec.add_dependency 'concurrent-ruby-edge', '~> 0.5.0'
22
+ spec.add_dependency 'concurrent-ruby', '~> 1.3.4'
23
+ spec.add_dependency 'concurrent-ruby-edge', '~> 0.7.1'
24
24
  spec.add_dependency 'dry-validation', '~> 1.0'
25
25
  spec.add_dependency 'httpclient', '~> 2.8', '>= 2.8.3'
26
26
  spec.add_dependency 'json', '>= 2.2.0', '< 3'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pubnub
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.4
4
+ version: 5.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - PubNub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-29 00:00:00.000000000 Z
11
+ date: 2025-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.5
33
+ version: 1.3.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.1.5
40
+ version: 1.3.4
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: concurrent-ruby-edge
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.5.0
47
+ version: 0.7.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.5.0
54
+ version: 0.7.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: dry-validation
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -184,6 +184,7 @@ files:
184
184
  - lib/pubnub/events/audit.rb
185
185
  - lib/pubnub/events/channel_registration.rb
186
186
  - lib/pubnub/events/delete_messages.rb
187
+ - lib/pubnub/events/fetch_messages.rb
187
188
  - lib/pubnub/events/get_all_channels_metadata.rb
188
189
  - lib/pubnub/events/get_all_uuid_metadata.rb
189
190
  - lib/pubnub/events/get_channel_members.rb
@@ -251,6 +252,7 @@ files:
251
252
  - lib/pubnub/validators/client.rb
252
253
  - lib/pubnub/validators/common_validator.rb
253
254
  - lib/pubnub/validators/delete.rb
255
+ - lib/pubnub/validators/fetch_messages.rb
254
256
  - lib/pubnub/validators/get_all_channels_metadata.rb
255
257
  - lib/pubnub/validators/get_all_uuid_metadata.rb
256
258
  - lib/pubnub/validators/get_channel_members.rb