pubnub 4.6.1 → 4.8.0

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.

@@ -0,0 +1,15 @@
1
+ ParameterType(
2
+ name: 'resourceType',
3
+ regexp: /CHANNEL|CHANNEL_GROUP|UUID/,
4
+ type: String,
5
+ transformer: ->(s) { s }
6
+ )
7
+
8
+ ParameterType(
9
+ name: 'permissionType',
10
+ regexp: /READ|WRITE|GET|MANAGE|UPDATE|JOIN|DELETE|/,
11
+ type: String,
12
+ transformer: ->(s) { s }
13
+ )
14
+
15
+
@@ -0,0 +1,39 @@
1
+ def has_permission(perms, permission_type)
2
+ current_perm = nil
3
+ eval "current_perm = Pubnub::Permissions.res(#{permission_type.downcase}: true).calculate_bitmask"
4
+ perms & current_perm != 0
5
+ end
6
+
7
+ def prepare_permissions_map(grants, resource_type)
8
+ grants
9
+ .select { |_, value|
10
+ value[:resource_type] == resource_type
11
+ }
12
+ .to_h { |name, value|
13
+ empty_permissions = if value[:pattern]
14
+ Pubnub::Permissions.pat
15
+ else
16
+ Pubnub::Permissions.res
17
+ end
18
+ permissions = value[:permission_type].reduce(empty_permissions) { |accumulated_permissions, string_perm|
19
+ accumulated_permissions.instance_variable_set("@" + string_perm.downcase, true)
20
+ accumulated_permissions
21
+ }
22
+ [name, permissions]
23
+ }
24
+ end
25
+
26
+ def call_grant_token(pubnub, grant_token_state)
27
+ pubnub.grant_token(
28
+ ttl: grant_token_state[:ttl],
29
+ http_sync: true,
30
+ channels: prepare_permissions_map(grant_token_state[:current_grant], "CHANNEL"),
31
+ channel_groups: prepare_permissions_map(grant_token_state[:current_grant], "CHANNEL_GROUP"),
32
+ uuids: prepare_permissions_map(grant_token_state[:current_grant], "UUID"),
33
+ authorized_uuid: grant_token_state[:authorized_uuid]
34
+ )
35
+ end
36
+
37
+ def parse_error_body(error_response)
38
+ Pubnub::Formatter.parse_json(error_response.status[:server_response].body)[0]
39
+ end
@@ -0,0 +1,98 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ Before do |scenario|
5
+ @grant_token_state = {}
6
+ @global_state = {}
7
+ @grant_token_state[:current_grant] = {}
8
+ @pn_configuration = {}
9
+
10
+ when_mock_server_used {
11
+ puts "Using mock"
12
+ expect(ENV['SERVER_HOST']).not_to be_nil
13
+ expect(ENV['SERVER_PORT']).not_to be_nil
14
+ @pn_configuration = {
15
+ origin: ENV['SERVER_HOST'] + ":" + ENV['SERVER_PORT'],
16
+ isSecure: false,
17
+ }
18
+ }
19
+
20
+ when_mock_server_used {
21
+ init_mock(scenario)
22
+ }
23
+ end
24
+
25
+ After do |scenario|
26
+ when_mock_server_used {
27
+ expect_mock(scenario)
28
+ }
29
+ end
30
+
31
+ def when_mock_server_used(&block)
32
+ if ENV['SERVER_MOCK']&.to_s&.downcase == 'true'
33
+ block.call
34
+ end
35
+ end
36
+
37
+ def init_mock(scenario)
38
+ contract_name = contract_name(scenario)
39
+ if contract_name
40
+ call_init_endpoint(contract_name)
41
+ end
42
+ end
43
+
44
+ def call_init_endpoint(contract_name)
45
+ Net::HTTP.get_response("#{ENV['SERVER_HOST']}", "/init?__contract__script__=#{contract_name}", "#{ENV['SERVER_PORT']}")
46
+ end
47
+
48
+ def expect_mock(scenario)
49
+ contract_name = contract_name(scenario)
50
+ if contract_name
51
+ expect_result = call_expect_endpoint()
52
+ print(expect_result)
53
+ if still_pending?(expect_result) || some_failed?(expect_result)
54
+ message = "Scenario #{extract_contract(expect_result)} considered failure:
55
+ pending - #{extract_pending(expect_result)},
56
+ failed - #{extract_failed(expect_result)}"
57
+ RSpec::Expectations.fail_with(message)
58
+ end
59
+ end
60
+ end
61
+
62
+ def extract_contract(expect_result)
63
+ expect_result['contract']
64
+ end
65
+
66
+ def extract_pending(expect_result)
67
+ expect_result['expectations']['pending'].join(", ")
68
+ end
69
+
70
+ def extract_failed(expect_result)
71
+ expect_result['expectations']['failed'].join(", ")
72
+ end
73
+
74
+ def still_pending?(expect_result)
75
+ pending = expect_result['expectations']['pending']
76
+ not pending.empty?
77
+ end
78
+
79
+ def some_failed?(expect_result)
80
+ pending = expect_result['expectations']['failed']
81
+ not pending.empty?
82
+ end
83
+
84
+ def call_expect_endpoint
85
+ expect_response = Net::HTTP.get_response("#{ENV['SERVER_HOST']}", "/expect", "#{ENV['SERVER_PORT']}")
86
+
87
+ if expect_response == nil || expect_response.body == nil
88
+ RSpec::Expectations.fail_with("Expect response body is null")
89
+ else
90
+ JSON.parse(expect_response.body)
91
+ end
92
+ end
93
+
94
+ def contract_name(scenario)
95
+ scenario.source_tag_names&.
96
+ select { |tagName| tagName.start_with?("@contract") }&.
97
+ map { |tagName| tagName.split("=")[1] }&.first
98
+ end
@@ -0,0 +1,182 @@
1
+ module Pubnub
2
+ class Cbor
3
+
4
+ private
5
+
6
+ TYPE_MASK = 0b11100000
7
+ ADDITIONAL_MASK = 0b00011111
8
+
9
+ TYPE_UNSIGNED_INT = 0b00000000
10
+ TYPE_NEGATIVE_INT = 0b00100000
11
+ TYPE_BYTE_STRING = 0b01000000
12
+ TYPE_TEXT_STRING = 0b01100000
13
+ TYPE_ARRAY = 0b10000000
14
+ TYPE_HASHMAP = 0b10100000
15
+ TYPE_TAG = 0b11000000
16
+ TYPE_FLOAT = 0b11100000
17
+
18
+ ADDITIONAL_TYPE_INDEFINITE = 31
19
+ INDEFINITE_BREAK = 0b11111111
20
+
21
+ ADDITIONAL_LENGTH_1B = 24
22
+ ADDITIONAL_LENGTH_2B = 25
23
+ ADDITIONAL_LENGTH_4B = 26
24
+ ADDITIONAL_LENGTH_8B = 27
25
+
26
+ ADDITIONAL_LENGTH_BYTES = {
27
+ ADDITIONAL_LENGTH_1B => 1,
28
+ ADDITIONAL_LENGTH_2B => 2,
29
+ ADDITIONAL_LENGTH_4B => 4,
30
+ ADDITIONAL_LENGTH_8B => 8,
31
+ }
32
+
33
+ SIMPLE_VALUE_FALSE = 0xF4
34
+ SIMPLE_VALUE_TRUE = 0xF5
35
+ SIMPLE_VALUE_NULL = 0xF6
36
+ SIMPLE_VALUE_UNDEF = 0xF7
37
+
38
+ def bytearray_to_i(byte_array)
39
+ byte_array.reverse_each.map.with_index do |b, i|
40
+ b << 8 * i
41
+ end.reduce(0) do |reduced, byte|
42
+ reduced | byte
43
+ end
44
+ end
45
+
46
+ def decode_integer(data, additional)
47
+ if ADDITIONAL_LENGTH_BYTES.member?(additional)
48
+ bytearray_to_i(data.shift(ADDITIONAL_LENGTH_BYTES[additional]))
49
+ else
50
+ additional
51
+ end
52
+ end
53
+
54
+ def decode_float(data, additional)
55
+ if additional <= 23
56
+ additional
57
+ else
58
+ bytes = bytearray_to_i(data.shift(ADDITIONAL_LENGTH_BYTES[additional]))
59
+ case (additional)
60
+ when ADDITIONAL_LENGTH_1B
61
+ bytes
62
+ when ADDITIONAL_LENGTH_2B
63
+ sign = (bytes >> 15) != 0 ? -1 : 1
64
+ exp = (bytes & 0b0111110000000000) >> 10
65
+ mant = bytes & 0b1111111111
66
+ if exp == 0
67
+ result = (2 ** -14) * (mant / 1024.to_f)
68
+ elsif exp == 0b11111
69
+ result = Float::INFINITY
70
+ else
71
+ result = (2 ** (exp - 15)) * (1 + mant / 1024.to_f)
72
+ end
73
+ sign * result
74
+ when ADDITIONAL_LENGTH_4B
75
+ sign = (bytes >> 31) != 0 ? -1 : 1
76
+ x = (bytes & ((1 << 23) - 1)) + (1 << 23)
77
+ exp = (bytes >> 23 & 0xFF) - 127
78
+ x * (2 ** (exp - 23)) * sign
79
+ when ADDITIONAL_LENGTH_8B
80
+ sign = (bytes >> 63) != 0 ? -1 : 1
81
+ exp = (bytes >> 52) & 0x7FF
82
+
83
+ mant = bytes & 0xFFFFFFFFFFFFF
84
+
85
+ if 0 == exp
86
+ val = mant * 2 ** (-(1022 + 52))
87
+ elsif 0b11111111111 != exp
88
+ val = (mant + (1 << 52)) * 2 ** (exp - (1023 + 52))
89
+ else
90
+ val = 0 == mant ? Float::INFINITY : Float::NAN
91
+ end
92
+ sign * val
93
+ end
94
+ end
95
+ end
96
+
97
+ def indefinite_data(data)
98
+ result = []
99
+
100
+ loop do
101
+ byte = data.shift
102
+ break if byte == INDEFINITE_BREAK
103
+ result.append(byte)
104
+ break if data.empty?
105
+ end
106
+ result
107
+ end
108
+
109
+ def compute_length(data, additional)
110
+ if ADDITIONAL_LENGTH_BYTES.member?(additional)
111
+ bytearray_to_i(data.shift(ADDITIONAL_LENGTH_BYTES[additional]))
112
+ else
113
+ additional
114
+ end
115
+ end
116
+
117
+ def decode_string(data, additional)
118
+ if additional == ADDITIONAL_TYPE_INDEFINITE
119
+ indefinite_data(data).pack('C*').force_encoding('UTF-8')
120
+ else
121
+ length = compute_length(data, additional)
122
+ data.shift(length).pack('C*').force_encoding('UTF-8')
123
+ end
124
+ end
125
+
126
+ def decode_map(data, additional)
127
+ length = compute_length(data, additional)
128
+ result = Hash.new
129
+ (1..length).each { result.store(parse_data(data), parse_data(data)) }
130
+ result
131
+ end
132
+
133
+ def decode_array(data, additional)
134
+ length = compute_length(data, additional)
135
+ (1..length).map { parse_data(data) }
136
+ end
137
+
138
+ def parse_data(data)
139
+ byte = data.shift
140
+
141
+ case (byte)
142
+ when SIMPLE_VALUE_NULL
143
+ return nil
144
+ when SIMPLE_VALUE_TRUE
145
+ return true
146
+ when SIMPLE_VALUE_FALSE
147
+ return false
148
+ when SIMPLE_VALUE_UNDEF
149
+ return nil
150
+ else
151
+ type = byte & TYPE_MASK
152
+ additional = byte & ADDITIONAL_MASK
153
+
154
+ case (type)
155
+ when TYPE_NEGATIVE_INT
156
+ -1 - decode_integer(data, additional)
157
+ when TYPE_UNSIGNED_INT
158
+ decode_integer(data, additional)
159
+ when TYPE_FLOAT
160
+ decode_float(data, additional).to_f
161
+ when TYPE_BYTE_STRING
162
+ decode_string(data, additional)
163
+ when TYPE_TEXT_STRING
164
+ decode_string(data, additional)
165
+ when TYPE_ARRAY
166
+ decode_array(data, additional)
167
+ when TYPE_HASHMAP
168
+ decode_map(data, additional)
169
+ else
170
+ nil
171
+ end
172
+ end
173
+ end
174
+
175
+ public
176
+
177
+ def decode(value)
178
+ parse_data(value)
179
+ end
180
+ end
181
+
182
+ end
@@ -4,7 +4,7 @@ module Pubnub
4
4
  class Client
5
5
  # Module that holds generator for all events
6
6
  module Events
7
- EVENTS = %w[publish subscribe presence leave history here_now audit grant delete_messages
7
+ EVENTS = %w[publish subscribe presence leave history here_now audit grant grant_token revoke_token delete_messages
8
8
  revoke time heartbeat where_now set_state state channel_registration message_counts signal
9
9
  add_channels_to_push list_push_provisions remove_channels_from_push remove_device_from_push
10
10
  set_uuid_metadata set_channel_metadata remove_uuid_metadata remove_channel_metadata
@@ -1,19 +1,46 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Toplevel Pubnub module.
2
4
  module Pubnub
3
5
  # Pubnub client Class
4
6
  class Client
5
7
  # Module that holds paged_history event logic
6
8
  module PagedHistory
9
+ # Fetch messages as long as one of criteria won't be met.
10
+ # Messages returned as single envelope.
11
+ def all_history_messages(options = {}, &block)
12
+ channel = options.fetch(:channel)
13
+ # Time frame between which messages should be fetched.
14
+ start_tt = options.fetch(:start, nil)
15
+ end_tt = options.fetch(:end, nil)
16
+ page_size = options.fetch(:page_size, 100) # How many messages per-request should be fetched.
17
+ reverse = options.fetch(:reverse, false) # Order in which messages should be retrieved if :end not set.
18
+ include_token = options.fetch(:include_token, true) # Whether timetoken should be included with message or not.
19
+ maximum = options.fetch(:max, 500) # Maximum number of messages which should be fetched.
20
+ callback = options.fetch(:callback, block)
21
+
22
+ reverse = false unless end_tt.nil? # Disable revers if closed time interval specified.
23
+ maximum = nil unless end_tt.nil? # Disable maximum messages count if closed time interval specified.
24
+
25
+ if options[:http_sync]
26
+ sync_all_history_messages(channel, include_token, page_size, reverse, maximum, callback, start: start_tt, end: end_tt)
27
+ else
28
+ async_all_history_messages(options)
29
+ end
30
+ end
31
+
7
32
  def paged_history(options = {}, &block)
8
33
  channel = options.fetch(:channel)
9
- page = options.fetch(:page, 1)
10
- limit = options.fetch(:limit, 100)
34
+ page = options.fetch(:page, 1) # How many mages should be fetched with specified limit.
35
+ limit = options.fetch(:limit, 100) # How many messages per page should be fetched.
36
+ include_token = options.fetch(:include_token, false) # Whether timetoken should be included with message or not.
11
37
  callback = options.fetch(:callback, block)
12
- sync = options[:http_sync]
13
- start_tt = options.fetch(:start)
14
- end_tt = options.fetch(:end)
15
- if sync
16
- sync_paged_history(channel, page, limit, callback, start: start_tt, end: end_tt)
38
+ # Time frame between which messages should be fetched.
39
+ start_tt = options.fetch(:start, nil)
40
+ end_tt = options.fetch(:end, nil)
41
+
42
+ if options[:http_sync]
43
+ sync_paged_history(channel, page, limit, include_token, callback, start: start_tt, end: end_tt)
17
44
  else
18
45
  async_paged_history(options)
19
46
  end
@@ -21,40 +48,140 @@ module Pubnub
21
48
 
22
49
  private
23
50
 
24
- def sync_paged_history(channel, page, limit, callback, timetokens)
51
+ def sync_all_history_messages(channel, include_token, page_size, reverse, maximum, callback, timetokens)
52
+ next_timetoken = timetokens[:start]
53
+ messages_timetokens = timetokens.dup
54
+ final_envelope = nil
55
+ keep_fetching = true
56
+ messages = []
57
+
58
+ while keep_fetching
59
+ envelope = history(
60
+ channel: channel,
61
+ include_token: include_token,
62
+ count: page_size,
63
+ reverse: reverse,
64
+ start: next_timetoken,
65
+ end: timetokens[:end],
66
+ http_sync: true
67
+ )
68
+
69
+ # Terminate fetch because last attempt failed.
70
+ if envelope.status[:category] != :ack
71
+ final_envelope = envelope
72
+ break
73
+ end
74
+
75
+ result_data = envelope.result[:data]
76
+ result_messages = result_data[:messages]
77
+ break if result_messages.empty?
78
+
79
+ if reverse || timetokens[:end]
80
+ messages_timetokens[:start] = result_data[:start].to_i if messages.empty?
81
+ messages_timetokens[:end] = result_data[:end].to_i
82
+ messages.concat(result_messages)
83
+ else
84
+ messages_timetokens[:end] = result_data[:end].to_i if messages.empty?
85
+ messages_timetokens[:start] = result_data[:start].to_i
86
+ messages.unshift(*result_messages)
87
+ end
88
+
89
+ keep_fetching = result_messages.length == page_size
90
+ keep_fetching = messages.length < maximum if keep_fetching && maximum && maximum > 0
91
+
92
+ if keep_fetching
93
+ next_timetoken = reverse ? result_data[:end].to_i : result_data[:start].to_i
94
+ next_timetoken = result_data[:end].to_i unless timetokens[:end].nil?
95
+ end
96
+ end
97
+
98
+ # Create envelop if no error should be reported.
99
+ final_envelope = envelope_with_messages(messages, messages_timetokens) if final_envelope.nil?
100
+
101
+ callback&.call final_envelope
102
+ final_envelope
103
+ end
104
+
105
+ # Retrieve results page-by-page (callback called for each page).
106
+ def sync_paged_history(channel, page, limit, include_token, callback, timetokens)
25
107
  envelopes = []
26
- page.times do |i|
27
- envelopes << history(
108
+ page.times do |_i|
109
+ envelope = history(
28
110
  channel: channel,
111
+ include_token: include_token,
29
112
  http_sync: true,
30
113
  count: limit,
31
114
  start: timetokens[:start],
32
115
  end: timetokens[:end]
33
116
  )
34
- envelopes.flatten!
35
- timetokens[:end] = envelopes.last.history_start.to_i
36
- envelopes = [] unless i == page - 1
117
+
118
+ break if envelope.result[:data][:messages].empty?
119
+
120
+ envelopes.push envelope
121
+ timetokens[:start] = envelope.result[:data][:start].to_i
122
+ # No need to iterate further if there is no more messages.
123
+ break if envelope.result[:data][:messages].length < limit
37
124
  end
38
125
 
39
126
  call_callback(envelopes, callback)
40
127
  end
41
128
 
42
129
  def async_paged_history(options)
43
- Concurrent::Future.new do
130
+ Concurrent::Future.execute do
44
131
  sync_options = options.dup
45
132
  sync_options[:http_sync] = true
46
- paged_history(sync_options, &block)
133
+ paged_history(sync_options)
134
+ end
135
+ end
136
+
137
+ def async_all_history_messages(options)
138
+ Concurrent::Future.execute do
139
+ sync_options = options.dup
140
+ sync_options[:http_sync] = true
141
+ all_history_messages(sync_options)
47
142
  end
48
143
  end
49
144
 
50
145
  def call_callback(envelopes, callback)
51
- envelopes.flatten!
52
146
  if callback
53
147
  envelopes.each do |envelope|
54
- secure_call callback, envelope
148
+ callback.call envelope
55
149
  end
56
150
  end
57
151
  envelopes
152
+ rescue StandardError => e
153
+ Pubnub.logger.error('Pubnub::Client') { "Error while calling callback #{e.inspect}" }
154
+ end
155
+
156
+ def envelope_with_messages(messages, timetokens)
157
+ Pubnub::Envelope.new(
158
+ event: :history,
159
+ event_options: nil,
160
+ timetoken: nil,
161
+ status: {
162
+ code: 200,
163
+ client_request: nil,
164
+ server_response: nil,
165
+
166
+ category: Pubnub::Constants::STATUS_ACK,
167
+ error: false,
168
+ auto_retried: false,
169
+
170
+ data: nil,
171
+ current_timetoken: nil,
172
+ last_timetoken: nil,
173
+ subscribed_channels: nil,
174
+ subscribed_channel_groups: nil,
175
+ config: nil
176
+ },
177
+ result: {
178
+ code: 200,
179
+ operation: Pubnub::Constants::OPERATION_HISTORY,
180
+ client_request: nil,
181
+ server_response: nil,
182
+ data: { messages: messages, end: timetokens[:end], start: timetokens[:start] }
183
+ }
184
+ )
58
185
  end
59
186
  end
60
187
  end
data/lib/pubnub/client.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'base64'
2
+
1
3
  require 'pubnub/error'
2
4
  require 'pubnub/uuid'
3
5
  require 'pubnub/formatter'
@@ -34,6 +36,8 @@ require 'pubnub/validators/client'
34
36
  require 'pubnub/validators/audit'
35
37
  require 'pubnub/validators/channel_registration'
36
38
  require 'pubnub/validators/grant'
39
+ require 'pubnub/validators/grant_token'
40
+ require 'pubnub/validators/revoke_token'
37
41
  require 'pubnub/validators/heartbeat'
38
42
  require 'pubnub/validators/here_now'
39
43
  require 'pubnub/validators/history'
@@ -67,6 +71,7 @@ require 'pubnub/validators/set_channel_members'
67
71
  require 'pubnub/validators/set_memberships'
68
72
  require 'pubnub/validators/remove_channel_members'
69
73
  require 'pubnub/validators/remove_memberships'
74
+ require 'pubnub/cbor'
70
75
 
71
76
  Dir[File.join(File.dirname(__dir__), 'pubnub', 'events', '*.rb')].each do |file|
72
77
  require file
@@ -319,6 +324,15 @@ module Pubnub
319
324
  @telemetry.await.fetch_average(event).value
320
325
  end
321
326
 
327
+ def parse_token(token)
328
+ token_bytes = Base64.urlsafe_decode64(token)
329
+ Cbor.new.decode(token_bytes.bytes)
330
+ end
331
+
332
+ def set_token(token)
333
+ @env[:token] = token
334
+ end
335
+
322
336
  private
323
337
 
324
338
  def create_state_pools(event)
@@ -57,6 +57,8 @@ module Pubnub
57
57
  OPERATION_CHANNEL_GROUP_REMOVE = :channel_group_remove
58
58
  OPERATION_AUDIT = :audit
59
59
  OPERATION_GRANT = :grant
60
+ OPERATION_GRANT_TOKEN = :grant_token
61
+ OPERATION_REVOKE_TOKEN = :revoke_token
60
62
  OPERATION_REVOKE = :revoke
61
63
  OPERATION_DELETE = :delete
62
64
  OPERATION_LIST_ALL_CHANNEL_GROUPS = :list_all_channel_groups
@@ -86,13 +88,14 @@ module Pubnub
86
88
  OPERATION_SUBSCRIBE, OPERATION_HEARTBEAT, OPERATION_PRESENCE, OPERATION_TIME, OPERATION_HISTORY,
87
89
  OPERATION_HERE_NOW, OPERATION_GLOBAL_HERE_NOW, OPERATION_GET_STATE, OPERATION_LIST_ALL_CHANNEL_GROUPS,
88
90
  OPERATION_LIST_ALL_CHANNELS_IN_CHANNEL_GROUP, OPERATION_CHANNEL_GROUP_ADD, OPERATION_CHANNEL_GROUP_REMOVE,
89
- OPERATION_AUDIT, OPERATION_GRANT, OPERATION_REVOKE, OPERATION_WHERE_NOW, OPERATION_MESSAGE_COUNTS,
90
- OPERATION_ADD_CHANNELS_TO_PUSH, OPERATION_LIST_PUSH_PROVISIONS, OPERATION_REMOVE_CHANNELS_FROM_PUSH,
91
- OPERATION_REMOVE_DEVICE_FROM_PUSH, OPERATION_SIGNAL, OPERATION_SET_UUID_METADATA, OPERATION_GET_UUID_METADATA,
92
- OPERATION_GET_ALL_UUID_METADATA, OPERATION_REMOVE_UUID_METADATA, OPERATION_SET_CHANNEL_METADATA,
93
- OPERATION_GET_CHANNEL_METADATA, OPERATION_GET_ALL_CHANNELS_METADATA, OPERATION_REMOVE_CHANNEL_METADATA,
94
- OPERATION_GET_CHANNEL_MEMBERS, OPERATION_SET_CHANNEL_MEMBERS, OPERATION_REMOVE_CHANNEL_MEMBERS,
95
- OPERATION_GET_MEMBERSHIPS, OPERATION_SET_MEMBERSHIPS, OPERATION_REMOVE_MEMBERSHIPS
91
+ OPERATION_AUDIT, OPERATION_GRANT, OPERATION_GRANT_TOKEN, OPERATION_REVOKE, OPERATION_WHERE_NOW,
92
+ OPERATION_MESSAGE_COUNTS, OPERATION_ADD_CHANNELS_TO_PUSH, OPERATION_LIST_PUSH_PROVISIONS,
93
+ OPERATION_REMOVE_CHANNELS_FROM_PUSH, OPERATION_REMOVE_DEVICE_FROM_PUSH, OPERATION_SIGNAL,
94
+ OPERATION_SET_UUID_METADATA, OPERATION_GET_UUID_METADATA, OPERATION_GET_ALL_UUID_METADATA,
95
+ OPERATION_REMOVE_UUID_METADATA, OPERATION_SET_CHANNEL_METADATA, OPERATION_GET_CHANNEL_METADATA,
96
+ OPERATION_GET_ALL_CHANNELS_METADATA, OPERATION_REMOVE_CHANNEL_METADATA, OPERATION_GET_CHANNEL_MEMBERS,
97
+ OPERATION_SET_CHANNEL_MEMBERS, OPERATION_REMOVE_CHANNEL_MEMBERS, OPERATION_GET_MEMBERSHIPS,
98
+ OPERATION_SET_MEMBERSHIPS, OPERATION_REMOVE_MEMBERSHIPS
96
99
  ].freeze
97
100
 
98
101
  # Announcements