pubnub 5.3.4 → 5.4.0

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,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