skyfall 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/LICENSE.txt +1 -1
- data/README.md +32 -2
- data/example/follower_tracker.rb +84 -0
- data/lib/skyfall/collection.rb +16 -12
- data/lib/skyfall/messages/account_message.rb +11 -0
- data/lib/skyfall/messages/handle_message.rb +5 -0
- data/lib/skyfall/messages/identity_message.rb +3 -0
- data/lib/skyfall/messages/tombstone_message.rb +5 -0
- data/lib/skyfall/messages/websocket_message.rb +2 -0
- data/lib/skyfall/operation.rb +15 -12
- data/lib/skyfall/stream.rb +47 -3
- data/lib/skyfall/version.rb +1 -1
- metadata +18 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db537537fcd4e38f184c6cdea3f51ba1b8554848d4c3cd1de20f63ca2d956fc2
|
4
|
+
data.tar.gz: 34c51f6c8c0152589562bf0a3b3c5246cd8a1e95664f1128c86bd17c6a313d59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11477293a1bc0377ef5d9eaa68cc2d374f76ac4d942006572e8b9e1668cb8f54a582abdeda81b65c1d72f6452ba2cad1153c403027ba5d7efbfa093624713105
|
7
|
+
data.tar.gz: 8d86b1f71a4fd5fa7f01077fefe8d8e292dc6b5007b79ee4d1ed1343f887c4104c0480b297e7ce4be61db0cce65211a568b642411fa5c3e7f62c4c91a4fe0f7b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.4.0] - 2024-09-23
|
2
|
+
|
3
|
+
- (re)added a "hearbeat" feature (removed earlier in 0.2.0) to fix the occasional issue when the websocket stops receiving data, but doesn't disconnect (not enabled by default, turn it on by setting `check_heartbeat` to true)
|
4
|
+
- added a way to set the user agent sent when connecting using the `user_agent` field (default is `"Skyfall/#{version}"`)
|
5
|
+
- added `app.bsky.feed.postgate` record type
|
6
|
+
|
7
|
+
## [0.3.1] - 2024-06-28
|
8
|
+
|
9
|
+
- added `app.bsky.graph.starterpack` and `chat.bsky.actor.declaration` record types
|
10
|
+
- added `#account` event type (`AccountMessage`)
|
11
|
+
- added `handle` field to `IdentityMessage`
|
12
|
+
- fixed param validation on `Stream` initialization
|
13
|
+
- reverted the change that added Ruby stdlib dependencies explicitly to the gemspec, since this causes more problems than it's worth - only `base64` is left there, since it's the one now required to be listed
|
14
|
+
|
1
15
|
## [0.3.0] - 2024-03-21
|
2
16
|
|
3
17
|
- added support for labeller firehose, served by labeller services at the `com.atproto.label.subscribeLabels` endpoint (aliased as `:subscribe_labels`)
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# Skyfall
|
2
2
|
|
3
|
-
|
3
|
+
A Ruby gem for streaming data from the Bluesky/AtProto firehose 🦋
|
4
|
+
|
5
|
+
> [!NOTE]
|
6
|
+
> ATProto Ruby gems collection: [skyfall](https://github.com/mackuba/skyfall) | [blue_factory](https://github.com/mackuba/blue_factory) | [minisky](https://github.com/mackuba/minisky) | [didkit](https://github.com/mackuba/didkit)
|
4
7
|
|
5
8
|
|
6
9
|
## What does it do
|
@@ -120,9 +123,36 @@ When Skyfall receives a message about a record type that's not on the list, whet
|
|
120
123
|
Do not however check if such operations have a `type` equal to `:unknown` first - just ignore the type and only check the `collection` string. The reason is that some next version of Skyfall might start recognizing those records and add a new `type` value for them like e.g. `:skygram_photo`, and then they won't match your condition anymore.
|
121
124
|
|
122
125
|
|
126
|
+
## Configuration
|
127
|
+
|
128
|
+
### User agent
|
129
|
+
|
130
|
+
`Skyfall::Stream` sends a user agent header when making a connection. This is set by default to `"Skyfall/0.x.y"`, but it's recommended that you override it using the `user_agent` field to something that identifies your app and its author – this will let the owner of the server you're connecting to know who to contact in case the client is causing some problems.
|
131
|
+
|
132
|
+
You can also append your user agent info to the default value like this:
|
133
|
+
|
134
|
+
```rb
|
135
|
+
sky.user_agent = "NewsBot (@news.bot) #{sky.default_user_agent}"
|
136
|
+
```
|
137
|
+
|
138
|
+
### Heartbeat and reconnecting
|
139
|
+
|
140
|
+
Occasionally, especially during times of very heavy traffic, the websocket can get into a stuck state where it stops receiving any data, but doesn't disconnect and just hangs like this forever. To work around this, there is a "heartbeat" feature which starts a background timer, which periodically checks how much time has passed since the last received event, and if the time exceeds a set limit, it manually disconnects and reconnects the stream.
|
141
|
+
|
142
|
+
The option is not enabled by default, because there are some firehoses which will not be sending events often, possibly only once in a while – e.g. labellers and independent PDS firehoses – and in this case we don't want any heartbeat since it will be completely normal not to have any events for a long time. It's not really possible to detect easily if we're connecting to a full network relay or one of those, so in order to avoid false alarms, you need to enable this manually using the `check_heartbeat` property.
|
143
|
+
|
144
|
+
You can also change the `heartbeat_interval`, i.e. how often the timer is triggered (default: 10s), and the `heartbeat_timeout`, i.e. the amount of time passed without events when it reconnects (default: 5 min):
|
145
|
+
|
146
|
+
```rb
|
147
|
+
sky.check_heartbeat = true
|
148
|
+
sky.heartbeat_interval = 5
|
149
|
+
sky.heartbeat_timeout = 120
|
150
|
+
```
|
151
|
+
|
152
|
+
|
123
153
|
## Credits
|
124
154
|
|
125
|
-
Copyright ©
|
155
|
+
Copyright © 2024 Kuba Suder ([@mackuba.eu](https://bsky.app/profile/mackuba.eu)).
|
126
156
|
|
127
157
|
The code is available under the terms of the [zlib license](https://choosealicense.com/licenses/zlib/) (permissive, similar to MIT).
|
128
158
|
|
@@ -0,0 +1,84 @@
|
|
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
|
data/lib/skyfall/collection.rb
CHANGED
@@ -1,16 +1,20 @@
|
|
1
1
|
module Skyfall
|
2
2
|
module Collection
|
3
|
-
BSKY_PROFILE
|
4
|
-
BSKY_FEED
|
5
|
-
BSKY_LIKE
|
6
|
-
BSKY_POST
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
BSKY_PROFILE = "app.bsky.actor.profile"
|
4
|
+
BSKY_FEED = "app.bsky.feed.generator"
|
5
|
+
BSKY_LIKE = "app.bsky.feed.like"
|
6
|
+
BSKY_POST = "app.bsky.feed.post"
|
7
|
+
BSKY_POSTGATE = "app.bsky.feed.postgate"
|
8
|
+
BSKY_REPOST = "app.bsky.feed.repost"
|
9
|
+
BSKY_THREADGATE = "app.bsky.feed.threadgate"
|
10
|
+
BSKY_BLOCK = "app.bsky.graph.block"
|
11
|
+
BSKY_FOLLOW = "app.bsky.graph.follow"
|
12
|
+
BSKY_LIST = "app.bsky.graph.list"
|
13
|
+
BSKY_LISTBLOCK = "app.bsky.graph.listblock"
|
14
|
+
BSKY_LISTITEM = "app.bsky.graph.listitem"
|
15
|
+
BSKY_STARTERPACK = "app.bsky.graph.starterpack"
|
16
|
+
BSKY_LABELER = "app.bsky.labeler.service"
|
17
|
+
|
18
|
+
BSKY_CHAT_DECLARATION = "chat.bsky.actor.declaration"
|
15
19
|
end
|
16
20
|
end
|
@@ -1,4 +1,9 @@
|
|
1
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
|
+
#
|
2
7
|
class HandleMessage < WebsocketMessage
|
3
8
|
def handle
|
4
9
|
@data_object['handle']
|
@@ -8,6 +8,7 @@ module Skyfall
|
|
8
8
|
class WebsocketMessage
|
9
9
|
using Skyfall::Extensions
|
10
10
|
|
11
|
+
require_relative 'account_message'
|
11
12
|
require_relative 'commit_message'
|
12
13
|
require_relative 'handle_message'
|
13
14
|
require_relative 'identity_message'
|
@@ -25,6 +26,7 @@ module Skyfall
|
|
25
26
|
type_object, data_object = decode_cbor_objects(data)
|
26
27
|
|
27
28
|
message_class = case type_object['t']
|
29
|
+
when '#account' then AccountMessage
|
28
30
|
when '#commit' then CommitMessage
|
29
31
|
when '#handle' then HandleMessage
|
30
32
|
when '#identity' then IdentityMessage
|
data/lib/skyfall/operation.rb
CHANGED
@@ -43,18 +43,21 @@ module Skyfall
|
|
43
43
|
|
44
44
|
def type
|
45
45
|
case collection
|
46
|
-
when Collection::BSKY_BLOCK
|
47
|
-
when Collection::BSKY_FEED
|
48
|
-
when Collection::BSKY_FOLLOW
|
49
|
-
when Collection::BSKY_LABELER
|
50
|
-
when Collection::BSKY_LIKE
|
51
|
-
when Collection::BSKY_LIST
|
52
|
-
when Collection::BSKY_LISTBLOCK
|
53
|
-
when Collection::BSKY_LISTITEM
|
54
|
-
when Collection::BSKY_POST
|
55
|
-
when Collection::
|
56
|
-
when Collection::
|
57
|
-
when Collection::
|
46
|
+
when Collection::BSKY_BLOCK then :bsky_block
|
47
|
+
when Collection::BSKY_FEED then :bsky_feed
|
48
|
+
when Collection::BSKY_FOLLOW then :bsky_follow
|
49
|
+
when Collection::BSKY_LABELER then :bsky_labeler
|
50
|
+
when Collection::BSKY_LIKE then :bsky_like
|
51
|
+
when Collection::BSKY_LIST then :bsky_list
|
52
|
+
when Collection::BSKY_LISTBLOCK then :bsky_listblock
|
53
|
+
when Collection::BSKY_LISTITEM then :bsky_listitem
|
54
|
+
when Collection::BSKY_POST then :bsky_post
|
55
|
+
when Collection::BSKY_POSTGATE then :bsky_postgate
|
56
|
+
when Collection::BSKY_PROFILE then :bsky_profile
|
57
|
+
when Collection::BSKY_REPOST then :bsky_repost
|
58
|
+
when Collection::BSKY_STARTERPACK then :bsky_starterpack
|
59
|
+
when Collection::BSKY_THREADGATE then :bsky_threadgate
|
60
|
+
when Collection::BSKY_CHAT_DECLARATION then :bsky_chat_declaration
|
58
61
|
else :unknown
|
59
62
|
end
|
60
63
|
end
|
data/lib/skyfall/stream.rb
CHANGED
@@ -14,11 +14,12 @@ module Skyfall
|
|
14
14
|
:subscribe_labels => SUBSCRIBE_LABELS
|
15
15
|
}
|
16
16
|
|
17
|
-
EVENTS = %w(message raw_message connecting connect disconnect reconnect error)
|
17
|
+
EVENTS = %w(message raw_message connecting connect disconnect reconnect error timeout)
|
18
18
|
|
19
19
|
MAX_RECONNECT_INTERVAL = 300
|
20
20
|
|
21
|
-
attr_accessor :
|
21
|
+
attr_accessor :cursor, :auto_reconnect, :last_update, :user_agent
|
22
|
+
attr_accessor :heartbeat_timeout, :heartbeat_interval, :check_heartbeat
|
22
23
|
|
23
24
|
def initialize(server, endpoint, cursor = nil)
|
24
25
|
@endpoint = check_endpoint(endpoint)
|
@@ -26,7 +27,12 @@ module Skyfall
|
|
26
27
|
@cursor = check_cursor(cursor)
|
27
28
|
@handlers = {}
|
28
29
|
@auto_reconnect = true
|
30
|
+
@check_heartbeat = false
|
29
31
|
@connection_attempts = 0
|
32
|
+
@heartbeat_interval = 10
|
33
|
+
@heartbeat_timeout = 300
|
34
|
+
@last_update = nil
|
35
|
+
@user_agent = default_user_agent
|
30
36
|
|
31
37
|
@handlers[:error] = proc { |e| puts "ERROR: #{e}" }
|
32
38
|
end
|
@@ -47,15 +53,18 @@ module Skyfall
|
|
47
53
|
@handlers[:error]&.call(e)
|
48
54
|
end
|
49
55
|
|
50
|
-
@ws = Faye::WebSocket::Client.new(url)
|
56
|
+
@ws = Faye::WebSocket::Client.new(url, nil, { headers: { 'User-Agent' => user_agent }})
|
51
57
|
|
52
58
|
@ws.on(:open) do |e|
|
53
59
|
@handlers[:connect]&.call
|
60
|
+
@last_update = Time.now
|
61
|
+
start_heartbeat_timer
|
54
62
|
end
|
55
63
|
|
56
64
|
@ws.on(:message) do |msg|
|
57
65
|
@reconnecting = false
|
58
66
|
@connection_attempts = 0
|
67
|
+
@last_update = Time.now
|
59
68
|
|
60
69
|
data = msg.data.pack('C*')
|
61
70
|
@handlers[:raw_message]&.call(data)
|
@@ -85,6 +94,7 @@ module Skyfall
|
|
85
94
|
connect
|
86
95
|
end
|
87
96
|
else
|
97
|
+
stop_heartbeat_timer
|
88
98
|
@engines_on = false
|
89
99
|
@handlers[:disconnect]&.call
|
90
100
|
EM.stop_event_loop unless @ws
|
@@ -110,6 +120,40 @@ module Skyfall
|
|
110
120
|
|
111
121
|
alias close disconnect
|
112
122
|
|
123
|
+
def default_user_agent
|
124
|
+
"Skyfall/#{Skyfall::VERSION}"
|
125
|
+
end
|
126
|
+
|
127
|
+
def check_heartbeat=(value)
|
128
|
+
@check_heartbeat = value
|
129
|
+
|
130
|
+
if @check_heartbeat && @engines_on && @ws && !@heartbeat_timer
|
131
|
+
start_heartbeat_timer
|
132
|
+
elsif !@check_heartbeat && @heartbeat_timer
|
133
|
+
stop_heartbeat_timer
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def start_heartbeat_timer
|
138
|
+
return if !@check_heartbeat || @heartbeat_interval.to_f <= 0 || @heartbeat_timeout.to_f <= 0
|
139
|
+
return if @heartbeat_timer
|
140
|
+
|
141
|
+
@heartbeat_timer = EM::PeriodicTimer.new(@heartbeat_interval) do
|
142
|
+
next if @ws.nil? || @heartbeat_timeout.to_f <= 0
|
143
|
+
time_passed = Time.now - @last_update
|
144
|
+
|
145
|
+
if time_passed > @heartbeat_timeout
|
146
|
+
@handlers[:timeout]&.call
|
147
|
+
reconnect
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def stop_heartbeat_timer
|
153
|
+
@heartbeat_timer&.cancel
|
154
|
+
@heartbeat_timer = nil
|
155
|
+
end
|
156
|
+
|
113
157
|
EVENTS.each do |event|
|
114
158
|
define_method "on_#{event}" do |&block|
|
115
159
|
@handlers[event.to_sym] = block
|
data/lib/skyfall/version.rb
CHANGED
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
|
+
version: 0.4.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-
|
11
|
+
date: 2024-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base32
|
@@ -30,6 +30,20 @@ dependencies:
|
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 0.3.4
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: base64
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.1'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0.1'
|
33
47
|
- !ruby/object:Gem::Dependency
|
34
48
|
name: cbor
|
35
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,62 +98,6 @@ dependencies:
|
|
84
98
|
- - "~>"
|
85
99
|
- !ruby/object:Gem::Version
|
86
100
|
version: '0.11'
|
87
|
-
- !ruby/object:Gem::Dependency
|
88
|
-
name: base64
|
89
|
-
requirement: !ruby/object:Gem::Requirement
|
90
|
-
requirements:
|
91
|
-
- - "~>"
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
version: '0.1'
|
94
|
-
type: :runtime
|
95
|
-
prerelease: false
|
96
|
-
version_requirements: !ruby/object:Gem::Requirement
|
97
|
-
requirements:
|
98
|
-
- - "~>"
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
version: '0.1'
|
101
|
-
- !ruby/object:Gem::Dependency
|
102
|
-
name: stringio
|
103
|
-
requirement: !ruby/object:Gem::Requirement
|
104
|
-
requirements:
|
105
|
-
- - "~>"
|
106
|
-
- !ruby/object:Gem::Version
|
107
|
-
version: '3.0'
|
108
|
-
type: :runtime
|
109
|
-
prerelease: false
|
110
|
-
version_requirements: !ruby/object:Gem::Requirement
|
111
|
-
requirements:
|
112
|
-
- - "~>"
|
113
|
-
- !ruby/object:Gem::Version
|
114
|
-
version: '3.0'
|
115
|
-
- !ruby/object:Gem::Dependency
|
116
|
-
name: time
|
117
|
-
requirement: !ruby/object:Gem::Requirement
|
118
|
-
requirements:
|
119
|
-
- - "~>"
|
120
|
-
- !ruby/object:Gem::Version
|
121
|
-
version: '0.3'
|
122
|
-
type: :runtime
|
123
|
-
prerelease: false
|
124
|
-
version_requirements: !ruby/object:Gem::Requirement
|
125
|
-
requirements:
|
126
|
-
- - "~>"
|
127
|
-
- !ruby/object:Gem::Version
|
128
|
-
version: '0.3'
|
129
|
-
- !ruby/object:Gem::Dependency
|
130
|
-
name: uri
|
131
|
-
requirement: !ruby/object:Gem::Requirement
|
132
|
-
requirements:
|
133
|
-
- - "~>"
|
134
|
-
- !ruby/object:Gem::Version
|
135
|
-
version: '0.13'
|
136
|
-
type: :runtime
|
137
|
-
prerelease: false
|
138
|
-
version_requirements: !ruby/object:Gem::Requirement
|
139
|
-
requirements:
|
140
|
-
- - "~>"
|
141
|
-
- !ruby/object:Gem::Version
|
142
|
-
version: '0.13'
|
143
101
|
description: "\n Skyfall is a Ruby library for connecting to the \"firehose\" of
|
144
102
|
the Bluesky social network, i.e. a websocket which\n streams all new posts and
|
145
103
|
everything else happening on the Bluesky network in real time. The code connects
|
@@ -156,6 +114,7 @@ files:
|
|
156
114
|
- LICENSE.txt
|
157
115
|
- README.md
|
158
116
|
- example/block_tracker.rb
|
117
|
+
- example/follower_tracker.rb
|
159
118
|
- example/monitor_phrases.rb
|
160
119
|
- example/print_all_posts.rb
|
161
120
|
- example/push_notifications.rb
|
@@ -166,6 +125,7 @@ files:
|
|
166
125
|
- lib/skyfall/errors.rb
|
167
126
|
- lib/skyfall/extensions.rb
|
168
127
|
- lib/skyfall/label.rb
|
128
|
+
- lib/skyfall/messages/account_message.rb
|
169
129
|
- lib/skyfall/messages/commit_message.rb
|
170
130
|
- lib/skyfall/messages/handle_message.rb
|
171
131
|
- lib/skyfall/messages/identity_message.rb
|