skyfall 0.1.0 → 0.1.1

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