kosmonaut 0.2.0
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.
- data/COPYING +19 -0
- data/README +94 -0
- data/Rakefile +29 -0
- data/kosmonaut.gemspec +19 -0
- data/lib/kosmonaut.rb +16 -0
- data/lib/kosmonaut/client.rb +77 -0
- data/lib/kosmonaut/errors.rb +62 -0
- data/lib/kosmonaut/socket.rb +49 -0
- data/lib/kosmonaut/version.rb +15 -0
- data/lib/kosmonaut/worker.rb +128 -0
- data/test/helper.rb +5 -0
- data/test/test_kosmonaut_client.rb +55 -0
- data/test/test_kosmonaut_worker.rb +29 -0
- metadata +79 -0
data/COPYING
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2012 Krzysztof Kowalik <chris@nu7hat.ch> and folks at Cubox
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
Ruby wrapper for Kosmonaut - the WebRocket client
|
2
|
+
=================================================
|
3
|
+
|
4
|
+
Kosmonaut.rb is a ruby backend client for the WebRocket.
|
5
|
+
The idea of the Kosmonaut is to keep it simple, straightforward
|
6
|
+
and easy to maintain, although to allow to build more
|
7
|
+
sophisticated libraries at top of it.
|
8
|
+
|
9
|
+
Installation
|
10
|
+
------------
|
11
|
+
You can install it easily from rubygems:
|
12
|
+
|
13
|
+
$ gem install kosmonaut
|
14
|
+
|
15
|
+
Or using bundler, add this line to your gemfile:
|
16
|
+
|
17
|
+
gem 'kosmonaut'
|
18
|
+
|
19
|
+
Usage
|
20
|
+
-----
|
21
|
+
Kosmonaut has two components: Client and Worker. Client is
|
22
|
+
used to manage a WebRocket's vhost and broadcast messages,
|
23
|
+
for example:
|
24
|
+
|
25
|
+
c = Kosmonaut::Client.new("wr://token@127.0.0.1:8081/vhost")
|
26
|
+
c.open_channel("world")
|
27
|
+
c.broadcast("world", "hello", {:who => "Chris"})
|
28
|
+
c.broadcast("world", "bye", {:see_you_when => "Soon!"})
|
29
|
+
c.request_single_access_token(".*")
|
30
|
+
|
31
|
+
Worker is used to listen for incoming messages and handle
|
32
|
+
it in user's desired way, example:
|
33
|
+
|
34
|
+
class MyWorker < Kosmonaut::Worker
|
35
|
+
def on_message(event, data)
|
36
|
+
if event == "hello"
|
37
|
+
puts "Hello #{data[:who]}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_error(err)
|
42
|
+
puts "Error encountered (code #{err.to_s})"
|
43
|
+
end
|
44
|
+
|
45
|
+
def on_exception(err)
|
46
|
+
puts "Ouch! something went wrong! Error: #{err.to_s}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
w = MyWorker.new("wr://token@127.0.0.1:8081/vhost")
|
51
|
+
w.listen
|
52
|
+
|
53
|
+
Hacking
|
54
|
+
-------
|
55
|
+
If you want to run kosmonaut.rb in development mode, first clone
|
56
|
+
the repo and install dependencies:
|
57
|
+
|
58
|
+
$ git clone https://github.com/webrocket/kosmonaut.rb.git
|
59
|
+
$ cd kosmonaut.rb
|
60
|
+
$ bundle
|
61
|
+
|
62
|
+
To run the tests you should have a `webrocket-server` instance
|
63
|
+
running with a `/test` vhost created. To create it use the
|
64
|
+
`webrocket-admin` tool:
|
65
|
+
|
66
|
+
$ webrocket-admin add_vhost /test
|
67
|
+
Reading cookie... done
|
68
|
+
Adding a vhost... done
|
69
|
+
---
|
70
|
+
Access token for this vhost: a70d7d2c0bc5761620948b3420d18df9072ca0d1
|
71
|
+
|
72
|
+
Now get the access token and run kosmonaut's tests using
|
73
|
+
rake task:
|
74
|
+
|
75
|
+
$ VHOST_TOKEN=a70d7d2c0bc5761620948b3420d18df9072ca0d1 rake test
|
76
|
+
|
77
|
+
If you want to get debug output add a `DEBUG` environment variable
|
78
|
+
while running tests:
|
79
|
+
|
80
|
+
$ VHOST_TOKEN=... DEBUG=1 rake test
|
81
|
+
|
82
|
+
With any quirks and doubts don't hesitate to start a github issue
|
83
|
+
or email one of the maintainers.
|
84
|
+
|
85
|
+
Sponsors
|
86
|
+
--------
|
87
|
+
All the work on the project is sponsored and supported by Cubox - an
|
88
|
+
awesome dev shop from Uruguay <http://cuboxsa.com>.
|
89
|
+
|
90
|
+
Copyright
|
91
|
+
---------
|
92
|
+
Copyright (C) 2012 Krzysztof Kowalik <chris@nu7hat.ch> and folks at Cubox
|
93
|
+
|
94
|
+
Released under the MIT license. See COPYING for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- ruby -*-
|
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
|
12
|
+
|
13
|
+
require 'rake/testtask'
|
14
|
+
Rake::TestTask.new do |t|
|
15
|
+
t.libs << "test"
|
16
|
+
t.test_files = FileList['test/test*.rb']
|
17
|
+
t.verbose = true
|
18
|
+
end
|
19
|
+
|
20
|
+
task :default => :test
|
21
|
+
|
22
|
+
desc "Opens console with loaded mustang env."
|
23
|
+
task :console do
|
24
|
+
$LOAD_PATH.unshift("./lib")
|
25
|
+
require 'kosmonaut'
|
26
|
+
require 'irb'
|
27
|
+
ARGV.clear
|
28
|
+
IRB.start
|
29
|
+
end
|
data/kosmonaut.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "kosmonaut"
|
6
|
+
s.version = "0.2.0"
|
7
|
+
s.summary = "Ruby client for the WebRocket backend"
|
8
|
+
s.description = "The WebRocket server backend client for ruby programming language"
|
9
|
+
s.authors = ["Krzysztof Kowalik", "Cubox"]
|
10
|
+
s.email = "chris@nu7hat.ch"
|
11
|
+
s.homepage = "http://webrocket.io/"
|
12
|
+
s.license = "MIT"
|
13
|
+
|
14
|
+
s.files = Dir["{lib/**/*.rb,test/*.rb,Rakefile,README*,COPYING,*.gemspec}"]
|
15
|
+
s.test_files = Dir["test/*.rb"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
|
18
|
+
s.add_dependency "json", "~> 1.0"
|
19
|
+
end
|
data/lib/kosmonaut.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'kosmonaut/errors'
|
2
|
+
require 'kosmonaut/socket'
|
3
|
+
require 'kosmonaut/worker'
|
4
|
+
require 'kosmonaut/client'
|
5
|
+
require 'kosmonaut/version'
|
6
|
+
|
7
|
+
module Kosmonaut
|
8
|
+
extend self
|
9
|
+
attr_accessor :debug
|
10
|
+
|
11
|
+
def log(msg)
|
12
|
+
print("DEBUG: ", msg, "\n") if Kosmonaut.debug
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Kosmonaut.debug = false
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'uri'
|
3
|
+
require 'socket'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'timeout'
|
6
|
+
require 'thread'
|
7
|
+
|
8
|
+
module Kosmonaut
|
9
|
+
class Client < Socket
|
10
|
+
include Kosmonaut
|
11
|
+
|
12
|
+
REQUEST_TIMEOUT = 5 # in seconds
|
13
|
+
|
14
|
+
def initialize(url)
|
15
|
+
super(url)
|
16
|
+
@mtx = Mutex.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def broadcast(channel, event, data)
|
20
|
+
payload = ["BC", channel, event, data.to_json]
|
21
|
+
perform_request(payload)
|
22
|
+
end
|
23
|
+
|
24
|
+
def open_channel(name, type)
|
25
|
+
payload = ["OC", name, type]
|
26
|
+
perform_request(payload)
|
27
|
+
end
|
28
|
+
|
29
|
+
def close_channel(name)
|
30
|
+
payload = ["CC", name]
|
31
|
+
perform_request(payload)
|
32
|
+
end
|
33
|
+
|
34
|
+
def request_single_access_token(permission)
|
35
|
+
payload = ["AT", permission]
|
36
|
+
perform_request(payload)
|
37
|
+
end
|
38
|
+
|
39
|
+
def socket_type
|
40
|
+
"req"
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def perform_request(payload)
|
46
|
+
@mtx.synchronize {
|
47
|
+
response = []
|
48
|
+
Timeout.timeout(REQUEST_TIMEOUT) {
|
49
|
+
s = connect
|
50
|
+
packet = pack(payload)
|
51
|
+
log("Client/REQ : #{packet.inspect}")
|
52
|
+
s.write(packet)
|
53
|
+
response = recv(s)
|
54
|
+
s.close
|
55
|
+
}
|
56
|
+
parse_response(response)
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_response(response)
|
61
|
+
cmd = response[0].to_s
|
62
|
+
log("Client/RES : #{response.join("\n").inspect}")
|
63
|
+
case cmd
|
64
|
+
when "OK"
|
65
|
+
return 0
|
66
|
+
when "ER"
|
67
|
+
errcode = response[1].to_i
|
68
|
+
error = ERRORS[errcode]
|
69
|
+
raise error.new if error
|
70
|
+
when "AT"
|
71
|
+
token = response[1].to_s
|
72
|
+
return token if token.size == 128
|
73
|
+
end
|
74
|
+
raise UnknownServerError.new
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Kosmonaut
|
2
|
+
class Error < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class BadRequestError < Error
|
6
|
+
def initialize
|
7
|
+
super "400: Bad request"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class UnauthorizedError < Error
|
12
|
+
def initialize
|
13
|
+
super "402: Unauthorized"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ForbiddenError < Error
|
18
|
+
def initialize
|
19
|
+
super "403: Forbidden"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class InvalidChannelNameError < Error
|
24
|
+
def initialize
|
25
|
+
super "451: Invalid channel name"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class ChannelNotFoundError < Error
|
30
|
+
def initialize
|
31
|
+
super "454: Channel not found"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class InternalError < Error
|
36
|
+
def initialize
|
37
|
+
super "597: Internal error"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class EndOfFileError < Error
|
42
|
+
def initialize
|
43
|
+
super "598: End of file"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class UnknownServerError < Error
|
48
|
+
def initialize
|
49
|
+
super "Unknown server error"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
ERRORS = {
|
54
|
+
400 => BadRequestError,
|
55
|
+
402 => UnauthorizedError,
|
56
|
+
403 => ForbiddenError,
|
57
|
+
451 => InvalidChannelNameError,
|
58
|
+
454 => ChannelNotFoundError,
|
59
|
+
597 => InternalError,
|
60
|
+
598 => EndOfFileError,
|
61
|
+
}
|
62
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Kosmonaut
|
2
|
+
class Socket
|
3
|
+
attr_reader :uri
|
4
|
+
|
5
|
+
def initialize(url)
|
6
|
+
@uri = URI.parse(url)
|
7
|
+
generate_identity
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def connect
|
13
|
+
TCPSocket.open(@uri.host, @uri.port)
|
14
|
+
end
|
15
|
+
|
16
|
+
def pack(payload=[])
|
17
|
+
payload.unshift("")
|
18
|
+
payload.unshift(@identity)
|
19
|
+
payload.join("\n") + "\n\r\n\r\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
def recv(s)
|
23
|
+
data = []
|
24
|
+
possible_eom = false # possible end of message
|
25
|
+
while !s.eof?
|
26
|
+
line = s.gets
|
27
|
+
if line == "\r\n"
|
28
|
+
break if possible_eom
|
29
|
+
possible_eom = true
|
30
|
+
else
|
31
|
+
possible_eom = false
|
32
|
+
data << line.strip
|
33
|
+
end
|
34
|
+
end
|
35
|
+
data
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def generate_identity
|
41
|
+
parts = []
|
42
|
+
parts << socket_type
|
43
|
+
parts << @uri.path
|
44
|
+
parts << @uri.user # secret
|
45
|
+
parts << SecureRandom.uuid
|
46
|
+
@identity = parts.join(":")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Kosmonaut
|
5
|
+
class Worker < Socket
|
6
|
+
include Kosmonaut
|
7
|
+
|
8
|
+
RECONNECT_DELAY = 1000 # in milliseconds
|
9
|
+
HEARTBEAT_INTERVAL = 2000 # in milliseconds
|
10
|
+
LIVENESS = 3
|
11
|
+
|
12
|
+
def initialize(url)
|
13
|
+
super(url)
|
14
|
+
@mtx = Mutex.new
|
15
|
+
@sock = nil
|
16
|
+
@alive = false
|
17
|
+
@reconnect_delay = RECONNECT_DELAY
|
18
|
+
@heartbeat_ivl = HEARTBEAT_INTERVAL
|
19
|
+
@heartbeat_at = 0
|
20
|
+
@liveness = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def listen
|
24
|
+
reconnect
|
25
|
+
@alive = true
|
26
|
+
while true
|
27
|
+
if !alive?
|
28
|
+
send(@sock, ["QT"])
|
29
|
+
disconnect
|
30
|
+
break
|
31
|
+
end
|
32
|
+
begin
|
33
|
+
Timeout.timeout(((@heartbeat_ivl * 2).to_f / 1000.0).to_i + 1) {
|
34
|
+
msg = recv(@sock)
|
35
|
+
@liveness = LIVENESS
|
36
|
+
log("Worker/RECV : #{msg.join("\n").inspect}")
|
37
|
+
next if msg.size < 1
|
38
|
+
cmd = msg.shift
|
39
|
+
|
40
|
+
case cmd
|
41
|
+
when "HB"
|
42
|
+
# nothing to do...
|
43
|
+
when "QT"
|
44
|
+
reconnect
|
45
|
+
next
|
46
|
+
when "TR"
|
47
|
+
message_handler(msg[0])
|
48
|
+
when "ER"
|
49
|
+
error_handler(msg.size < 1 ? 597 : msg[0])
|
50
|
+
end
|
51
|
+
}
|
52
|
+
rescue Timeout::Error, Errno::ECONNRESET
|
53
|
+
if (@liveness -= 1) == 0
|
54
|
+
sleep(@reconnect_delay.to_f / 1000.0)
|
55
|
+
reconnect
|
56
|
+
end
|
57
|
+
end
|
58
|
+
if Time.now.to_f > @heartbeat_at
|
59
|
+
send(@sock, ["HB"])
|
60
|
+
@heartbeat_at = Time.now.to_f + (@heartbeat_ivl.to_f / 1000.0)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def stop
|
66
|
+
@mtx.synchronize { @alive = false }
|
67
|
+
end
|
68
|
+
|
69
|
+
def alive?
|
70
|
+
@mtx.synchronize { @alive }
|
71
|
+
end
|
72
|
+
|
73
|
+
def socket_type
|
74
|
+
"dlr"
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def send(s, payload)
|
80
|
+
packet = pack(payload)
|
81
|
+
@sock.write(packet)
|
82
|
+
log("Worker/SENT : #{packet.inspect}")
|
83
|
+
end
|
84
|
+
|
85
|
+
def disconnect
|
86
|
+
if @sock
|
87
|
+
@sock.close
|
88
|
+
@sock = nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def reconnect
|
93
|
+
disconnect
|
94
|
+
@sock = connect
|
95
|
+
@sock.write(pack(["RD"]))
|
96
|
+
@liveness = LIVENESS
|
97
|
+
@heartbeat_at = Time.now.to_f + (@heartbeat_ivl.to_f / 1000.0)
|
98
|
+
end
|
99
|
+
|
100
|
+
def message_handler(data)
|
101
|
+
if respond_to?(:on_message)
|
102
|
+
payload = JSON.parse(data.to_s)
|
103
|
+
event = payload.keys.first
|
104
|
+
data = data[event]
|
105
|
+
on_message(event, data)
|
106
|
+
end
|
107
|
+
rescue => err
|
108
|
+
exception_handler(err)
|
109
|
+
end
|
110
|
+
|
111
|
+
def error_handler(errcode)
|
112
|
+
if respond_to?(:on_error)
|
113
|
+
err = ERRORS[errcode.to_i]
|
114
|
+
on_error(err ? err : UnknownServerError)
|
115
|
+
end
|
116
|
+
rescue => err
|
117
|
+
exception_handler(err)
|
118
|
+
end
|
119
|
+
|
120
|
+
def exception_handler(err)
|
121
|
+
if respond_to?(:on_exception)
|
122
|
+
on_exception(err)
|
123
|
+
else
|
124
|
+
raise err
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path("../helper", __FILE__)
|
2
|
+
|
3
|
+
class TestKosmonautClient < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@client = Kosmonaut::Client.new("wr://#{ENV["VHOST_TOKEN"].to_s}@127.0.0.1:8081/test")
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_api
|
9
|
+
# tests depends each other, so we have to run it in
|
10
|
+
# correct order...
|
11
|
+
_test_open_channel
|
12
|
+
_test_open_channel_with_invalid_name
|
13
|
+
_test_broadcast
|
14
|
+
_test_broadcast_to_not_existing_channel
|
15
|
+
_test_close_channel
|
16
|
+
_test_close_not_existing_channel
|
17
|
+
_test_request_single_access_token
|
18
|
+
end
|
19
|
+
|
20
|
+
def _test_open_channel
|
21
|
+
@client.open_channel("foo", 0)
|
22
|
+
end
|
23
|
+
|
24
|
+
def _test_open_channel_with_invalid_name
|
25
|
+
@client.open_channel("%%%", 0)
|
26
|
+
assert false
|
27
|
+
rescue Kosmonaut::InvalidChannelNameError
|
28
|
+
end
|
29
|
+
|
30
|
+
def _test_broadcast
|
31
|
+
@client.broadcast("foo", "test", {})
|
32
|
+
end
|
33
|
+
|
34
|
+
def _test_broadcast_to_not_existing_channel
|
35
|
+
@client.broadcast("foobar", "test", {})
|
36
|
+
assert false
|
37
|
+
rescue Kosmonaut::ChannelNotFoundError
|
38
|
+
end
|
39
|
+
|
40
|
+
def _test_close_channel
|
41
|
+
@client.close_channel("foo")
|
42
|
+
end
|
43
|
+
|
44
|
+
def _test_close_not_existing_channel
|
45
|
+
@client.close_channel("bar")
|
46
|
+
assert false
|
47
|
+
rescue Kosmonaut::ChannelNotFoundError
|
48
|
+
end
|
49
|
+
|
50
|
+
def _test_request_single_access_token
|
51
|
+
token = @client.request_single_access_token(".*")
|
52
|
+
assert token
|
53
|
+
assert_equal 128, token.size
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.expand_path("../helper", __FILE__)
|
2
|
+
|
3
|
+
class MyWorker < Kosmonaut::Worker
|
4
|
+
def on_message(event, data)
|
5
|
+
puts "MSG", event, data
|
6
|
+
end
|
7
|
+
|
8
|
+
def on_error(err)
|
9
|
+
puts "ERR", err.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def on_exception(err)
|
13
|
+
puts "EXC", err.to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class TestKosmonautWorker < MiniTest::Unit::TestCase
|
18
|
+
def setup
|
19
|
+
@worker = MyWorker.new("wr://#{ENV["VHOST_TOKEN"].to_s}@127.0.0.1:8081/test")
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_api
|
23
|
+
Thread.new {
|
24
|
+
sleep(15)
|
25
|
+
@worker.stop
|
26
|
+
}
|
27
|
+
@worker.listen
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kosmonaut
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.2.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Krzysztof Kowalik
|
9
|
+
- Cubox
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2012-01-16 00:00:00 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: json
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "1.0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
description: The WebRocket server backend client for ruby programming language
|
28
|
+
email: chris@nu7hat.ch
|
29
|
+
executables: []
|
30
|
+
|
31
|
+
extensions: []
|
32
|
+
|
33
|
+
extra_rdoc_files: []
|
34
|
+
|
35
|
+
files:
|
36
|
+
- lib/kosmonaut/client.rb
|
37
|
+
- lib/kosmonaut/errors.rb
|
38
|
+
- lib/kosmonaut/socket.rb
|
39
|
+
- lib/kosmonaut/version.rb
|
40
|
+
- lib/kosmonaut/worker.rb
|
41
|
+
- lib/kosmonaut.rb
|
42
|
+
- test/helper.rb
|
43
|
+
- test/test_kosmonaut_client.rb
|
44
|
+
- test/test_kosmonaut_worker.rb
|
45
|
+
- Rakefile
|
46
|
+
- README
|
47
|
+
- COPYING
|
48
|
+
- kosmonaut.gemspec
|
49
|
+
homepage: http://webrocket.io/
|
50
|
+
licenses:
|
51
|
+
- MIT
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.8.10
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Ruby client for the WebRocket backend
|
76
|
+
test_files:
|
77
|
+
- test/helper.rb
|
78
|
+
- test/test_kosmonaut_client.rb
|
79
|
+
- test/test_kosmonaut_worker.rb
|