skyfall 0.4.1 → 0.5.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 +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +182 -29
- data/example/block_tracker.rb +1 -1
- data/example/{monitor_phrases.rb → jet_monitor_phrases.rb} +3 -2
- data/example/print_all_posts.rb +1 -1
- data/example/push_notifications.rb +1 -1
- data/lib/skyfall/collection.rb +44 -14
- data/lib/skyfall/faye_ext.rb +48 -0
- data/lib/skyfall/{messages → firehose}/account_message.rb +3 -1
- data/lib/skyfall/{messages → firehose}/commit_message.rb +9 -3
- data/lib/skyfall/firehose/handle_message.rb +14 -0
- data/lib/skyfall/firehose/identity_message.rb +9 -0
- data/lib/skyfall/{messages → firehose}/info_message.rb +3 -1
- data/lib/skyfall/{messages → firehose}/labels_message.rb +2 -2
- data/lib/skyfall/{messages/websocket_message.rb → firehose/message.rb} +19 -11
- data/lib/skyfall/firehose/operation.rb +58 -0
- data/lib/skyfall/firehose/sync_message.rb +9 -0
- data/lib/skyfall/firehose/tombstone_message.rb +11 -0
- data/lib/skyfall/firehose/unknown_message.rb +6 -0
- data/lib/skyfall/firehose.rb +79 -0
- data/lib/skyfall/jetstream/account_message.rb +19 -0
- data/lib/skyfall/jetstream/commit_message.rb +16 -0
- data/lib/skyfall/jetstream/identity_message.rb +15 -0
- data/lib/skyfall/jetstream/message.rb +54 -0
- data/lib/skyfall/jetstream/operation.rb +58 -0
- data/lib/skyfall/jetstream/unknown_message.rb +6 -0
- data/lib/skyfall/jetstream.rb +121 -0
- data/lib/skyfall/stream.rb +45 -59
- data/lib/skyfall/version.rb +1 -1
- data/lib/skyfall.rb +4 -2
- metadata +24 -18
- data/example/follower_tracker.rb +0 -84
- data/lib/skyfall/messages/handle_message.rb +0 -12
- data/lib/skyfall/messages/identity_message.rb +0 -7
- data/lib/skyfall/messages/tombstone_message.rb +0 -9
- data/lib/skyfall/messages/unknown_message.rb +0 -4
- data/lib/skyfall/operation.rb +0 -74
@@ -1,11 +1,12 @@
|
|
1
1
|
require_relative '../errors'
|
2
2
|
require_relative '../extensions'
|
3
|
+
require_relative '../firehose'
|
3
4
|
|
4
5
|
require 'cbor'
|
5
6
|
require 'time'
|
6
7
|
|
7
8
|
module Skyfall
|
8
|
-
class
|
9
|
+
class Firehose::Message
|
9
10
|
using Skyfall::Extensions
|
10
11
|
|
11
12
|
require_relative 'account_message'
|
@@ -14,26 +15,29 @@ module Skyfall
|
|
14
15
|
require_relative 'identity_message'
|
15
16
|
require_relative 'info_message'
|
16
17
|
require_relative 'labels_message'
|
18
|
+
require_relative 'sync_message'
|
17
19
|
require_relative 'tombstone_message'
|
18
20
|
require_relative 'unknown_message'
|
19
21
|
|
20
|
-
attr_reader :type_object, :data_object
|
21
22
|
attr_reader :type, :did, :seq
|
22
|
-
|
23
23
|
alias repo did
|
24
24
|
|
25
|
+
# :nodoc: - consider this as semi-private API
|
26
|
+
attr_reader :type_object, :data_object
|
27
|
+
|
25
28
|
def self.new(data)
|
26
29
|
type_object, data_object = decode_cbor_objects(data)
|
27
30
|
|
28
31
|
message_class = case type_object['t']
|
29
|
-
when '#account'
|
30
|
-
when '#commit'
|
31
|
-
when '#handle'
|
32
|
-
when '#identity'
|
33
|
-
when '#info'
|
34
|
-
when '#labels'
|
35
|
-
when '#
|
36
|
-
|
32
|
+
when '#account' then Firehose::AccountMessage
|
33
|
+
when '#commit' then Firehose::CommitMessage
|
34
|
+
when '#handle' then Firehose::HandleMessage
|
35
|
+
when '#identity' then Firehose::IdentityMessage
|
36
|
+
when '#info' then Firehose::InfoMessage
|
37
|
+
when '#labels' then Firehose::LabelsMessage
|
38
|
+
when '#sync' then Firehose::SyncMessage
|
39
|
+
when '#tombstone' then Firehose::TombstoneMessage
|
40
|
+
else Firehose::UnknownMessage
|
37
41
|
end
|
38
42
|
|
39
43
|
message = message_class.allocate
|
@@ -54,6 +58,10 @@ module Skyfall
|
|
54
58
|
[]
|
55
59
|
end
|
56
60
|
|
61
|
+
def unknown?
|
62
|
+
self.is_a?(Firehose::UnknownMessage)
|
63
|
+
end
|
64
|
+
|
57
65
|
def time
|
58
66
|
@time ||= @data_object['time'] && Time.parse(@data_object['time'])
|
59
67
|
end
|
@@ -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,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,54 @@
|
|
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 unknown?
|
43
|
+
self.is_a?(Jetstream::UnknownMessage)
|
44
|
+
end
|
45
|
+
|
46
|
+
def operations
|
47
|
+
[]
|
48
|
+
end
|
49
|
+
|
50
|
+
def time
|
51
|
+
@time ||= @json['time_us'] && Time.at(@json['time_us'] / 1_000_000.0)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
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,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
|
data/lib/skyfall/stream.rb
CHANGED
@@ -1,30 +1,32 @@
|
|
1
|
-
require_relative 'messages/websocket_message'
|
2
|
-
|
3
1
|
require 'eventmachine'
|
4
2
|
require 'faye/websocket'
|
5
3
|
require 'uri'
|
6
4
|
|
5
|
+
require_relative 'version'
|
6
|
+
|
7
7
|
module Skyfall
|
8
8
|
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
9
|
EVENTS = %w(message raw_message connecting connect disconnect reconnect error timeout)
|
18
|
-
|
19
10
|
MAX_RECONNECT_INTERVAL = 300
|
20
11
|
|
21
|
-
attr_accessor :
|
12
|
+
attr_accessor :auto_reconnect, :last_update, :user_agent
|
22
13
|
attr_accessor :heartbeat_timeout, :heartbeat_interval, :check_heartbeat
|
23
14
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
15
|
+
def self.new(server, endpoint = nil, cursor = nil)
|
16
|
+
# to be removed in 0.6
|
17
|
+
if endpoint || cursor
|
18
|
+
STDERR.puts "Warning: Skyfall::Stream has been renamed to Skyfall::Firehose. This initializer will be removed in the next version."
|
19
|
+
Firehose.new(server, endpoint, cursor)
|
20
|
+
else
|
21
|
+
instance = self.allocate
|
22
|
+
instance.send(:initialize, server)
|
23
|
+
instance
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(service)
|
28
|
+
@root_url = build_root_url(service)
|
29
|
+
|
28
30
|
@handlers = {}
|
29
31
|
@auto_reconnect = true
|
30
32
|
@check_heartbeat = false
|
@@ -53,7 +55,7 @@ module Skyfall
|
|
53
55
|
@handlers[:error]&.call(e)
|
54
56
|
end
|
55
57
|
|
56
|
-
@ws =
|
58
|
+
@ws = build_websocket_client(url)
|
57
59
|
|
58
60
|
@ws.on(:open) do |e|
|
59
61
|
@handlers[:connect]&.call
|
@@ -65,17 +67,7 @@ module Skyfall
|
|
65
67
|
@reconnecting = false
|
66
68
|
@connection_attempts = 0
|
67
69
|
@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
|
70
|
+
handle_message(msg)
|
79
71
|
end
|
80
72
|
|
81
73
|
@ws.on(:error) do |e|
|
@@ -103,6 +95,11 @@ module Skyfall
|
|
103
95
|
end
|
104
96
|
end
|
105
97
|
|
98
|
+
def handle_message(msg)
|
99
|
+
data = msg.data
|
100
|
+
@handlers[:raw_message]&.call(data)
|
101
|
+
end
|
102
|
+
|
106
103
|
def reconnect
|
107
104
|
@reconnecting = true
|
108
105
|
@connection_attempts = 0
|
@@ -121,6 +118,10 @@ module Skyfall
|
|
121
118
|
alias close disconnect
|
122
119
|
|
123
120
|
def default_user_agent
|
121
|
+
version_string
|
122
|
+
end
|
123
|
+
|
124
|
+
def version_string
|
124
125
|
"Skyfall/#{Skyfall::VERSION}"
|
125
126
|
end
|
126
127
|
|
@@ -184,44 +185,29 @@ module Skyfall
|
|
184
185
|
end
|
185
186
|
end
|
186
187
|
|
187
|
-
def
|
188
|
-
|
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
|
188
|
+
def build_websocket_client(url)
|
189
|
+
Faye::WebSocket::Client.new(url, nil, { headers: { 'User-Agent' => user_agent }})
|
199
190
|
end
|
200
191
|
|
201
|
-
def
|
202
|
-
|
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
|
192
|
+
def build_websocket_url
|
193
|
+
@root_url
|
212
194
|
end
|
213
195
|
|
214
|
-
def build_root_url(
|
215
|
-
if
|
216
|
-
if
|
217
|
-
|
218
|
-
|
219
|
-
|
196
|
+
def build_root_url(service)
|
197
|
+
if service.is_a?(String)
|
198
|
+
if service.include?('/')
|
199
|
+
uri = URI(service)
|
200
|
+
if uri.scheme != 'ws' && uri.scheme != 'wss'
|
201
|
+
raise ArgumentError, "Service parameter should be a hostname or a ws:// or wss:// URL"
|
202
|
+
end
|
203
|
+
uri.to_s
|
220
204
|
else
|
221
|
-
"wss://#{
|
205
|
+
service = "wss://#{service}"
|
206
|
+
uri = URI(service) # raises if invalid
|
207
|
+
service
|
222
208
|
end
|
223
209
|
else
|
224
|
-
raise ArgumentError, "
|
210
|
+
raise ArgumentError, "Service parameter should be a string"
|
225
211
|
end
|
226
212
|
end
|
227
213
|
end
|
data/lib/skyfall/version.rb
CHANGED