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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -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 +44 -14
  9. data/lib/skyfall/faye_ext.rb +48 -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} +19 -11
  17. data/lib/skyfall/firehose/operation.rb +58 -0
  18. data/lib/skyfall/firehose/sync_message.rb +9 -0
  19. data/lib/skyfall/firehose/tombstone_message.rb +11 -0
  20. data/lib/skyfall/firehose/unknown_message.rb +6 -0
  21. data/lib/skyfall/firehose.rb +79 -0
  22. data/lib/skyfall/jetstream/account_message.rb +19 -0
  23. data/lib/skyfall/jetstream/commit_message.rb +16 -0
  24. data/lib/skyfall/jetstream/identity_message.rb +15 -0
  25. data/lib/skyfall/jetstream/message.rb +54 -0
  26. data/lib/skyfall/jetstream/operation.rb +58 -0
  27. data/lib/skyfall/jetstream/unknown_message.rb +6 -0
  28. data/lib/skyfall/jetstream.rb +121 -0
  29. data/lib/skyfall/stream.rb +45 -59
  30. data/lib/skyfall/version.rb +1 -1
  31. data/lib/skyfall.rb +4 -2
  32. metadata +24 -18
  33. data/example/follower_tracker.rb +0 -84
  34. data/lib/skyfall/messages/handle_message.rb +0 -12
  35. data/lib/skyfall/messages/identity_message.rb +0 -7
  36. data/lib/skyfall/messages/tombstone_message.rb +0 -9
  37. data/lib/skyfall/messages/unknown_message.rb +0 -4
  38. 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 WebsocketMessage
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' then AccountMessage
30
- when '#commit' then CommitMessage
31
- when '#handle' then HandleMessage
32
- when '#identity' then IdentityMessage
33
- when '#info' then InfoMessage
34
- when '#labels' then LabelsMessage
35
- when '#tombstone' then TombstoneMessage
36
- else UnknownMessage
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,9 @@
1
+ require_relative '../firehose'
2
+
3
+ module Skyfall
4
+ class Firehose::SyncMessage < Firehose::Message
5
+ def rev
6
+ @rev ||= @data_object['rev']
7
+ end
8
+ end
9
+ 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,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,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,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 :cursor, :auto_reconnect, :last_update, :user_agent
12
+ attr_accessor :auto_reconnect, :last_update, :user_agent
22
13
  attr_accessor :heartbeat_timeout, :heartbeat_interval, :check_heartbeat
23
14
 
24
- def initialize(server, endpoint, cursor = nil)
25
- @endpoint = check_endpoint(endpoint)
26
- @root_url = build_root_url(server)
27
- @cursor = check_cursor(cursor)
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 = Faye::WebSocket::Client.new(url, nil, { headers: { 'User-Agent' => user_agent }})
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 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
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 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
192
+ def build_websocket_url
193
+ @root_url
212
194
  end
213
195
 
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"
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://#{server}"
205
+ service = "wss://#{service}"
206
+ uri = URI(service) # raises if invalid
207
+ service
222
208
  end
223
209
  else
224
- raise ArgumentError, "Server parameter should be a string"
210
+ raise ArgumentError, "Service parameter should be a string"
225
211
  end
226
212
  end
227
213
  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.1"
5
5
  end