kosmonaut 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/NEWS CHANGED
@@ -1,6 +1,30 @@
1
1
  Releases
2
2
  ========
3
3
 
4
+ v0.3.1
5
+ ------
6
+ * Documentation.
7
+ * Listener doesn't try to reconnect when unauthenticated.
8
+
9
+ v0.3.0
10
+ ------
11
+ * Kosmonaut::Client#request_single_access token gets 2 arguments now - uid and
12
+ permission - according to new spec and implementation of WebRocket.
13
+
14
+ v0.2.4
15
+ ------
16
+ * Handled broken pipe error.
17
+ * Timeouts switched to raw socket options.
18
+
19
+ v0.2.3
20
+ ------
21
+ * Worker's listener tweaks and optimization.
22
+
23
+ v0.2.2
24
+ ------
25
+ * Optimized timeouts.
26
+ * Fixed bug in opening new channel.
27
+
4
28
  v0.2.1
5
29
  ------
6
30
  * Fixed behaviour of the worker's listener.
@@ -8,4 +32,4 @@ v0.2.1
8
32
  v0.2.0
9
33
  ------
10
34
  * Pure ruby implementation of the client and worker using majordomo pattern.
11
- * Tests for the API
35
+ * Tests for the API
data/README CHANGED
@@ -85,7 +85,7 @@ or email one of the maintainers.
85
85
  Sponsors
86
86
  --------
87
87
  All the work on the project is sponsored and supported by Cubox - an
88
- awesome dev shop from Uruguay <http://cuboxsa.com>.
88
+ awesome dev shop from Uruguay <http://cuboxlabs.com>.
89
89
 
90
90
  Copyright
91
91
  ---------
data/Rakefile CHANGED
@@ -1,14 +1,12 @@
1
1
  # -*- ruby -*-
2
2
 
3
- =begin
4
- require 'rdoc/task'
5
- Rake::RDocTask.new do |rdoc|
6
- rdoc.rdoc_dir = 'rdoc'
7
- rdoc.title = "Kosmonaut - The WebRocket backend client"
8
- rdoc.rdoc_files.include('README*')
9
- rdoc.rdoc_files.include('lib/**/*.rb')
10
- end
11
- =end
3
+ #require 'rdoc/task'
4
+ #Rake::RDocTask.new do |rdoc|
5
+ # rdoc.rdoc_dir = 'rdoc'
6
+ # rdoc.title = "Kosmonaut - The WebRocket backend client"
7
+ # rdoc.rdoc_files.include('README*')
8
+ # rdoc.rdoc_files.include('lib/**/*.rb')
9
+ #end
12
10
 
13
11
  require 'rake/testtask'
14
12
  Rake::TestTask.new do |t|
@@ -1,3 +1,13 @@
1
+ # Copyright (C) 2012 Krzysztof Kowalik <chris@nu7hat.ch> and folks at Cubox
2
+ #
3
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
9
+ # SOFTWARE.
10
+
1
11
  require 'kosmonaut/errors'
2
12
  require 'kosmonaut/socket'
3
13
  require 'kosmonaut/worker'
@@ -1,25 +1,45 @@
1
+ # Copyright (C) 2012 Krzysztof Kowalik <chris@nu7hat.ch> and folks at Cubox
2
+ #
3
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
9
+ # SOFTWARE.
10
+
1
11
  require 'json'
2
12
  require 'thread'
3
13
 
4
14
  module Kosmonaut
15
+ # Public: Client is an implementation REQ-REP type socket which handles
16
+ # communication between backend application and WebRocket backend endpoint.
17
+ #
18
+ # Client is used to synchronously request operations from the server.
19
+ # Synchronous operations are used to provide consistency for the backed
20
+ # generated events.
21
+ #
22
+ # Examples
23
+ #
24
+ # c = Kosmonaut::Client.new("wr://token@127.0.0.1:8081/vhost")
25
+ # c.open_channel("comments")
26
+ #
27
+ # @comment = User.new(params[:comment])
28
+ #
29
+ # if @comment.save
30
+ # c.broadcast("comments", "comment_added", @comment.to_json)
31
+ # # ...
32
+ # end
33
+ #
5
34
  class Client < Socket
6
35
  # Maximum number of seconds to wait for the request to being processed.
7
36
  REQUEST_TIMEOUT = 5.0
8
37
 
9
38
  # Public: The Client constructor. Pre-configures the client instance. See
10
- # also the Kosmonaut::Socket#initialize for the details.
39
+ # also the Kosmonaut::Socket#initialize to get more information.
11
40
  #
12
41
  # url - The WebRocket backend endpoint URL to connect to.
13
42
  #
14
- # The endpoint's URL must have the following format:
15
- #
16
- # [scheme]://[secret]@[host]:[port]/[vhost]
17
- #
18
- # Examples
19
- #
20
- # c = Kosmonaut::Client.new("wr://f343...fa4a@myhost.com:8080/hello")
21
- # c.broadcast("room", "status", {"message" => "is going to the beach!"})
22
- #
23
43
  def initialize(url)
24
44
  super(url)
25
45
  @mtx = Mutex.new
@@ -38,32 +58,81 @@ module Kosmonaut
38
58
  # c.broadcast("room". "message", {"content" => "Hello World!"})
39
59
  # c.broadcast("room". "status", {"message" => "is saying hello!"})
40
60
  #
61
+ # Returns 0 if succeed.
62
+ # Raises one of the Kosmonaut::Error inherited exceptions.
41
63
  def broadcast(channel, event, data)
42
64
  payload = ["BC", channel, event, data.to_json]
43
65
  perform_request(payload)
44
66
  end
45
-
67
+
68
+ # Public: Opens specified channel. If channel already exists, then ok
69
+ # response will be received anyway. If channel name is starts with the
70
+ # `presence-` or `private-` prefix, then appropriate type of the channel
71
+ # will be created.
72
+ #
73
+ # name - A name of the channel to be created.
74
+ #
75
+ # Examples
76
+ #
77
+ # c.open_channel("room")
78
+ # c.open_channel("presence-room")
79
+ # c.open_channel("private-room")
80
+ #
81
+ # Returns 0 if succeed.
82
+ # Raises one of the Kosmonaut::Error inherited exceptions.
46
83
  def open_channel(name)
47
84
  payload = ["OC", name]
48
85
  perform_request(payload)
49
86
  end
50
87
 
88
+ # Public: Closes specified channel. If channel doesn't exist then an
89
+ # error will be thrown.
90
+ #
91
+ # name - A name of the channel to be deleted.
92
+ #
93
+ # Examples
94
+ #
95
+ # c.close_channel("hello")
96
+ # c.close_channel("presence-room")
97
+ #
98
+ # Returns 0 if succeed.
99
+ # Raises one of the Kosmonaut::Error inherited exceptions.
51
100
  def close_channel(name)
52
101
  payload = ["CC", name]
53
102
  perform_request(payload)
54
103
  end
55
104
 
105
+ # Public: Sends a request to generate a single access token for given
106
+ # user with specified permissions.
107
+ #
108
+ # uid - An user defined unique ID.
109
+ # permission - A permissions regexp to match against the channels.
110
+ #
111
+ # Examples
112
+ #
113
+ # @current_user = User.find(params[:id])
114
+ # c.request_single_access_token(@current_user.username, ".*")
115
+ #
116
+ #
117
+ # Returns generated access token string if succeed.
118
+ # Raises one of the Kosmonaut::Error inherited exceptions.
56
119
  def request_single_access_token(uid, permission)
57
120
  payload = ["AT", uid, permission]
58
121
  perform_request(payload)
59
122
  end
60
123
 
124
+ private
125
+
126
+ # Internal: Returns abbreviation of the socket type.
61
127
  def socket_type
62
128
  "req"
63
129
  end
64
130
 
65
- private
66
-
131
+ # Internal: Performs request with specified payload and waits for the
132
+ # response with it's result.
133
+ #
134
+ # Returns response result if succeed.
135
+ # Raises one of the Kosmonaut::Error inherited exceptions.
67
136
  def perform_request(payload)
68
137
  @mtx.synchronize {
69
138
  response = []
@@ -77,6 +146,18 @@ module Kosmonaut
77
146
  }
78
147
  end
79
148
 
149
+ # Internal: Parses given response and discovers it's result according
150
+ # to the WebRocket Backend Protocol specification.
151
+ #
152
+ # Response format
153
+ #
154
+ # 0x01 | command \n |
155
+ # 0x02 | payload... \n | *
156
+ # 0x.. | ... \n | *
157
+ # | \r\n\r\n |
158
+ #
159
+ # Returns response result if succeed.
160
+ # Raises one of the Kosmonaut::Error inherited exceptions.
80
161
  def parse_response(response)
81
162
  cmd = response[0].to_s
82
163
  Kosmonaut.log("Client/RES : #{response.join("\n").inspect}")
@@ -1,3 +1,13 @@
1
+ # Copyright (C) 2012 Krzysztof Kowalik <chris@nu7hat.ch> and folks at Cubox
2
+ #
3
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
9
+ # SOFTWARE.
10
+
1
11
  module Kosmonaut
2
12
  class Error < StandardError
3
13
  end
@@ -1,33 +1,77 @@
1
+ # Copyright (C) 2012 Krzysztof Kowalik <chris@nu7hat.ch> and folks at Cubox
2
+ #
3
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
9
+ # SOFTWARE.
10
+
1
11
  require 'uri'
2
12
  require 'socket'
3
13
  require 'securerandom'
4
14
 
5
15
  module Kosmonaut
16
+ # Internal: Socket is a base class defining tools and helpers used by
17
+ # Client and Worker implementations.
6
18
  class Socket
19
+ # Public: A parsed URL of the WebRocket backend endpoint.
7
20
  attr_reader :uri
8
21
 
22
+ # Internal: The Socket constructor.
23
+ #
24
+ # The endpoint's URL must have the following format:
25
+ #
26
+ # [scheme]://[secret]@[host]:[port]/[vhost]
27
+ #
9
28
  def initialize(url)
10
29
  @uri = URI.parse(url)
11
30
  @addr = ::Socket.getaddrinfo(@uri.host, nil)
12
31
  end
13
32
 
33
+ protected
34
+
35
+ # Internal: Connect creates new connection with the backend endpoint.
36
+ #
37
+ # timeout - A value of the maximum execution time (float).
38
+ #
39
+ # Returns configured and connected socket instance.
14
40
  def connect(timeout)
15
- secs = timeout.to_i
16
- usecs = ((timeout - secs) * 1_000_000).to_i
41
+ secs = timeout.to_i
42
+ usecs = ((timeout - secs) * 1_000_000).to_i
17
43
  optval = [secs, usecs].pack("l_2")
18
44
 
45
+ # Raw timeouts are way way way faster than Timeout module or SystemTimer
46
+ # and doesn't need external dependencies.
19
47
  s = ::Socket.new(::Socket.const_get(@addr[0][0]), ::Socket::SOCK_STREAM, 0)
20
48
  s.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
21
49
  s.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_RCVTIMEO, optval)
22
50
  s.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_SNDTIMEO, optval)
23
51
  s.connect(::Socket.pack_sockaddr_in(@uri.port, @addr[0][3]))
24
52
 
25
- generate_identity
53
+ generate_identity!
26
54
  return s
27
55
  end
28
56
 
29
- protected
30
-
57
+ # Internal: Pack converts given payload into single packet in format
58
+ # defined by WebRocket Backend Protocol.
59
+ #
60
+ # Packet format
61
+ #
62
+ # 0x01 | identity \n | *
63
+ # 0x02 | \n | *
64
+ # 0x03 | command \n |
65
+ # 0x04 | payload... \n | *
66
+ # 0x.. | ... \n | *
67
+ # | \r\n\r\n |
68
+ #
69
+ # * - optional field
70
+ #
71
+ # payload - The data to be packed.
72
+ # with_identity - Whether identity should be prepend to the packet.
73
+ #
74
+ # Returns packed data.
31
75
  def pack(payload=[], with_identity=true)
32
76
  if with_identity
33
77
  payload.unshift("")
@@ -36,11 +80,16 @@ module Kosmonaut
36
80
  payload.join("\n") + "\n\r\n\r\n"
37
81
  end
38
82
 
39
- def recv(s)
83
+ # Internal: Reads one packet from given socket instance.
84
+ #
85
+ # sock - The socket to receive from.
86
+ #
87
+ # Returns received data (frames) as an array of strings.
88
+ def recv(sock)
40
89
  data = []
41
90
  possible_eom = false # possible end of message
42
- while !s.eof?
43
- line = s.gets
91
+ while !sock.eof?
92
+ line = sock.gets
44
93
  if line == "\r\n"
45
94
  break if possible_eom
46
95
  possible_eom = true
@@ -54,13 +103,13 @@ module Kosmonaut
54
103
 
55
104
  private
56
105
 
57
- def generate_identity
58
- parts = []
59
- parts << socket_type
60
- parts << @uri.path
61
- parts << @uri.user # secret
62
- parts << SecureRandom.uuid
63
- @identity = parts.join(":")
106
+ # Internal: Generates unique identity for the socket connection.
107
+ # Identity is composed from the following parts:
108
+ #
109
+ # [socket-type]:[vhost]:[vhost-token]:[uuid]
110
+ #
111
+ def generate_identity!
112
+ @identity = [socket_type, @uri.path, @uri.user, SecureRandom.uuid].join(":")
64
113
  end
65
114
  end
66
115
  end
@@ -1,8 +1,18 @@
1
+ # Copyright (C) 2012 Krzysztof Kowalik <chris@nu7hat.ch> and folks at Cubox
2
+ #
3
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
9
+ # SOFTWARE.
10
+
1
11
  module Kosmonaut
2
12
  module Version
3
13
  MAJOR = 0
4
14
  MINOR = 3
5
- PATCH = 0
15
+ PATCH = 1
6
16
 
7
17
  def self.to_s
8
18
  [MAJOR, MINOR, PATCH].join('.')
@@ -1,11 +1,62 @@
1
+ # Copyright (C) 2012 Krzysztof Kowalik <chris@nu7hat.ch> and folks at Cubox
2
+ #
3
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
9
+ # SOFTWARE.
10
+
1
11
  require 'json'
2
12
  require 'thread'
3
13
 
4
14
  module Kosmonaut
15
+ # Public: Worker is an implementation of SUBSCRIBER socket which handles
16
+ # events incoming from the WebRocket backend endpoint.
17
+ #
18
+ # The communication here is asynchronous, and Worker can't send other
19
+ # messages than ready state, heartbeat, or quit notification.
20
+ #
21
+ # Worker shouldn't be called directly, it should be used as a base class
22
+ # for implementing your own workers.
23
+ #
24
+ # Examples
25
+ #
26
+ # class MyWorker < Kosmonaut::Worker
27
+ # def on_message(event, data)
28
+ # if event == "append_chat_history"
29
+ # @room = Room.find(data[:room_id])
30
+ # @room.messages.build(data[:message])
31
+ # @room.save!
32
+ # end
33
+ # end
34
+ #
35
+ # def on_error(err)
36
+ # puts "WEBROCKET ERROR: #{err.to_s}"
37
+ # end
38
+ #
39
+ # def on_exception(err)
40
+ # puts "INTERNAL ERROR: #{err.to_s}"
41
+ # end
42
+ # end
43
+ #
44
+ # w = MyWorker.new("wr://token@127.0.0.1:8081/vhost")
45
+ # w.listen
46
+ #
5
47
  class Worker < Socket
6
- RECONNECT_DELAY = 1000 # in milliseconds
7
- HEARTBEAT_INTERVAL = 500 # in milliseconds
48
+ # Number of milliseconds after which client should retry to reconnect
49
+ # to the bakcend endpoint.
50
+ RECONNECT_DELAY = 1000
8
51
 
52
+ # Number of milliseconds between next heartbeat message.
53
+ HEARTBEAT_INTERVAL = 500
54
+
55
+ # Public: The Worker constructor. Pre-configures the worker instance. See
56
+ # also the Kosmonaut::Socket#initialize to get more information.
57
+ #
58
+ # url - The WebRocket backend endpoint URL to connect to.
59
+ #
9
60
  def initialize(url)
10
61
  super(url)
11
62
  @mtx = Mutex.new
@@ -16,6 +67,10 @@ module Kosmonaut
16
67
  @heartbeat_at = 0
17
68
  end
18
69
 
70
+ # Public: Listen starts a listener's loop for the worker. Listener implements
71
+ # the Majordomo pattern to manage connection with the backend.
72
+ #
73
+ # Raises Kosmonaut::UnauthorizedError if worker's credentials are invalid.
19
74
  def listen
20
75
  @alive = true
21
76
  reconnect
@@ -31,7 +86,7 @@ module Kosmonaut
31
86
  end
32
87
 
33
88
  msg = recv(@sock)
34
- raise Errno::ECONNRESET if @sock.eof? || msg.empty?
89
+ raise Errno::ECONNRESET if msg.empty?
35
90
  Kosmonaut.log("Worker/RECV : #{msg.join("\n").inspect}")
36
91
  cmd = msg.shift
37
92
 
@@ -46,6 +101,8 @@ module Kosmonaut
46
101
  when "ER"
47
102
  error_handler(msg.size < 1 ? 597 : msg[0])
48
103
  end
104
+
105
+ raise Errno::ECONNRESET if @sock.eof?
49
106
  rescue Errno::EAGAIN, Errno::ECONNRESET, Errno::ECONNREFUSED, IOError => err
50
107
  Kosmonaut.log("Worker/RECONNECT: " + err.to_s)
51
108
  sleep(@reconnect_delay.to_f / 1000.0)
@@ -59,33 +116,49 @@ module Kosmonaut
59
116
  end
60
117
  end
61
118
 
119
+ # Public: Breaks the listener's loop and stops execution of
120
+ # the worker.
62
121
  def stop
63
122
  @mtx.synchronize { @alive = false }
64
123
  end
65
124
 
125
+ # Public: Returns whether this worker's event loop is running.
66
126
  def alive?
67
127
  @mtx.synchronize { @alive }
68
128
  end
69
129
 
130
+ private
131
+
132
+ # Internal: Returns abbreviation of the socket type.
70
133
  def socket_type
71
134
  "dlr"
72
135
  end
73
-
74
- private
75
-
76
- def send(s, payload, with_identity=false)
77
- return unless s
136
+
137
+ # Internal: Packs given payload and writes it to the specified socket.
138
+ #
139
+ # sock - The socket to write to.
140
+ # payload - The payload to be packed and sent.
141
+ # with_identity - Whether identity should be prepend to the packet.
142
+ #
143
+ def send(sock, payload, with_identity=false)
144
+ return unless sock
78
145
  packet = pack(payload, with_identity)
79
- s.write(packet)
146
+ sock.write(packet)
80
147
  Kosmonaut.log("Worker/SENT : #{packet.inspect}")
148
+ nil
81
149
  rescue Errno::EPIPE
82
150
  end
83
-
151
+
152
+ # Internal: Disconnects and cleans up the socket if connected.
84
153
  def disconnect
85
- @sock.close if @sock
154
+ @sock.close if @sock
155
+ @sock = nil
86
156
  rescue IOError
87
157
  end
88
-
158
+
159
+ # Internal: Sets up new connection with the backend endpoint and sends
160
+ # information that it's ready to work. Also initializes heartbeat
161
+ # scheduling.
89
162
  def reconnect
90
163
  @sock = connect(((@heartbeat_ivl * 2).to_f / 1000.0).to_i + 1)
91
164
  send(@sock, ["RD"], true)
@@ -93,6 +166,11 @@ module Kosmonaut
93
166
  rescue Errno::ECONNREFUSED
94
167
  end
95
168
 
169
+ # Intenral: Message handler routes received data to user defined
170
+ # 'on_message' method (if exists) and handles it's exceptions.
171
+ #
172
+ # data - The data to be handled.
173
+ #
96
174
  def message_handler(data)
97
175
  if respond_to?(:on_message)
98
176
  payload = JSON.parse(data.to_s)
@@ -102,15 +180,30 @@ module Kosmonaut
102
180
  exception_handler(err)
103
181
  end
104
182
 
183
+ # Internal: Handles given WebRocket error.
184
+ #
185
+ # errcode - A code of the received error.
186
+ #
187
+ # Raises Kosmonaut::UnauthorizerError if error 402 has been received.
105
188
  def error_handler(errcode)
106
189
  if respond_to?(:on_error)
107
190
  err = ERRORS[errcode.to_i]
108
- on_error(err ? err : UnknownServerError)
191
+ if err == UnauthorizedError
192
+ raise err.new
193
+ end
194
+ begin
195
+ on_error((err ? err : UnknownServerError).new)
196
+ rescue => err
197
+ exception_handler(err)
198
+ end
109
199
  end
110
- rescue => err
111
- exception_handler(err)
112
200
  end
113
201
 
202
+ # Internal: Exception handler passes given error to user defined
203
+ # exception handler or raises error if such not exists.
204
+ #
205
+ # err - The exception to be handled.
206
+ #
114
207
  def exception_handler(err)
115
208
  if respond_to?(:on_exception)
116
209
  on_exception(err)
@@ -2,15 +2,15 @@ require File.expand_path("../helper", __FILE__)
2
2
 
3
3
  class MyWorker < Kosmonaut::Worker
4
4
  def on_message(event, data)
5
- puts "MSG", event, data
5
+ puts "MSG : #{event} : #{data.inspect}"
6
6
  end
7
7
 
8
8
  def on_error(err)
9
- puts "ERR", err.to_s
9
+ puts "ERR : #{err.to_s}"
10
10
  end
11
11
 
12
12
  def on_exception(err)
13
- puts "EXC", err.to_s
13
+ puts "EXC : #{err.to_s}"
14
14
  end
15
15
  end
16
16
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: kosmonaut
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.0
5
+ version: 0.3.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Krzysztof Kowalik
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2012-01-24 00:00:00 Z
14
+ date: 2012-01-28 00:00:00 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: json
@@ -44,12 +44,12 @@ extensions: []
44
44
  extra_rdoc_files: []
45
45
 
46
46
  files:
47
- - lib/kosmonaut.rb
47
+ - lib/kosmonaut/client.rb
48
+ - lib/kosmonaut/errors.rb
48
49
  - lib/kosmonaut/socket.rb
49
- - lib/kosmonaut/worker.rb
50
50
  - lib/kosmonaut/version.rb
51
- - lib/kosmonaut/errors.rb
52
- - lib/kosmonaut/client.rb
51
+ - lib/kosmonaut/worker.rb
52
+ - lib/kosmonaut.rb
53
53
  - test/helper.rb
54
54
  - test/test_kosmonaut_client.rb
55
55
  - test/test_kosmonaut_worker.rb
@@ -82,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
82
  requirements: []
83
83
 
84
84
  rubyforge_project:
85
- rubygems_version: 1.8.15
85
+ rubygems_version: 1.8.10
86
86
  signing_key:
87
87
  specification_version: 3
88
88
  summary: Ruby client for the WebRocket backend