skyfall 0.1.0 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4045bf9dcd6a2ed5078cb557a64dc67c9e3d3c829a2909d9451c72c89f591c42
4
- data.tar.gz: 1b2813d54fbd7cdd34334404f1e9607d05bbf923584009eedd0b630f8182fd7b
3
+ metadata.gz: 0c827cbd3a6c7563d7a84ea7ec0547b0b75f5bfa1626373493ede36d9c8c10c1
4
+ data.tar.gz: 840e0cb0a8d007e2aa49a7805d15b68494a87cf03c756056cc618aaba476eb25
5
5
  SHA512:
6
- metadata.gz: 5c439017a0d277eb20977600847e74c8d52570ebb4eed3db5c39624d573b44dcc7b2404154131cf828f15df97b132a2b16de2eb608b6ed3a64e52c5a8f80b1e1
7
- data.tar.gz: feadd80a468759c3a1a62b634e22ac4aa950bad708ffed6d7ed77b575a21c8841c01a0dc145da039f36203be0f92695d251f76e41de395d2296b4a1afd0e87fe
6
+ metadata.gz: b87ccd4ee8fd5652ccb72e8b4312e03a0dbc938c01c0d47b4b0cf7896c89e9ad6e9482fd9fc914210098d7be8867a0198197db788569f63c30edbf9cf5dedc11
7
+ data.tar.gz: 86b9fcc440daeaa3e1bfea26a1707c5789bbf7141d2d21c1f279e1704c717c048807bda01f5dba05de1cfebc101715247fa0901fb9a42b641e6516f265c0e716
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [0.1.1] - 2023-06-13
2
+
3
+ - added heartbeat thread to restart websocket if it stops responding
4
+
1
5
  ## [0.1.0] - 2023-06-01
2
6
 
3
7
  - connecting to the firehose websocket
data/README.md CHANGED
@@ -52,7 +52,8 @@ Each message passed to `on_message` is an instance of the `WebsocketMessage` cla
52
52
  - `seq` (sequential number)
53
53
  - `time` (Time)
54
54
  - `repo` (string) - DID of the repository (user account)
55
- - `commit` - CID
55
+ - `commit` - CID of the commit
56
+ - `prev` - CID of the previous commit in that repo
56
57
  - `operations` - list of operations (usually one)
57
58
 
58
59
  Operations are objects of type `Operation` and have such properties:
@@ -63,9 +64,9 @@ Operations are objects of type `Operation` and have such properties:
63
64
  - `action` (symbol) - `:create`, `:update` or `:delete`
64
65
  - `uri` (string) - the at:// URI
65
66
  - `type` (symbol) - short name of the collection, e.g. `:bsky_post`
66
- - `cid` - CID
67
+ - `cid` - CID of the operation/record (`nil` for delete operations)
67
68
 
68
- Most operations will also have an attached record (JSON object) with details of the post, like etc. The record data is currently available as a Ruby hash via `raw_record` property (custom types will be added in a later version).
69
+ Create and update operations will also have an attached record (JSON object) with details of the post, like etc. The record data is currently available as a Ruby hash via `raw_record` property (custom types will be added in a later version).
69
70
 
70
71
  So for example, in order to filter only "create post" operations and print their details, you can do something like this:
71
72
 
data/lib/skyfall/cid.rb CHANGED
@@ -16,6 +16,14 @@ module Skyfall
16
16
  CID.new(data[1..-1])
17
17
  end
18
18
 
19
+ def self.from_json(string)
20
+ raise DecodeError.new("Unexpected CID length") unless string.length == 59
21
+ raise DecodeError.new("Unexpected CID prefix") unless string[0] == 'b'
22
+
23
+ data = Base32.decode(string[1..-1].upcase)
24
+ CID.new(data)
25
+ end
26
+
19
27
  def initialize(data)
20
28
  @data = data
21
29
  end
@@ -7,5 +7,6 @@ module Skyfall
7
7
  BSKY_BLOCK = "app.bsky.graph.block"
8
8
  BSKY_PROFILE = "app.bsky.actor.profile"
9
9
  BSKY_LISTITEM = "app.bsky.graph.listitem"
10
+ BSKY_FEED = "app.bsky.feed.generator"
10
11
  end
11
12
  end
@@ -33,6 +33,7 @@ module Skyfall
33
33
  when Collection::BSKY_BLOCK then :bsky_block
34
34
  when Collection::BSKY_PROFILE then :bsky_profile
35
35
  when Collection::BSKY_LISTITEM then :bsky_listitem
36
+ when Collection::BSKY_FEED then :bsky_feed
36
37
  else :unknown
37
38
  end
38
39
  end
@@ -9,10 +9,16 @@ module Skyfall
9
9
  :subscribe_repos => SUBSCRIBE_REPOS
10
10
  }
11
11
 
12
+ attr_accessor :heartbeat_timeout, :heartbeat_interval
13
+
12
14
  def initialize(server, endpoint)
13
15
  @endpoint = check_endpoint(endpoint)
14
16
  @server = check_hostname(server)
15
17
  @handlers = {}
18
+ @heartbeat_mutex = Mutex.new
19
+ @heartbeat_interval = 5
20
+ @heartbeat_timeout = 30
21
+ @last_update = nil
16
22
  end
17
23
 
18
24
  def connect
@@ -20,9 +26,11 @@ module Skyfall
20
26
 
21
27
  url = "wss://#{@server}/xrpc/#{@endpoint}"
22
28
  handlers = @handlers
29
+ stream = self
23
30
 
24
31
  @websocket = WebSocket::Client::Simple.connect(url) do |ws|
25
32
  ws.on :message do |msg|
33
+ stream.notify_heartbeat
26
34
  handlers[:raw_message]&.call(msg.data)
27
35
 
28
36
  if handlers[:message]
@@ -43,15 +51,61 @@ module Skyfall
43
51
  handlers[:error]&.call(e)
44
52
  end
45
53
  end
54
+
55
+ if @heartbeat_interval && @heartbeat_timeout && @heartbeat_thread.nil?
56
+ hb_interval = @heartbeat_interval
57
+ hb_timeout = @heartbeat_timeout
58
+
59
+ @last_update = Time.now
60
+
61
+ @heartbeat_thread = Thread.new do
62
+ loop do
63
+ sleep(hb_interval)
64
+ @heartbeat_mutex.synchronize do
65
+ if Time.now - @last_update > hb_timeout
66
+ force_restart
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ def force_restart
75
+ @websocket.close
76
+ @websocket = nil
77
+
78
+ timeout = 5
79
+
80
+ loop do
81
+ begin
82
+ @handlers[:reconnect]&.call
83
+ connect
84
+ break
85
+ rescue Exception => e
86
+ @handlers[:error]&.call(e)
87
+ sleep(timeout)
88
+ timeout *= 2
89
+ end
90
+ end
91
+
92
+ @last_update = Time.now
46
93
  end
47
94
 
48
95
  def disconnect
49
96
  return unless @websocket
50
97
 
98
+ @heartbeat_thread&.kill
99
+ @heartbeat_thread = nil
100
+
51
101
  @websocket.close
52
102
  @websocket = nil
53
103
  end
54
104
 
105
+ def notify_heartbeat
106
+ @heartbeat_mutex.synchronize { @last_update = Time.now }
107
+ end
108
+
55
109
  alias close disconnect
56
110
 
57
111
  def on_message(&block)
@@ -74,6 +128,10 @@ module Skyfall
74
128
  @handlers[:error] = block
75
129
  end
76
130
 
131
+ def on_reconnect(&block)
132
+ @handlers[:reconnect] = block
133
+ end
134
+
77
135
 
78
136
  private
79
137
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Skyfall
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
@@ -12,7 +12,7 @@ module Skyfall
12
12
  using Skyfall::Extensions
13
13
 
14
14
  attr_reader :type_object, :data_object
15
- attr_reader :type, :repo, :time, :seq, :commit, :blocks, :operations
15
+ attr_reader :type, :repo, :time, :seq, :commit, :prev, :blocks, :operations
16
16
 
17
17
  def initialize(data)
18
18
  objects = CBOR.decode_sequence(data)
@@ -34,7 +34,9 @@ module Skyfall
34
34
 
35
35
  return unless @type == :commit
36
36
 
37
- @commit = CID.from_cbor_tag(@data_object['commit'])
37
+ @commit = @data_object['commit'] && CID.from_cbor_tag(@data_object['commit'])
38
+ @prev = @data_object['prev'] && CID.from_cbor_tag(@data_object['prev'])
39
+
38
40
  @blocks = CarArchive.new(@data_object['blocks'])
39
41
 
40
42
  @operations = @data_object['ops'].map { |op|
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.0
4
+ version: 0.1.1
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-01 00:00:00.000000000 Z
11
+ date: 2023-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base32