bridge-ruby 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README.md +31 -0
- data/Rakefile +24 -0
- data/bridge-ruby.gemspec +24 -0
- data/doc/Bridge.html +276 -0
- data/doc/Bridge/Bridge.html +1874 -0
- data/doc/Bridge/Bridge/SystemService.html +396 -0
- data/doc/Bridge/Client.html +271 -0
- data/doc/Bridge/Connection.html +1180 -0
- data/doc/Bridge/Connection/SockBuffer.html +322 -0
- data/doc/Bridge/Reference.html +605 -0
- data/doc/Bridge/Serializer.html +405 -0
- data/doc/Bridge/Serializer/Callback.html +498 -0
- data/doc/Bridge/Tcp.html +657 -0
- data/doc/Bridge/Util.html +643 -0
- data/doc/Bridge/Util/CallbackReference.html +557 -0
- data/doc/OpenSSL/X509/Certificate.html +275 -0
- data/doc/SSLCertificateVerification.html +446 -0
- data/doc/_index.html +239 -0
- data/doc/class_list.html +53 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +328 -0
- data/doc/file.README.html +106 -0
- data/doc/file_list.html +55 -0
- data/doc/frames.html +28 -0
- data/doc/index.html +106 -0
- data/doc/js/app.js +214 -0
- data/doc/js/full_list.js +173 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +772 -0
- data/doc/top-level-namespace.html +112 -0
- data/examples/channels/client-writeable.rb +24 -0
- data/examples/channels/client.rb +23 -0
- data/examples/channels/server.rb +24 -0
- data/examples/chat/chatclient.rb +21 -0
- data/examples/chat/chatserver.rb +24 -0
- data/examples/client-context/client.rb +21 -0
- data/examples/client-context/server.rb +25 -0
- data/examples/secure/example.rb +8 -0
- data/examples/simple/channels.rb +47 -0
- data/examples/simple/services.rb +41 -0
- data/include/ssl/cacert.pem +3331 -0
- data/lib/bridge-ruby.rb +441 -0
- data/lib/client.rb +14 -0
- data/lib/connection.rb +162 -0
- data/lib/reference.rb +49 -0
- data/lib/serializer.rb +104 -0
- data/lib/ssl_utils.rb +68 -0
- data/lib/tcp.rb +73 -0
- data/lib/util.rb +101 -0
- data/lib/version.rb +3 -0
- data/rakelib/package.rake +4 -0
- data/rakelib/test.rake +8 -0
- data/test/regression/reconnect.rb +48 -0
- data/test/regression/rpc.rb +39 -0
- data/test/regression/test.rb +58 -0
- data/test/unit/bridge_dummy.rb +26 -0
- data/test/unit/connection_dummy.rb +21 -0
- data/test/unit/reference_dummy.rb +11 -0
- data/test/unit/tcp_dummy.rb +12 -0
- data/test/unit/test.rb +20 -0
- data/test/unit/test_reference.rb +30 -0
- data/test/unit/test_serializer.rb +109 -0
- data/test/unit/test_tcp.rb +51 -0
- data/test/unit/test_util.rb +59 -0
- metadata +162 -0
data/lib/util.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module Bridge
|
7
|
+
module Util #:nodoc: all
|
8
|
+
|
9
|
+
@log = Logger.new(STDOUT)
|
10
|
+
|
11
|
+
def self.generate_guid
|
12
|
+
chars = (('a'..'z').to_a + (0..9).to_a)
|
13
|
+
(0...12).map{ chars[rand(26)] }.join
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.stringify obj
|
17
|
+
JSON::generate obj
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.parse str
|
21
|
+
JSON::parse str
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.info msg
|
25
|
+
@log.info msg
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.warn msg
|
29
|
+
@log.warn msg
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.error msg
|
33
|
+
@log.error msg
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.set_log_level level
|
37
|
+
if level > 2
|
38
|
+
@log.level = Logger::INFO
|
39
|
+
elsif level == 2
|
40
|
+
@log.level = Logger::WARN
|
41
|
+
elsif level == 1
|
42
|
+
@log.level = Logger::ERROR
|
43
|
+
else
|
44
|
+
@log.level = Logger::FATAL
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.ref_callback ref
|
49
|
+
CallbackReference.new ref do |*args, &blk|
|
50
|
+
args << blk if blk
|
51
|
+
self.call *args
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.find_ops obj
|
56
|
+
if obj.is_a? Module
|
57
|
+
return obj.methods false
|
58
|
+
else
|
59
|
+
return obj.class.instance_methods false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class CallbackReference < Proc
|
64
|
+
def initialize ref
|
65
|
+
@ref = ref
|
66
|
+
end
|
67
|
+
|
68
|
+
def callback *args, &blk
|
69
|
+
args << blk if blk
|
70
|
+
@ref.callback *args
|
71
|
+
end
|
72
|
+
|
73
|
+
def call *args, &blk
|
74
|
+
args << blk if blk
|
75
|
+
@ref.callback *args
|
76
|
+
end
|
77
|
+
|
78
|
+
def method atom
|
79
|
+
if atom.to_s == 'callback'
|
80
|
+
self
|
81
|
+
else
|
82
|
+
Class.method atom
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def methods bool
|
87
|
+
[:callback]
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_dict op = nil
|
91
|
+
@ref.to_dict op
|
92
|
+
end
|
93
|
+
|
94
|
+
def respond_to? atom
|
95
|
+
atom == :callback || atom == :to_dict || Class.respond_to?(atom)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
data/lib/version.rb
ADDED
data/rakelib/test.rake
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../../lib/bridge'
|
2
|
+
require_relative './test'
|
3
|
+
|
4
|
+
description = 'Reconnects';
|
5
|
+
failureMessage = 'This implementation of the Bridge API does not support reconnects.';
|
6
|
+
|
7
|
+
=begin
|
8
|
+
Passing this test means the following:
|
9
|
+
|
10
|
+
We can connect, reconnects (seem to) work. buffering between reconnects
|
11
|
+
works, services are preserved between these reconnects (i.e. should happen
|
12
|
+
in < 5s), and client ID is preserved.
|
13
|
+
=end
|
14
|
+
|
15
|
+
EM::run do
|
16
|
+
test = Test.new(failureMessage, 1, 4)
|
17
|
+
|
18
|
+
class T
|
19
|
+
def initialize(test, id)
|
20
|
+
@id = id
|
21
|
+
@test = test
|
22
|
+
@test.advance 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def cb(id)
|
26
|
+
if id != @id
|
27
|
+
@test.fail "ID not preserved."
|
28
|
+
end
|
29
|
+
@test.advance 3
|
30
|
+
@test.close
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
bridge = Bridge::Bridge.new({:api_key => 'abcdefgh'}).connect {
|
35
|
+
test.advance 0
|
36
|
+
}
|
37
|
+
|
38
|
+
bridge.ready {
|
39
|
+
svc = T.new(test, bridge.connection.client_id)
|
40
|
+
bridge.publish_service('test_reconn', svc) {
|
41
|
+
test.advance 2
|
42
|
+
bridge.connection.sock.close_connection
|
43
|
+
EM::Timer.new(0) {
|
44
|
+
bridge.get_service('test_reconn') {|service| service.cb(bridge.connection.client_id)}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative '../../lib/bridge'
|
2
|
+
require_relative './test'
|
3
|
+
|
4
|
+
description = 'Basic RPC';
|
5
|
+
failureMessage = 'This implementation of the Bridge API is incapable of RPC.';
|
6
|
+
|
7
|
+
=begin
|
8
|
+
Passing this test means the following:
|
9
|
+
|
10
|
+
We can connect (it seems), we can publish a service, the callback to
|
11
|
+
publishService is called, and calling a method of getService works.
|
12
|
+
|
13
|
+
=end
|
14
|
+
|
15
|
+
EM::run do
|
16
|
+
test = Test.new(failureMessage, 2, 3)
|
17
|
+
|
18
|
+
bridge = Bridge::Bridge.new({:api_key => 'abcdefgh'}).connect {
|
19
|
+
test.advance 0
|
20
|
+
}
|
21
|
+
|
22
|
+
module ConsoleLogServer
|
23
|
+
def self.log(msg = "", test)
|
24
|
+
if msg == '123'
|
25
|
+
test.advance(2)
|
26
|
+
else
|
27
|
+
test.log('received ' + msg + ' but expected 123')
|
28
|
+
end
|
29
|
+
test.close
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
bridge.ready {
|
34
|
+
bridge.publish_service('test_consolelog', ConsoleLogServer) {
|
35
|
+
test.advance 1
|
36
|
+
bridge.get_service('test_consolelog') {|service| service.log('123', test)}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
|
3
|
+
class Test
|
4
|
+
def initialize failureMessage, logLevel, stages
|
5
|
+
@messages = []
|
6
|
+
@stages = stages
|
7
|
+
@stage = 0
|
8
|
+
@failureMessage = failureMessage
|
9
|
+
@timer = EM::Timer.new(5) { self.fail "timeout" }
|
10
|
+
if !(logLevel == 0 || logLevel == 1 || logLevel == 2)
|
11
|
+
raise "Invalid log level #{logLevel}"
|
12
|
+
end
|
13
|
+
@logLevel = logLevel
|
14
|
+
end
|
15
|
+
|
16
|
+
def advance expected
|
17
|
+
if @stage != expected
|
18
|
+
self.fail "out of order: at stage #{@stage}, not #{expected}"
|
19
|
+
else
|
20
|
+
@stage += 1
|
21
|
+
@timer.cancel
|
22
|
+
@timer = EM::Timer.new(5) { self.fail "timeout" }
|
23
|
+
if @logLevel > 0
|
24
|
+
puts "Advancing to stage #{@stage}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def close
|
30
|
+
if @stage != @stages
|
31
|
+
puts "Failure: reached stage #{@stage} of #{@stages}"
|
32
|
+
else
|
33
|
+
puts "Success; passed this test."
|
34
|
+
end
|
35
|
+
|
36
|
+
Process::exit
|
37
|
+
end
|
38
|
+
|
39
|
+
def fail(m = failureMessage)
|
40
|
+
puts "============================================"
|
41
|
+
puts " Description: ", m
|
42
|
+
if @logLevel != 0
|
43
|
+
puts " Message stack: "
|
44
|
+
@messages.each {|msg| puts msg}
|
45
|
+
end
|
46
|
+
self.close
|
47
|
+
end
|
48
|
+
|
49
|
+
def log msg
|
50
|
+
if @logLevel != 0
|
51
|
+
@messages += msg
|
52
|
+
if logLevel == 2
|
53
|
+
puts msg
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative "reference_dummy.rb"
|
2
|
+
|
3
|
+
class BridgeDummy
|
4
|
+
|
5
|
+
attr_accessor :last_args, :last_dest, :stored, :options
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@options = {
|
9
|
+
:redirector => 'http://redirector.getbridge.com',
|
10
|
+
:reconnect => true,
|
11
|
+
:log => 2, # 0 for no output
|
12
|
+
}
|
13
|
+
@stored = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def store_object handler, ops
|
17
|
+
@stored << [handler, ops]
|
18
|
+
return ReferenceDummy.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def send args, destination
|
22
|
+
@last_args = args
|
23
|
+
@last_dest = destination
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class ConnectionDummy
|
2
|
+
|
3
|
+
attr_accessor :messages, :onopened
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@messages = []
|
7
|
+
@onopened = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def onopen *args
|
11
|
+
@onopened = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def onclose *args
|
15
|
+
end
|
16
|
+
|
17
|
+
def onmessage data, tcp
|
18
|
+
messages << data[:data]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/test/unit/test.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start do
|
3
|
+
add_filter "/test/"
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
|
8
|
+
require_relative '../../lib/bridge'
|
9
|
+
require_relative '../../lib/connection'
|
10
|
+
require_relative '../../lib/reference'
|
11
|
+
require_relative '../../lib/serializer'
|
12
|
+
require_relative '../../lib/tcp'
|
13
|
+
require_relative '../../lib/util'
|
14
|
+
require_relative '../../lib/version'
|
15
|
+
|
16
|
+
require_relative 'test_util.rb'
|
17
|
+
require_relative 'test_serializer.rb'
|
18
|
+
require_relative 'test_tcp.rb'
|
19
|
+
require_relative 'test_reference.rb'
|
20
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "bridge"
|
2
|
+
require_relative "bridge_dummy.rb"
|
3
|
+
require "test/unit"
|
4
|
+
|
5
|
+
class TestReference < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
## Nothing really
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def test_reference
|
17
|
+
dummy = BridgeDummy.new
|
18
|
+
ref = Bridge::Reference.new dummy, ['x', 'y', 'z'], [:a, :b, :c]
|
19
|
+
assert_equal(['a', 'b', 'c'], ref.operations)
|
20
|
+
assert_equal({:ref => ['x', 'y', 'z'], :operations => ['a', 'b', 'c']}, ref.to_dict)
|
21
|
+
|
22
|
+
blk = lambda {}
|
23
|
+
ref.test 1, 2, &blk
|
24
|
+
assert_equal([1,2,blk], dummy.last_args)
|
25
|
+
assert_equal(['x', 'y', 'z', 'test'], dummy.last_dest[:ref])
|
26
|
+
assert(!dummy.last_dest.key?(:operations))
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require "bridge"
|
2
|
+
require_relative "bridge_dummy.rb"
|
3
|
+
require_relative "reference_dummy.rb"
|
4
|
+
require "test/unit"
|
5
|
+
|
6
|
+
class TestSerializer < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
## Nothing really
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def test_serialize
|
18
|
+
dummy = BridgeDummy.new
|
19
|
+
test2 = Test2.new
|
20
|
+
test3 = Test3.new
|
21
|
+
test4 = lambda {}
|
22
|
+
obj = {
|
23
|
+
:a => {
|
24
|
+
:b => Test1
|
25
|
+
},
|
26
|
+
:c => 5,
|
27
|
+
:d => true,
|
28
|
+
:e => 'abc',
|
29
|
+
:f => [test2, test3],
|
30
|
+
:g => test2,
|
31
|
+
:h => test3,
|
32
|
+
:i => test4
|
33
|
+
}
|
34
|
+
ser = Bridge::Serializer.serialize dummy, obj
|
35
|
+
|
36
|
+
assert(dummy.stored.include?([Test1, [:a]]))
|
37
|
+
assert(dummy.stored.include?([test2, [:c]]))
|
38
|
+
assert(dummy.stored.include?([test3, [:d, :e]]))
|
39
|
+
|
40
|
+
found = false
|
41
|
+
dummy.stored.each do | x |
|
42
|
+
if x[1] == ['callback']
|
43
|
+
assert_instance_of(Bridge::Serializer::Callback, x[0])
|
44
|
+
found = true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
assert found
|
49
|
+
|
50
|
+
expected_ser = {
|
51
|
+
:a => {
|
52
|
+
:b => "dummy"
|
53
|
+
},
|
54
|
+
:c => 5,
|
55
|
+
:d => true,
|
56
|
+
:e => 'abc',
|
57
|
+
:f => ["dummy", "dummy"],
|
58
|
+
:g => "dummy",
|
59
|
+
:h => "dummy",
|
60
|
+
:i => "dummy"
|
61
|
+
}
|
62
|
+
|
63
|
+
assert_equal(expected_ser, ser)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_unserialize
|
67
|
+
dummy = BridgeDummy.new
|
68
|
+
obj = {
|
69
|
+
:a => {'ref' => ['x','x','x'], 'operations' => ['a','b']},
|
70
|
+
:b => {
|
71
|
+
:i => {'ref' => ['z','z','z'], 'operations' => ['callback']}
|
72
|
+
},
|
73
|
+
:c => 5,
|
74
|
+
:d => true,
|
75
|
+
:e => 'abc',
|
76
|
+
:f => [1, {'ref' => ['y','y','y'], 'operations' => ['c','d']}],
|
77
|
+
:g => 2,
|
78
|
+
:h => 'foo'
|
79
|
+
}
|
80
|
+
|
81
|
+
unser = Bridge::Serializer.unserialize dummy, obj
|
82
|
+
|
83
|
+
assert_instance_of(Bridge::Reference, unser[:a])
|
84
|
+
assert_instance_of(Bridge::Reference, unser[:f][1])
|
85
|
+
assert_instance_of(Bridge::Util::CallbackReference, unser[:b][:i])
|
86
|
+
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
module Test1
|
91
|
+
def self.a
|
92
|
+
end
|
93
|
+
def b
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Test2
|
98
|
+
def c
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Test3 < Test2
|
103
|
+
def d
|
104
|
+
end
|
105
|
+
def e
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|