skyfall 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -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/collection.rb +26 -0
  9. data/lib/skyfall/{messages → firehose}/account_message.rb +3 -1
  10. data/lib/skyfall/{messages → firehose}/commit_message.rb +9 -3
  11. data/lib/skyfall/firehose/handle_message.rb +14 -0
  12. data/lib/skyfall/firehose/identity_message.rb +9 -0
  13. data/lib/skyfall/{messages → firehose}/info_message.rb +3 -1
  14. data/lib/skyfall/{messages → firehose}/labels_message.rb +2 -2
  15. data/lib/skyfall/{messages/websocket_message.rb → firehose/message.rb} +13 -11
  16. data/lib/skyfall/firehose/operation.rb +58 -0
  17. data/lib/skyfall/firehose/tombstone_message.rb +11 -0
  18. data/lib/skyfall/firehose/unknown_message.rb +6 -0
  19. data/lib/skyfall/firehose.rb +79 -0
  20. data/lib/skyfall/jetstream/account_message.rb +19 -0
  21. data/lib/skyfall/jetstream/commit_message.rb +16 -0
  22. data/lib/skyfall/jetstream/identity_message.rb +15 -0
  23. data/lib/skyfall/jetstream/message.rb +50 -0
  24. data/lib/skyfall/jetstream/operation.rb +58 -0
  25. data/lib/skyfall/jetstream/unknown_message.rb +6 -0
  26. data/lib/skyfall/jetstream.rb +121 -0
  27. data/lib/skyfall/stream.rb +39 -59
  28. data/lib/skyfall/version.rb +1 -1
  29. data/lib/skyfall.rb +4 -2
  30. metadata +21 -14
  31. data/example/follower_tracker.rb +0 -84
  32. data/lib/skyfall/messages/handle_message.rb +0 -12
  33. data/lib/skyfall/messages/identity_message.rb +0 -7
  34. data/lib/skyfall/messages/tombstone_message.rb +0 -9
  35. data/lib/skyfall/messages/unknown_message.rb +0 -4
  36. data/lib/skyfall/operation.rb +0 -74
@@ -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.1"
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.1
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-10-04 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
@@ -1,84 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Example: track when people follow and unfollow your account.
4
-
5
- # load skyfall from a local folder - you normally won't need this
6
- $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
7
-
8
- require 'json'
9
- require 'open-uri'
10
- require 'skyfall'
11
-
12
- $monitored_did = ARGV[0]
13
-
14
- if $monitored_did.to_s.empty?
15
- puts "Usage: #{$PROGRAM_NAME} <monitored_did>"
16
- exit 1
17
- elsif ARGV[0] !~ /^did:plc:[a-z0-9]{24}$/
18
- puts "Not a valid DID: #{$monitored_did}"
19
- exit 1
20
- end
21
-
22
- sky = Skyfall::Stream.new('bsky.network', :subscribe_repos)
23
-
24
- sky.on_connect { puts "Connected, monitoring #{$monitored_did}" }
25
- sky.on_disconnect { puts "Disconnected" }
26
- sky.on_reconnect { puts "Reconnecting..." }
27
- sky.on_error { |e| puts "ERROR: #{e}" }
28
-
29
- sky.on_message do |msg|
30
- # we're only interested in repo commit messages
31
- next if msg.type != :commit
32
-
33
- msg.operations.each do |op|
34
- next if op.action != :create
35
-
36
- begin
37
- case op.type
38
- when :bsky_block
39
- process_block(msg, op)
40
- when :bsky_listitem
41
- process_list_item(msg, op)
42
- end
43
- rescue StandardError => e
44
- puts "Error: #{e}"
45
- end
46
- end
47
- end
48
-
49
- def process_block(msg, op)
50
- if op.raw_record['subject'] == $monitored_did
51
- owner_handle = get_user_handle(op.repo)
52
- puts "@#{owner_handle} has blocked you! (#{msg.time.getlocal})"
53
- end
54
- end
55
-
56
- def process_list_item(msg, op)
57
- if op.raw_record['subject'] == $monitored_did
58
- owner_handle = get_user_handle(op.repo)
59
-
60
- list_uri = op.raw_record['list']
61
- list_name = get_list_name(list_uri)
62
-
63
- puts "@#{owner_handle} has added you to list \"#{list_name}\" (#{msg.time.getlocal})"
64
- end
65
- end
66
-
67
- def get_user_handle(did)
68
- url = "https://plc.directory/#{did}"
69
- json = JSON.parse(URI.open(url).read)
70
- json['alsoKnownAs'][0].gsub('at://', '')
71
- end
72
-
73
- def get_list_name(list_uri)
74
- repo, type, rkey = list_uri.gsub('at://', '').split('/')
75
- url = "https://bsky.social/xrpc/com.atproto.repo.getRecord?repo=#{repo}&collection=#{type}&rkey=#{rkey}"
76
-
77
- json = JSON.parse(URI.open(url).read)
78
- json['value']['name']
79
- end
80
-
81
- # close the connection cleanly on Ctrl+C
82
- trap("SIGINT") { sky.disconnect }
83
-
84
- sky.connect
@@ -1,12 +0,0 @@
1
- module Skyfall
2
-
3
- #
4
- # Note: this event type is deprecated and will stop being emitted at some point.
5
- # You should instead listen for 'identity' events (Skyfall::IdentityMessage).
6
- #
7
- class HandleMessage < WebsocketMessage
8
- def handle
9
- @data_object['handle']
10
- end
11
- end
12
- end