skyfall 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bc7ba74da06a265f8b1af42633b4c462f87fbf5764b38505628d9255bd97831
4
- data.tar.gz: 9bbb8e00563fdab6ee906ce82a3ddcde4936b8f0ee187da4d4f8032f5f344446
3
+ metadata.gz: b1d8eea31c1c63f4aabd513a470083862b653f4fb1ba5a0a638da1d9e8cba3af
4
+ data.tar.gz: 15e57a872800ad3a0c2a0f38be1ed31694617e82fe0981e1c9a1598c9f70e325
5
5
  SHA512:
6
- metadata.gz: 440c94077709828c54814ed8a4d520dbb513755412fa5baaee443d55f2493833e5c9196ffbcee256a118b8bdc6e41d92479fa041514ab8d9d16978aa4ec1d4c7
7
- data.tar.gz: b43da862f141b6ed476036eee85c8514a3b93a7a93bcaa16e089ee6149137c6b548639351445b2d3bddb3e2c458e8dc6e2c3eaa3f71d2efb9d92dad734f2fbf1
6
+ metadata.gz: 84544c24ff44ed583df898567b260db3b23517de6248b105f6199de49f2a3bcfaaada701bb62252c59a44af2845321637cfa4ab5061b9f8f800d27107fb2f83e
7
+ data.tar.gz: fb62308d1e517fdd257633a19f503dc9f9fce7d5b6b4d778a588c19facbe8c45ff60cca3e242ae9024c4975c9ca84326083e4eeddedd0da8d34f3ae9f647d05b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.1.3] - 2023-07-04
2
+
3
+ - allow passing a previously saved cursor to websocket to replay any missed events
4
+ - the cursor is also kept in memory and automatically used when reconnecting
5
+ - added "connecting" callback with url as argument
6
+ - fixed connecting to websocket when endpoint is given as a string
7
+ - improved error handling during parsing
8
+
1
9
  ## [0.1.2] - 2023-06-15
2
10
 
3
11
  - added rkey property for Operation
@@ -4,4 +4,15 @@ module Skyfall
4
4
 
5
5
  class UnsupportedError < StandardError
6
6
  end
7
+
8
+ class SubscriptionError < StandardError
9
+ attr_reader :error_type, :error_message
10
+
11
+ def initialize(error_type, error_message = nil)
12
+ @error_type = error_type
13
+ @error_message = error_message
14
+
15
+ super("Subscription error: #{error_type}" + (error_message ? " (#{error_message})" : ""))
16
+ end
17
+ end
7
18
  end
@@ -1,4 +1,6 @@
1
1
  require_relative 'websocket_message'
2
+
3
+ require 'uri'
2
4
  require 'websocket-client-simple'
3
5
 
4
6
  module Skyfall
@@ -9,11 +11,12 @@ module Skyfall
9
11
  :subscribe_repos => SUBSCRIBE_REPOS
10
12
  }
11
13
 
12
- attr_accessor :heartbeat_timeout, :heartbeat_interval
14
+ attr_accessor :heartbeat_timeout, :heartbeat_interval, :cursor
13
15
 
14
- def initialize(server, endpoint)
16
+ def initialize(server, endpoint, cursor = nil)
15
17
  @endpoint = check_endpoint(endpoint)
16
18
  @server = check_hostname(server)
19
+ @cursor = cursor
17
20
  @handlers = {}
18
21
  @heartbeat_mutex = Mutex.new
19
22
  @heartbeat_interval = 5
@@ -24,19 +27,21 @@ module Skyfall
24
27
  def connect
25
28
  return if @websocket
26
29
 
27
- url = "wss://#{@server}/xrpc/#{@endpoint}"
30
+ url = build_websocket_url
28
31
  handlers = @handlers
29
32
  stream = self
30
33
 
34
+ handlers[:connecting]&.call(url)
35
+
31
36
  @websocket = WebSocket::Client::Simple.connect(url) do |ws|
32
37
  ws.on :message do |msg|
33
38
  stream.notify_heartbeat
34
- handlers[:raw_message]&.call(msg.data)
35
39
 
36
- if handlers[:message]
37
- atp_message = Skyfall::WebsocketMessage.new(msg.data)
38
- handlers[:message].call(atp_message)
39
- end
40
+ atp_message = Skyfall::WebsocketMessage.new(msg.data)
41
+ stream.cursor = atp_message.seq
42
+
43
+ handlers[:raw_message]&.call(msg.data)
44
+ handlers[:message]&.call(atp_message)
40
45
  end
41
46
 
42
47
  ws.on :open do
@@ -116,6 +121,10 @@ module Skyfall
116
121
  @handlers[:raw_message] = block
117
122
  end
118
123
 
124
+ def on_connecting(&block)
125
+ @handlers[:connecting] = block
126
+ end
127
+
119
128
  def on_connect(&block)
120
129
  @handlers[:connect] = block
121
130
  end
@@ -135,6 +144,12 @@ module Skyfall
135
144
 
136
145
  private
137
146
 
147
+ def build_websocket_url
148
+ url = "wss://#{@server}/xrpc/#{@endpoint}"
149
+ url += "?cursor=#{@cursor}" if @cursor
150
+ url
151
+ end
152
+
138
153
  def check_endpoint(endpoint)
139
154
  if endpoint.is_a?(String)
140
155
  raise ArgumentError("Invalid endpoint name: #{endpoint}") if endpoint.strip.empty? || !endpoint.include?('.')
@@ -144,6 +159,8 @@ module Skyfall
144
159
  else
145
160
  raise ArgumentError("Endpoint should be a string or a symbol")
146
161
  end
162
+
163
+ endpoint
147
164
  end
148
165
 
149
166
  def check_hostname(server)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Skyfall
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
@@ -15,15 +15,7 @@ module Skyfall
15
15
  attr_reader :type, :repo, :time, :seq, :commit, :prev, :blocks, :operations
16
16
 
17
17
  def initialize(data)
18
- objects = CBOR.decode_sequence(data)
19
- raise DecodeError.new("Invalid number of objects: #{objects.length}") unless objects.length == 2
20
-
21
- @type_object, @data_object = objects
22
- raise DecodeError.new("Invalid object type: #{@type_object}") unless @type_object.is_a?(Hash)
23
- raise DecodeError.new("Invalid object type: #{@data_object}") unless @data_object.is_a?(Hash)
24
- raise DecodeError.new("Missing data: #{@type_object}") unless @type_object['op'] && @type_object['t']
25
- raise DecodeError.new("Invalid message type: #{@type_object['t']}") unless @type_object['t'].start_with?('#')
26
- raise UnsupportedError.new("Unexpected CBOR object: #{@type_object}") unless @type_object['op'] == 1
18
+ @type_object, @data_object = decode_cbor_objects(data)
27
19
 
28
20
  @type = @type_object['t'][1..-1].to_sym
29
21
  @operations = []
@@ -54,5 +46,32 @@ module Skyfall
54
46
  vars = keys.map { |v| "#{v}=#{instance_variable_get(v).inspect}" }.join(", ")
55
47
  "#<#{self.class}:0x#{object_id} #{vars}>"
56
48
  end
49
+
50
+ private
51
+
52
+ def decode_cbor_objects(data)
53
+ objects = CBOR.decode_sequence(data)
54
+
55
+ if objects.length < 2
56
+ raise DecodeError.new("Malformed message: #{objects.inspect}")
57
+ elsif objects.length > 2
58
+ raise DecodeError.new("Invalid number of objects: #{objects.length}")
59
+ end
60
+
61
+ type_object, data_object = objects
62
+
63
+ if data_object['error']
64
+ raise SubscriptionError.new(data_object['error'], data_object['message'])
65
+ end
66
+
67
+ raise DecodeError.new("Invalid object type: #{type_object}") unless type_object.is_a?(Hash)
68
+ raise UnsupportedError.new("Unexpected CBOR object: #{type_object}") unless type_object['op'] == 1
69
+ raise DecodeError.new("Missing data: #{type_object} #{objects.inspect}") unless type_object['op'] && type_object['t']
70
+ raise DecodeError.new("Invalid message type: #{type_object['t']}") unless type_object['t'].start_with?('#')
71
+
72
+ raise DecodeError.new("Invalid object type: #{data_object}") unless data_object.is_a?(Hash)
73
+
74
+ [type_object, data_object]
75
+ end
57
76
  end
58
77
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skyfall
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kuba Suder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-15 00:00:00.000000000 Z
11
+ date: 2023-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base32