ably 1.2.4 → 1.2.6

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +2 -2
  3. data/CHANGELOG.md +27 -0
  4. data/README.md +24 -7
  5. data/SPEC.md +1722 -853
  6. data/ably.gemspec +2 -2
  7. data/lib/ably/auth.rb +19 -11
  8. data/lib/ably/models/protocol_message.rb +5 -26
  9. data/lib/ably/modules/safe_deferrable.rb +2 -2
  10. data/lib/ably/modules/state_emitter.rb +1 -1
  11. data/lib/ably/realtime/auth.rb +4 -0
  12. data/lib/ably/realtime/channel/channel_manager.rb +51 -48
  13. data/lib/ably/realtime/channel/channel_properties.rb +9 -0
  14. data/lib/ably/realtime/channel/channel_state_machine.rb +2 -0
  15. data/lib/ably/realtime/channel.rb +4 -3
  16. data/lib/ably/realtime/channels.rb +20 -0
  17. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -13
  18. data/lib/ably/realtime/client.rb +14 -6
  19. data/lib/ably/realtime/connection/connection_manager.rb +21 -22
  20. data/lib/ably/realtime/connection.rb +78 -110
  21. data/lib/ably/realtime/presence/members_map.rb +41 -92
  22. data/lib/ably/realtime/presence/presence_manager.rb +12 -17
  23. data/lib/ably/realtime/presence.rb +15 -6
  24. data/lib/ably/realtime/push.rb +0 -27
  25. data/lib/ably/realtime/recovery_key_context.rb +36 -0
  26. data/lib/ably/rest/client.rb +4 -6
  27. data/lib/ably/rest/push/admin.rb +1 -1
  28. data/lib/ably/rest/push.rb +0 -19
  29. data/lib/ably/util/ably_extensions.rb +29 -0
  30. data/lib/ably/util/crypto.rb +2 -2
  31. data/lib/ably/util/safe_deferrable.rb +1 -1
  32. data/lib/ably/version.rb +5 -7
  33. data/spec/acceptance/realtime/channel_history_spec.rb +8 -12
  34. data/spec/acceptance/realtime/channel_spec.rb +474 -300
  35. data/spec/acceptance/realtime/client_spec.rb +1 -1
  36. data/spec/acceptance/realtime/connection_failures_spec.rb +8 -25
  37. data/spec/acceptance/realtime/connection_spec.rb +33 -125
  38. data/spec/acceptance/realtime/message_spec.rb +23 -52
  39. data/spec/acceptance/realtime/presence_spec.rb +123 -92
  40. data/spec/acceptance/rest/channel_spec.rb +2 -2
  41. data/spec/acceptance/rest/client_spec.rb +9 -2
  42. data/spec/acceptance/rest/message_spec.rb +8 -11
  43. data/spec/acceptance/rest/push_admin_spec.rb +20 -15
  44. data/spec/shared/client_initializer_behaviour.rb +1 -1
  45. data/spec/support/markdown_spec_formatter.rb +1 -1
  46. data/spec/unit/models/protocol_message_spec.rb +0 -78
  47. data/spec/unit/models/token_details_spec.rb +4 -2
  48. data/spec/unit/realtime/channels_spec.rb +1 -1
  49. data/spec/unit/realtime/connection_spec.rb +0 -30
  50. data/spec/unit/realtime/recovery_key_context_spec.rb +36 -0
  51. data/spec/unit/util/crypto_spec.rb +15 -15
  52. metadata +26 -12
  53. data/spec/acceptance/realtime/push_spec.rb +0 -27
  54. data/spec/acceptance/rest/push_spec.rb +0 -25
@@ -127,14 +127,6 @@ describe Ably::Models::ProtocolMessage do
127
127
  end
128
128
  end
129
129
 
130
- context '#connection_serial' do
131
- let(:protocol_message) { new_protocol_message(connection_serial: "55") }
132
- it 'converts :connection_serial to an Integer' do
133
- expect(protocol_message.connection_serial).to be_a(Integer)
134
- expect(protocol_message.connection_serial).to eql(55)
135
- end
136
- end
137
-
138
130
  context '#flags (#TR4i)' do
139
131
  context 'when nil' do
140
132
  let(:protocol_message) { new_protocol_message({}) }
@@ -241,76 +233,6 @@ describe Ably::Models::ProtocolMessage do
241
233
  end
242
234
  end
243
235
 
244
- context '#has_connection_serial?' do
245
- context 'without connection_serial' do
246
- let(:protocol_message) { new_protocol_message({}) }
247
-
248
- it 'returns false' do
249
- expect(protocol_message.has_connection_serial?).to eql(false)
250
- end
251
- end
252
-
253
- context 'with connection_serial' do
254
- let(:protocol_message) { new_protocol_message(connection_serial: "55") }
255
-
256
- it 'returns true' do
257
- expect(protocol_message.has_connection_serial?).to eql(true)
258
- end
259
- end
260
- end
261
-
262
- context '#serial' do
263
- context 'with underlying msg_serial' do
264
- let(:protocol_message) { new_protocol_message(msg_serial: "55") }
265
- it 'converts :msg_serial to an Integer' do
266
- expect(protocol_message.serial).to be_a(Integer)
267
- expect(protocol_message.serial).to eql(55)
268
- end
269
- end
270
-
271
- context 'with underlying connection_serial' do
272
- let(:protocol_message) { new_protocol_message(connection_serial: "55") }
273
- it 'converts :connection_serial to an Integer' do
274
- expect(protocol_message.serial).to be_a(Integer)
275
- expect(protocol_message.serial).to eql(55)
276
- end
277
- end
278
-
279
- context 'with underlying connection_serial and msg_serial' do
280
- let(:protocol_message) { new_protocol_message(connection_serial: "99", msg_serial: "11") }
281
- it 'prefers connection_serial and converts :connection_serial to an Integer' do
282
- expect(protocol_message.serial).to be_a(Integer)
283
- expect(protocol_message.serial).to eql(99)
284
- end
285
- end
286
- end
287
-
288
- context '#has_serial?' do
289
- context 'without msg_serial or connection_serial' do
290
- let(:protocol_message) { new_protocol_message({}) }
291
-
292
- it 'returns false' do
293
- expect(protocol_message.has_serial?).to eql(false)
294
- end
295
- end
296
-
297
- context 'with msg_serial' do
298
- let(:protocol_message) { new_protocol_message(msg_serial: "55") }
299
-
300
- it 'returns true' do
301
- expect(protocol_message.has_serial?).to eql(true)
302
- end
303
- end
304
-
305
- context 'with connection_serial' do
306
- let(:protocol_message) { new_protocol_message(connection_serial: "55") }
307
-
308
- it 'returns true' do
309
- expect(protocol_message.has_serial?).to eql(true)
310
- end
311
- end
312
- end
313
-
314
236
  context '#error' do
315
237
  context 'with no error attribute' do
316
238
  let(:protocol_message) { new_protocol_message(action: 1) }
@@ -56,6 +56,7 @@ describe Ably::Models::TokenDetails do
56
56
 
57
57
  context '#expired?' do
58
58
  let(:expire_time) { Time.now + Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER }
59
+ let(:clock_skew) { 1 } # clock skew of 1 second
59
60
 
60
61
  context 'once grace period buffer has passed' do
61
62
  subject { Ably::Models::TokenDetails.new(expires: expire_time - 1) }
@@ -74,7 +75,7 @@ describe Ably::Models::TokenDetails do
74
75
  end
75
76
 
76
77
  context 'when expires is not available (i.e. string tokens)' do
77
- subject { Ably::Models::TokenDetails.new() }
78
+ subject { Ably::Models::TokenDetails.new }
78
79
 
79
80
  it 'is always false' do
80
81
  expect(subject.expired?).to eql(false)
@@ -90,8 +91,9 @@ describe Ably::Models::TokenDetails do
90
91
  expect(subject.expired?(from: (Time.now - server_offset_time))).to eql(false)
91
92
  end
92
93
 
94
+ # Test is flaky and fails on CI, so adding a bit of extra tolerance (clock_skew) to make it work
93
95
  it 'is true' do
94
- expect(subject.expired?(from: Time.now)).to eql(true)
96
+ expect(subject.expired?(from: Time.now + clock_skew)).to eql(true)
95
97
  end
96
98
  end
97
99
  end
@@ -2,7 +2,7 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Ably::Realtime::Channels do
5
- let(:connection) { instance_double('Ably::Realtime::Connection', unsafe_on: true, on_resume: true) }
5
+ let(:connection) { instance_double('Ably::Realtime::Connection', unsafe_on: true) }
6
6
  let(:client) do
7
7
  instance_double('Ably::Realtime::Client', connection: connection, client_id: 'clientId', logger: double('logger').as_null_object)
8
8
  end
@@ -34,36 +34,6 @@ describe Ably::Realtime::Connection do
34
34
  it_behaves_like 'an incoming protocol message bus'
35
35
  it_behaves_like 'an outgoing protocol message bus'
36
36
 
37
- describe 'connection resume callbacks', api_private: true do
38
- let(:callbacks) { [] }
39
-
40
- describe '#trigger_resumed' do
41
- it 'executes the callbacks' do
42
- subject.on_resume { callbacks << true }
43
- subject.trigger_resumed
44
- expect(callbacks.count).to eql(1)
45
- end
46
- end
47
-
48
- describe '#on_resume' do
49
- it 'registers a callback' do
50
- subject.on_resume { callbacks << true }
51
- subject.trigger_resumed
52
- expect(callbacks.count).to eql(1)
53
- end
54
- end
55
-
56
- describe '#off_resume' do
57
- it 'registers a callback' do
58
- subject.on_resume { callbacks << true }
59
- additional_proc = lambda { raise 'This should not be called' }
60
- subject.off_resume(&additional_proc)
61
- subject.trigger_resumed
62
- expect(callbacks.count).to eql(1)
63
- end
64
- end
65
- end
66
-
67
37
  after(:all) do
68
38
  sleep 1 # let realtime library shut down any open clients
69
39
  end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'ably/realtime/recovery_key_context'
3
+
4
+ describe Ably::Realtime::RecoveryKeyContext do
5
+
6
+ context 'connection recovery key' do
7
+
8
+ it 'should encode recovery key - RTN16i, RTN16f, RTN16j' do
9
+ connection_key = 'key'
10
+ msg_serial = 123
11
+ channel_serials = {
12
+ 'channel1' => 'serial1',
13
+ 'channel2' => 'serial2'
14
+ }
15
+ recovery_context = Ably::Realtime::RecoveryKeyContext.new(connection_key, msg_serial, channel_serials)
16
+ encoded_recovery_key = recovery_context.to_json
17
+ expect(encoded_recovery_key).to eq "{\"connection_key\":\"key\",\"msg_serial\":123," <<
18
+ "\"channel_serials\":{\"channel1\":\"serial1\",\"channel2\":\"serial2\"}}"
19
+ end
20
+
21
+ it 'should decode recovery key - RTN16i, RTN16f, RTN16j' do
22
+ encoded_recovery_key = "{\"connection_key\":\"key\",\"msg_serial\":123," <<
23
+ "\"channel_serials\":{\"channel1\":\"serial1\",\"channel2\":\"serial2\"}}"
24
+ decoded_recovery_key = Ably::Realtime::RecoveryKeyContext.from_json(encoded_recovery_key)
25
+ expect(decoded_recovery_key.connection_key).to eq("key")
26
+ expect(decoded_recovery_key.msg_serial).to eq(123)
27
+ end
28
+
29
+ it 'should return nil for invalid recovery key - RTN16i, RTN16f, RTN16j' do
30
+ encoded_recovery_key = "{\"invalid key\"}"
31
+ decoded_recovery_key = Ably::Realtime::RecoveryKeyContext.from_json(encoded_recovery_key)
32
+ expect(decoded_recovery_key).to be_nil
33
+ end
34
+
35
+ end
36
+ end
@@ -72,26 +72,26 @@ describe Ably::Util::Crypto do
72
72
  end
73
73
  end
74
74
 
75
- context 'encrypts & decrypt' do
75
+ context '#encrypt & #decrypt' do
76
76
  let(:string) { random_str }
77
- let(:byte_array) { random_str.to_msgpack.unpack('C*') }
78
-
79
- specify '#encrypt encrypts a string' do
80
- encrypted = subject.encrypt(string)
81
- expect(subject.decrypt(encrypted)).to eql(string)
82
- end
77
+ let(:empty_string) { '' }
83
78
 
84
- specify '#decrypt decrypts a string' do
79
+ specify 'encrypts and decrypts a non-empty string' do
80
+ expect(string).to be_ascii_only
85
81
  encrypted = subject.encrypt(string)
86
- expect(subject.decrypt(encrypted)).to eql(string)
82
+ expect(encrypted).to be_truthy
83
+ decrypted = subject.decrypt(encrypted)
84
+ expect(decrypted).to eql(string)
85
+ expect(decrypted).to be_ascii_only
87
86
  end
88
- end
89
-
90
- context 'encrypting an empty string' do
91
- let(:empty_string) { '' }
92
87
 
93
- it 'raises an ArgumentError' do
94
- expect { subject.encrypt(empty_string) }.to raise_error ArgumentError, /data must not be empty/
88
+ specify 'encrypts and decrypts an empty string' do
89
+ expect(empty_string).to be_ascii_only
90
+ encrypted = subject.encrypt(empty_string)
91
+ expect(encrypted).to be_truthy
92
+ decrypted = subject.decrypt(encrypted)
93
+ expect(decrypted).to eql(empty_string)
94
+ expect(decrypted).to be_ascii_only
95
95
  end
96
96
  end
97
97
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ably
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 1.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lewis Marshall
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-06-29 00:00:00.000000000 Z
12
+ date: 2024-07-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -26,19 +26,19 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  version: 1.2.6
28
28
  - !ruby/object:Gem::Dependency
29
- name: em-http-request
29
+ name: ably-em-http-request
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '1.1'
34
+ version: 1.1.8
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: '1.1'
41
+ version: 1.1.8
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: statesman
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -283,14 +283,14 @@ dependencies:
283
283
  requirements:
284
284
  - - "~>"
285
285
  - !ruby/object:Gem::Version
286
- version: 0.21.2
286
+ version: 0.22.0
287
287
  type: :development
288
288
  prerelease: false
289
289
  version_requirements: !ruby/object:Gem::Requirement
290
290
  requirements:
291
291
  - - "~>"
292
292
  - !ruby/object:Gem::Version
293
- version: 0.21.2
293
+ version: 0.22.0
294
294
  - !ruby/object:Gem::Dependency
295
295
  name: simplecov-lcov
296
296
  requirement: !ruby/object:Gem::Requirement
@@ -347,6 +347,20 @@ dependencies:
347
347
  - - "~>"
348
348
  - !ruby/object:Gem::Version
349
349
  version: 3.8.0
350
+ - !ruby/object:Gem::Dependency
351
+ name: webrick
352
+ requirement: !ruby/object:Gem::Requirement
353
+ requirements:
354
+ - - "~>"
355
+ - !ruby/object:Gem::Version
356
+ version: 1.7.0
357
+ type: :development
358
+ prerelease: false
359
+ version_requirements: !ruby/object:Gem::Requirement
360
+ requirements:
361
+ - - "~>"
362
+ - !ruby/object:Gem::Version
363
+ version: 1.7.0
350
364
  description: A Ruby client library for ably.io realtime messaging
351
365
  email:
352
366
  - lewis@lmars.net
@@ -455,6 +469,7 @@ files:
455
469
  - lib/ably/realtime/push/admin.rb
456
470
  - lib/ably/realtime/push/channel_subscriptions.rb
457
471
  - lib/ably/realtime/push/device_registrations.rb
472
+ - lib/ably/realtime/recovery_key_context.rb
458
473
  - lib/ably/rest.rb
459
474
  - lib/ably/rest/channel.rb
460
475
  - lib/ably/rest/channel/push_channel.rb
@@ -472,6 +487,7 @@ files:
472
487
  - lib/ably/rest/push/admin.rb
473
488
  - lib/ably/rest/push/channel_subscriptions.rb
474
489
  - lib/ably/rest/push/device_registrations.rb
490
+ - lib/ably/util/ably_extensions.rb
475
491
  - lib/ably/util/crypto.rb
476
492
  - lib/ably/util/pub_sub.rb
477
493
  - lib/ably/util/safe_deferrable.rb
@@ -487,7 +503,6 @@ files:
487
503
  - spec/acceptance/realtime/presence_history_spec.rb
488
504
  - spec/acceptance/realtime/presence_spec.rb
489
505
  - spec/acceptance/realtime/push_admin_spec.rb
490
- - spec/acceptance/realtime/push_spec.rb
491
506
  - spec/acceptance/realtime/stats_spec.rb
492
507
  - spec/acceptance/realtime/time_spec.rb
493
508
  - spec/acceptance/rest/auth_spec.rb
@@ -499,7 +514,6 @@ files:
499
514
  - spec/acceptance/rest/message_spec.rb
500
515
  - spec/acceptance/rest/presence_spec.rb
501
516
  - spec/acceptance/rest/push_admin_spec.rb
502
- - spec/acceptance/rest/push_spec.rb
503
517
  - spec/acceptance/rest/stats_spec.rb
504
518
  - spec/acceptance/rest/time_spec.rb
505
519
  - spec/lib/unit/models/channel_options_spec.rb
@@ -564,6 +578,7 @@ files:
564
578
  - spec/unit/realtime/presence_spec.rb
565
579
  - spec/unit/realtime/push_channel_spec.rb
566
580
  - spec/unit/realtime/realtime_spec.rb
581
+ - spec/unit/realtime/recovery_key_context_spec.rb
567
582
  - spec/unit/realtime/safe_deferrable_spec.rb
568
583
  - spec/unit/realtime/websocket_transport_spec.rb
569
584
  - spec/unit/rest/channel_spec.rb
@@ -592,7 +607,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
592
607
  - !ruby/object:Gem::Version
593
608
  version: '0'
594
609
  requirements: []
595
- rubygems_version: 3.1.6
610
+ rubygems_version: 3.5.4
596
611
  signing_key:
597
612
  specification_version: 4
598
613
  summary: A Ruby client library for ably.io realtime messaging implemented using EventMachine
@@ -608,7 +623,6 @@ test_files:
608
623
  - spec/acceptance/realtime/presence_history_spec.rb
609
624
  - spec/acceptance/realtime/presence_spec.rb
610
625
  - spec/acceptance/realtime/push_admin_spec.rb
611
- - spec/acceptance/realtime/push_spec.rb
612
626
  - spec/acceptance/realtime/stats_spec.rb
613
627
  - spec/acceptance/realtime/time_spec.rb
614
628
  - spec/acceptance/rest/auth_spec.rb
@@ -620,7 +634,6 @@ test_files:
620
634
  - spec/acceptance/rest/message_spec.rb
621
635
  - spec/acceptance/rest/presence_spec.rb
622
636
  - spec/acceptance/rest/push_admin_spec.rb
623
- - spec/acceptance/rest/push_spec.rb
624
637
  - spec/acceptance/rest/stats_spec.rb
625
638
  - spec/acceptance/rest/time_spec.rb
626
639
  - spec/lib/unit/models/channel_options_spec.rb
@@ -685,6 +698,7 @@ test_files:
685
698
  - spec/unit/realtime/presence_spec.rb
686
699
  - spec/unit/realtime/push_channel_spec.rb
687
700
  - spec/unit/realtime/realtime_spec.rb
701
+ - spec/unit/realtime/recovery_key_context_spec.rb
688
702
  - spec/unit/realtime/safe_deferrable_spec.rb
689
703
  - spec/unit/realtime/websocket_transport_spec.rb
690
704
  - spec/unit/rest/channel_spec.rb
@@ -1,27 +0,0 @@
1
- # encoding: utf-8
2
- require 'spec_helper'
3
-
4
- describe Ably::Realtime::Push, :event_machine do
5
- vary_by_protocol do
6
- let(:default_options) { { key: api_key, environment: environment, protocol: protocol} }
7
- let(:client_options) { default_options }
8
- let(:client) do
9
- Ably::Realtime::Client.new(client_options)
10
- end
11
- subject { client.push }
12
-
13
- describe '#activate' do
14
- it 'raises an unsupported exception' do
15
- expect { subject.activate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
16
- stop_reactor
17
- end
18
- end
19
-
20
- describe '#deactivate' do
21
- it 'raises an unsupported exception' do
22
- expect { subject.deactivate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
23
- stop_reactor
24
- end
25
- end
26
- end
27
- end
@@ -1,25 +0,0 @@
1
- # encoding: utf-8
2
- require 'spec_helper'
3
-
4
- describe Ably::Rest::Push do
5
- vary_by_protocol do
6
- let(:default_options) { { key: api_key, environment: environment, protocol: protocol} }
7
- let(:client_options) { default_options }
8
- let(:client) do
9
- Ably::Rest::Client.new(client_options)
10
- end
11
- subject { client.push }
12
-
13
- describe '#activate' do
14
- it 'raises an unsupported exception' do
15
- expect { subject.activate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
16
- end
17
- end
18
-
19
- describe '#deactivate' do
20
- it 'raises an unsupported exception' do
21
- expect { subject.deactivate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
22
- end
23
- end
24
- end
25
- end