skyfall 0.4.0 → 0.5.0

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/README.md +182 -29
  4. data/example/block_tracker.rb +1 -1
  5. data/example/{monitor_phrases.rb → jet_monitor_phrases.rb} +3 -2
  6. data/example/print_all_posts.rb +1 -1
  7. data/example/push_notifications.rb +1 -1
  8. data/lib/skyfall/car_archive.rb +13 -12
  9. data/lib/skyfall/collection.rb +26 -0
  10. data/lib/skyfall/{messages → firehose}/account_message.rb +3 -1
  11. data/lib/skyfall/{messages → firehose}/commit_message.rb +9 -3
  12. data/lib/skyfall/firehose/handle_message.rb +14 -0
  13. data/lib/skyfall/firehose/identity_message.rb +9 -0
  14. data/lib/skyfall/{messages → firehose}/info_message.rb +3 -1
  15. data/lib/skyfall/{messages → firehose}/labels_message.rb +2 -2
  16. data/lib/skyfall/{messages/websocket_message.rb → firehose/message.rb} +13 -11
  17. data/lib/skyfall/firehose/operation.rb +58 -0
  18. data/lib/skyfall/firehose/tombstone_message.rb +11 -0
  19. data/lib/skyfall/firehose/unknown_message.rb +6 -0
  20. data/lib/skyfall/firehose.rb +79 -0
  21. data/lib/skyfall/jetstream/account_message.rb +19 -0
  22. data/lib/skyfall/jetstream/commit_message.rb +16 -0
  23. data/lib/skyfall/jetstream/identity_message.rb +15 -0
  24. data/lib/skyfall/jetstream/message.rb +50 -0
  25. data/lib/skyfall/jetstream/operation.rb +58 -0
  26. data/lib/skyfall/jetstream/unknown_message.rb +6 -0
  27. data/lib/skyfall/jetstream.rb +121 -0
  28. data/lib/skyfall/stream.rb +39 -59
  29. data/lib/skyfall/version.rb +1 -1
  30. data/lib/skyfall.rb +4 -2
  31. metadata +21 -14
  32. data/example/follower_tracker.rb +0 -84
  33. data/lib/skyfall/messages/handle_message.rb +0 -12
  34. data/lib/skyfall/messages/identity_message.rb +0 -7
  35. data/lib/skyfall/messages/tombstone_message.rb +0 -9
  36. data/lib/skyfall/messages/unknown_message.rb +0 -4
  37. data/lib/skyfall/operation.rb +0 -74
@@ -0,0 +1,58 @@
1
+ require_relative '../collection'
2
+ require_relative '../firehose'
3
+
4
+ module Skyfall
5
+ class Firehose::Operation
6
+ def initialize(message, json)
7
+ @message = message
8
+ @json = json
9
+ end
10
+
11
+ def repo
12
+ @message.repo
13
+ end
14
+
15
+ alias did repo
16
+
17
+ def path
18
+ @json['path']
19
+ end
20
+
21
+ def action
22
+ @json['action'].to_sym
23
+ end
24
+
25
+ def collection
26
+ @json['path'].split('/')[0]
27
+ end
28
+
29
+ def rkey
30
+ @json['path'].split('/')[1]
31
+ end
32
+
33
+ def uri
34
+ "at://#{repo}/#{path}"
35
+ end
36
+
37
+ def cid
38
+ @cid ||= @json['cid'] && CID.from_cbor_tag(@json['cid'])
39
+ end
40
+
41
+ def raw_record
42
+ @raw_record ||= @message.raw_record_for_operation(self)
43
+ end
44
+
45
+ def type
46
+ Collection.short_code(collection)
47
+ end
48
+
49
+ def inspectable_variables
50
+ instance_variables - [:@message]
51
+ end
52
+
53
+ def inspect
54
+ vars = inspectable_variables.map { |v| "#{v}=#{instance_variable_get(v).inspect}" }.join(", ")
55
+ "#<#{self.class}:0x#{object_id} #{vars}>"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../firehose'
2
+
3
+ module Skyfall
4
+
5
+ #
6
+ # Note: this event type is deprecated and will stop being emitted at some point.
7
+ # You should instead listen for 'account' events (Skyfall::Firehose::AccountMessage).
8
+ #
9
+ class Firehose::TombstoneMessage < Firehose::Message
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ require_relative '../firehose'
2
+
3
+ module Skyfall
4
+ class Firehose::UnknownMessage < Firehose::Message
5
+ end
6
+ end
@@ -0,0 +1,79 @@
1
+ require_relative 'stream'
2
+ require 'uri'
3
+
4
+ module Skyfall
5
+ class Firehose < Stream
6
+ SUBSCRIBE_REPOS = "com.atproto.sync.subscribeRepos"
7
+ SUBSCRIBE_LABELS = "com.atproto.label.subscribeLabels"
8
+
9
+ NAMED_ENDPOINTS = {
10
+ :subscribe_repos => SUBSCRIBE_REPOS,
11
+ :subscribe_labels => SUBSCRIBE_LABELS
12
+ }
13
+
14
+ attr_accessor :cursor
15
+
16
+ def self.new(server, endpoint, cursor = nil)
17
+ # to be removed in 0.6
18
+ instance = self.allocate
19
+ instance.send(:initialize, server, endpoint, cursor)
20
+ instance
21
+ end
22
+
23
+ def initialize(server, endpoint, cursor = nil)
24
+ require_relative 'firehose/message'
25
+ super(server)
26
+
27
+ @endpoint = check_endpoint(endpoint)
28
+ @cursor = check_cursor(cursor)
29
+ @root_url = @root_url.chomp('/')
30
+
31
+ if URI(@root_url).path != ''
32
+ raise ArgumentError, "Server parameter should not include any path"
33
+ end
34
+ end
35
+
36
+ def handle_message(msg)
37
+ data = msg.data.pack('C*')
38
+ @handlers[:raw_message]&.call(data)
39
+
40
+ if @handlers[:message]
41
+ atp_message = Message.new(data)
42
+ @cursor = atp_message.seq
43
+ @handlers[:message].call(atp_message)
44
+ else
45
+ @cursor = nil
46
+ end
47
+ end
48
+
49
+
50
+ private
51
+
52
+ def build_websocket_url
53
+ @root_url + "/xrpc/" + @endpoint + (@cursor ? "?cursor=#{@cursor}" : "")
54
+ end
55
+
56
+ def check_cursor(cursor)
57
+ if cursor.nil?
58
+ nil
59
+ elsif cursor.is_a?(Integer) || cursor.is_a?(String) && cursor =~ /^[0-9]+$/
60
+ cursor.to_i
61
+ else
62
+ raise ArgumentError, "Invalid cursor: #{cursor.inspect} - cursor must be an integer number"
63
+ end
64
+ end
65
+
66
+ def check_endpoint(endpoint)
67
+ if endpoint.is_a?(String)
68
+ raise ArgumentError.new("Invalid endpoint name: #{endpoint}") if endpoint.strip == '' || !endpoint.include?('.')
69
+ elsif endpoint.is_a?(Symbol)
70
+ raise ArgumentError.new("Unknown endpoint: #{endpoint}") if NAMED_ENDPOINTS[endpoint].nil?
71
+ endpoint = NAMED_ENDPOINTS[endpoint]
72
+ else
73
+ raise ArgumentError, "Endpoint should be a string or a symbol"
74
+ end
75
+
76
+ endpoint
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,19 @@
1
+ require_relative '../errors'
2
+ require_relative '../jetstream'
3
+
4
+ module Skyfall
5
+ class Jetstream::AccountMessage < Jetstream::Message
6
+ def initialize(json)
7
+ raise DecodeError.new("Missing event details") if json['account'].nil?
8
+ super
9
+ end
10
+
11
+ def active?
12
+ @json['account']['active']
13
+ end
14
+
15
+ def status
16
+ @json['account']['status']&.to_sym
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ require_relative '../errors'
2
+ require_relative '../jetstream'
3
+ require_relative 'operation'
4
+
5
+ module Skyfall
6
+ class Jetstream::CommitMessage < Jetstream::Message
7
+ def initialize(json)
8
+ raise DecodeError.new("Missing event details") if json['commit'].nil?
9
+ super
10
+ end
11
+
12
+ def operations
13
+ @operations ||= [Jetstream::Operation.new(self, json['commit'])]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ require_relative '../errors'
2
+ require_relative '../jetstream'
3
+
4
+ module Skyfall
5
+ class Jetstream::IdentityMessage < Jetstream::Message
6
+ def initialize(json)
7
+ raise DecodeError.new("Missing event details") if json['identity'].nil?
8
+ super
9
+ end
10
+
11
+ def handle
12
+ @json['identity']['handle']
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ require_relative '../errors'
2
+ require_relative '../jetstream'
3
+
4
+ require 'time'
5
+
6
+ module Skyfall
7
+ class Jetstream::Message
8
+ require_relative 'account_message'
9
+ require_relative 'commit_message'
10
+ require_relative 'identity_message'
11
+ require_relative 'unknown_message'
12
+
13
+ attr_reader :did, :type, :time_us
14
+ alias repo did
15
+ alias seq time_us
16
+
17
+ # :nodoc: - consider this as semi-private API
18
+ attr_reader :json
19
+
20
+ def self.new(data)
21
+ json = JSON.parse(data)
22
+
23
+ message_class = case json['kind']
24
+ when 'account' then Jetstream::AccountMessage
25
+ when 'commit' then Jetstream::CommitMessage
26
+ when 'identity' then Jetstream::IdentityMessage
27
+ else Jetstream::UnknownMessage
28
+ end
29
+
30
+ message = message_class.allocate
31
+ message.send(:initialize, json)
32
+ message
33
+ end
34
+
35
+ def initialize(json)
36
+ @json = json
37
+ @type = @json['kind'].to_sym
38
+ @did = @json['did']
39
+ @time_us = @json['time_us']
40
+ end
41
+
42
+ def operations
43
+ []
44
+ end
45
+
46
+ def time
47
+ @time ||= @json['time_us'] && Time.at(@json['time_us'] / 1_000_000.0)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,58 @@
1
+ require_relative '../collection'
2
+ require_relative '../jetstream'
3
+
4
+ module Skyfall
5
+ class Jetstream::Operation
6
+ def initialize(message, json)
7
+ @message = message
8
+ @json = json
9
+ end
10
+
11
+ def repo
12
+ @message.repo
13
+ end
14
+
15
+ alias did repo
16
+
17
+ def path
18
+ @json['collection'] + '/' + @json['rkey']
19
+ end
20
+
21
+ def action
22
+ @json['operation'].to_sym
23
+ end
24
+
25
+ def collection
26
+ @json['collection']
27
+ end
28
+
29
+ def rkey
30
+ @json['rkey']
31
+ end
32
+
33
+ def uri
34
+ "at://#{repo}/#{collection}/#{rkey}"
35
+ end
36
+
37
+ def cid
38
+ @cid ||= @json['cid'] && CID.from_json(@json['cid'])
39
+ end
40
+
41
+ def raw_record
42
+ @json['record']
43
+ end
44
+
45
+ def type
46
+ Collection.short_code(collection)
47
+ end
48
+
49
+ def inspectable_variables
50
+ instance_variables - [:@message]
51
+ end
52
+
53
+ def inspect
54
+ vars = inspectable_variables.map { |v| "#{v}=#{instance_variable_get(v).inspect}" }.join(", ")
55
+ "#<#{self.class}:0x#{object_id} #{vars}>"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,6 @@
1
+ require_relative '../jetstream'
2
+
3
+ module Skyfall
4
+ class Jetstream::UnknownMessage < Jetstream::Message
5
+ end
6
+ end
@@ -0,0 +1,121 @@
1
+ require_relative 'stream'
2
+
3
+ require 'json'
4
+ require 'time'
5
+ require 'uri'
6
+
7
+ module Skyfall
8
+ class Jetstream < Stream
9
+ def self.new(server, params = {})
10
+ # to be removed in 0.6
11
+ instance = self.allocate
12
+ instance.send(:initialize, server, params)
13
+ instance
14
+ end
15
+
16
+ attr_accessor :cursor
17
+
18
+ def initialize(server, params = {})
19
+ require_relative 'jetstream/message'
20
+ super(server)
21
+
22
+ @root_url = @root_url.chomp('/')
23
+
24
+ if URI(@root_url).path != ''
25
+ raise ArgumentError, "Server parameter should not include any path"
26
+ end
27
+
28
+ @params = check_params(params)
29
+ @cursor = @params.delete(:cursor)
30
+ end
31
+
32
+ def handle_message(msg)
33
+ data = msg.data
34
+ @handlers[:raw_message]&.call(data)
35
+
36
+ if @handlers[:message]
37
+ jet_message = Message.new(data)
38
+ @cursor = jet_message.time_us
39
+ @handlers[:message].call(jet_message)
40
+ else
41
+ @cursor = nil
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def build_websocket_url
48
+ params = @cursor ? @params.merge(cursor: @cursor) : @params
49
+ query = URI.encode_www_form(params)
50
+
51
+ @root_url + "/subscribe" + (query.length > 0 ? "?#{query}" : '')
52
+ end
53
+
54
+ def check_params(params)
55
+ params ||= {}
56
+ processed = {}
57
+
58
+ raise ArgumentError.new("Params should be a hash") unless params.is_a?(Hash)
59
+
60
+ params.each do |k, v|
61
+ next if v.nil?
62
+
63
+ if k.is_a?(Symbol)
64
+ k = k.to_s
65
+ elsif !k.is_a?(String)
66
+ raise ArgumentError.new("Invalid params key: #{k.inspect}")
67
+ end
68
+
69
+ k = k.gsub(/_([a-zA-Z])/) { $1.upcase }.to_sym
70
+ processed[k] = check_option(k, v)
71
+ end
72
+
73
+ processed
74
+ end
75
+
76
+ def check_option(k, v)
77
+ case k
78
+ when :wantedCollections
79
+ check_wanted_collections(v)
80
+ when :wantedDids
81
+ check_wanted_dids(v)
82
+ when :cursor
83
+ check_cursor(v)
84
+ when :compress, :requireHello
85
+ raise ArgumentError.new("Skyfall::Jetstream doesn't support the #{k.inspect} option yet")
86
+ else
87
+ raise ArgumentError.new("Unknown option: #{k.inspect}")
88
+ end
89
+ end
90
+
91
+ def check_wanted_collections(list)
92
+ list = [list] unless list.is_a?(Array)
93
+
94
+ list.map do |c|
95
+ if c.is_a?(String)
96
+ # TODO: more validation
97
+ c
98
+ elsif c.is_a?(Symbol)
99
+ Collection.from_short_code(c) or raise ArgumentError.new("Unknown collection symbol: #{c.inspect}")
100
+ else
101
+ raise ArgumentError.new("Invalid collection argument: #{c.inspect}")
102
+ end
103
+ end
104
+ end
105
+
106
+ def check_wanted_dids(list)
107
+ list = [list] unless list.is_a?(Array)
108
+
109
+ if x = list.detect { |c| !c.is_a?(String) || c !~ /\Adid:[a-z]+:/ }
110
+ raise ArgumentError.new("Invalid DID argument: #{x.inspect}")
111
+ end
112
+
113
+ # TODO: more validation
114
+ list
115
+ end
116
+
117
+ def check_cursor(cursor)
118
+ cursor.to_i
119
+ end
120
+ end
121
+ end
@@ -1,30 +1,30 @@
1
- require_relative 'messages/websocket_message'
2
-
3
1
  require 'eventmachine'
4
2
  require 'faye/websocket'
5
3
  require 'uri'
6
4
 
7
5
  module Skyfall
8
6
  class Stream
9
- SUBSCRIBE_REPOS = "com.atproto.sync.subscribeRepos"
10
- SUBSCRIBE_LABELS = "com.atproto.label.subscribeLabels"
11
-
12
- NAMED_ENDPOINTS = {
13
- :subscribe_repos => SUBSCRIBE_REPOS,
14
- :subscribe_labels => SUBSCRIBE_LABELS
15
- }
16
-
17
7
  EVENTS = %w(message raw_message connecting connect disconnect reconnect error timeout)
18
-
19
8
  MAX_RECONNECT_INTERVAL = 300
20
9
 
21
- attr_accessor :cursor, :auto_reconnect, :last_update, :user_agent
10
+ attr_accessor :auto_reconnect, :last_update, :user_agent
22
11
  attr_accessor :heartbeat_timeout, :heartbeat_interval, :check_heartbeat
23
12
 
24
- def initialize(server, endpoint, cursor = nil)
25
- @endpoint = check_endpoint(endpoint)
26
- @root_url = build_root_url(server)
27
- @cursor = check_cursor(cursor)
13
+ def self.new(server, endpoint = nil, cursor = nil)
14
+ # to be removed in 0.6
15
+ if endpoint || cursor
16
+ STDERR.puts "Warning: Skyfall::Stream has been renamed to Skyfall::Firehose. This initializer will be removed in the next version."
17
+ Firehose.new(server, endpoint, cursor)
18
+ else
19
+ instance = self.allocate
20
+ instance.send(:initialize, server)
21
+ instance
22
+ end
23
+ end
24
+
25
+ def initialize(service)
26
+ @root_url = build_root_url(service)
27
+
28
28
  @handlers = {}
29
29
  @auto_reconnect = true
30
30
  @check_heartbeat = false
@@ -65,17 +65,7 @@ module Skyfall
65
65
  @reconnecting = false
66
66
  @connection_attempts = 0
67
67
  @last_update = Time.now
68
-
69
- data = msg.data.pack('C*')
70
- @handlers[:raw_message]&.call(data)
71
-
72
- if @handlers[:message]
73
- atp_message = Skyfall::WebsocketMessage.new(data)
74
- @cursor = atp_message.seq
75
- @handlers[:message].call(atp_message)
76
- else
77
- @cursor = nil
78
- end
68
+ handle_message(msg)
79
69
  end
80
70
 
81
71
  @ws.on(:error) do |e|
@@ -103,6 +93,11 @@ module Skyfall
103
93
  end
104
94
  end
105
95
 
96
+ def handle_message(msg)
97
+ data = msg.data
98
+ @handlers[:raw_message]&.call(data)
99
+ end
100
+
106
101
  def reconnect
107
102
  @reconnecting = true
108
103
  @connection_attempts = 0
@@ -121,6 +116,10 @@ module Skyfall
121
116
  alias close disconnect
122
117
 
123
118
  def default_user_agent
119
+ version_string
120
+ end
121
+
122
+ def version_string
124
123
  "Skyfall/#{Skyfall::VERSION}"
125
124
  end
126
125
 
@@ -185,43 +184,24 @@ module Skyfall
185
184
  end
186
185
 
187
186
  def build_websocket_url
188
- @root_url + "/xrpc/" + @endpoint + (@cursor ? "?cursor=#{@cursor}" : "")
189
- end
190
-
191
- def check_cursor(cursor)
192
- if cursor.nil?
193
- nil
194
- elsif cursor.is_a?(Integer) || cursor.is_a?(String) && cursor =~ /^[0-9]+$/
195
- cursor.to_i
196
- else
197
- raise ArgumentError, "Invalid cursor: #{cursor.inspect} - cursor must be an integer number"
198
- end
187
+ @root_url
199
188
  end
200
189
 
201
- def check_endpoint(endpoint)
202
- if endpoint.is_a?(String)
203
- raise ArgumentError.new("Invalid endpoint name: #{endpoint}") if endpoint.strip == '' || !endpoint.include?('.')
204
- elsif endpoint.is_a?(Symbol)
205
- raise ArgumentError.new("Unknown endpoint: #{endpoint}") if NAMED_ENDPOINTS[endpoint].nil?
206
- endpoint = NAMED_ENDPOINTS[endpoint]
207
- else
208
- raise ArgumentError, "Endpoint should be a string or a symbol"
209
- end
210
-
211
- endpoint
212
- end
213
-
214
- def build_root_url(server)
215
- if server.is_a?(String)
216
- if server.start_with?('ws://') || server.start_with?('wss://')
217
- server
218
- elsif server.strip.empty? || server.include?('/')
219
- raise ArgumentError, "Server parameter should be a hostname or a ws:// or wss:// URL"
190
+ def build_root_url(service)
191
+ if service.is_a?(String)
192
+ if service.include?('/')
193
+ uri = URI(service)
194
+ if uri.scheme != 'ws' && uri.scheme != 'wss'
195
+ raise ArgumentError, "Service parameter should be a hostname or a ws:// or wss:// URL"
196
+ end
197
+ uri.to_s
220
198
  else
221
- "wss://#{server}"
199
+ service = "wss://#{service}"
200
+ uri = URI(service) # raises if invalid
201
+ service
222
202
  end
223
203
  else
224
- raise ArgumentError, "Server parameter should be a string"
204
+ raise ArgumentError, "Service parameter should be a string"
225
205
  end
226
206
  end
227
207
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Skyfall
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/skyfall.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'skyfall/stream'
4
- require_relative 'skyfall/messages/websocket_message'
3
+ require_relative 'skyfall/firehose'
4
+ require_relative 'skyfall/firehose/message'
5
+ require_relative 'skyfall/jetstream'
6
+ require_relative 'skyfall/jetstream/message'
5
7
  require_relative 'skyfall/version'
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.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kuba Suder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-23 00:00:00.000000000 Z
11
+ date: 2024-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base32
@@ -114,8 +114,7 @@ files:
114
114
  - LICENSE.txt
115
115
  - README.md
116
116
  - example/block_tracker.rb
117
- - example/follower_tracker.rb
118
- - example/monitor_phrases.rb
117
+ - example/jet_monitor_phrases.rb
119
118
  - example/print_all_posts.rb
120
119
  - example/push_notifications.rb
121
120
  - lib/skyfall.rb
@@ -124,17 +123,25 @@ files:
124
123
  - lib/skyfall/collection.rb
125
124
  - lib/skyfall/errors.rb
126
125
  - lib/skyfall/extensions.rb
126
+ - lib/skyfall/firehose.rb
127
+ - lib/skyfall/firehose/account_message.rb
128
+ - lib/skyfall/firehose/commit_message.rb
129
+ - lib/skyfall/firehose/handle_message.rb
130
+ - lib/skyfall/firehose/identity_message.rb
131
+ - lib/skyfall/firehose/info_message.rb
132
+ - lib/skyfall/firehose/labels_message.rb
133
+ - lib/skyfall/firehose/message.rb
134
+ - lib/skyfall/firehose/operation.rb
135
+ - lib/skyfall/firehose/tombstone_message.rb
136
+ - lib/skyfall/firehose/unknown_message.rb
137
+ - lib/skyfall/jetstream.rb
138
+ - lib/skyfall/jetstream/account_message.rb
139
+ - lib/skyfall/jetstream/commit_message.rb
140
+ - lib/skyfall/jetstream/identity_message.rb
141
+ - lib/skyfall/jetstream/message.rb
142
+ - lib/skyfall/jetstream/operation.rb
143
+ - lib/skyfall/jetstream/unknown_message.rb
127
144
  - lib/skyfall/label.rb
128
- - lib/skyfall/messages/account_message.rb
129
- - lib/skyfall/messages/commit_message.rb
130
- - lib/skyfall/messages/handle_message.rb
131
- - lib/skyfall/messages/identity_message.rb
132
- - lib/skyfall/messages/info_message.rb
133
- - lib/skyfall/messages/labels_message.rb
134
- - lib/skyfall/messages/tombstone_message.rb
135
- - lib/skyfall/messages/unknown_message.rb
136
- - lib/skyfall/messages/websocket_message.rb
137
- - lib/skyfall/operation.rb
138
145
  - lib/skyfall/stream.rb
139
146
  - lib/skyfall/version.rb
140
147
  - sig/skyfall.rbs