vitobotta-brb 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +22 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +13 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +57 -0
- data/Rakefile +23 -0
- data/examples/simple_client.rb +40 -0
- data/examples/simple_core.rb +29 -0
- data/init.rb +2 -0
- data/lib/brb.rb +5 -0
- data/lib/brb/event_machine.rb +91 -0
- data/lib/brb/exception.rb +9 -0
- data/lib/brb/logger.rb +35 -0
- data/lib/brb/request.rb +98 -0
- data/lib/brb/service.rb +56 -0
- data/lib/brb/tunnel.rb +95 -0
- data/lib/brb/tunnel/shared.rb +158 -0
- data/spec/brb/brb_logger_spec.rb +35 -0
- data/spec/brb/brb_massive_usage_spec.rb +103 -0
- data/spec/brb/brb_service_spec.rb +29 -0
- data/spec/brb/brb_tunnel_spec.rb +176 -0
- data/spec/spec_helper.rb +54 -0
- metadata +82 -0
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
0.3.0 (May 21, 2010)
|
2
|
+
|
3
|
+
* Added Callback functionality through block
|
4
|
+
* Added Callback example
|
5
|
+
* Little spec refactoring
|
6
|
+
|
7
|
+
0.2.2 (Apr 21, 2010)
|
8
|
+
|
9
|
+
* Change silent option to verbose
|
10
|
+
|
11
|
+
0.2.1 (Apr 16, 2010)
|
12
|
+
|
13
|
+
* Automatically start EM if not started
|
14
|
+
* Deprecate the usage of BrB::Service.instance => use BrB::Service instead
|
15
|
+
|
16
|
+
0.2.0 (Apr 16, 2010)
|
17
|
+
|
18
|
+
* Releasing gem and wiki
|
19
|
+
|
20
|
+
0.1.0 (Feb 01, 2009)
|
21
|
+
|
22
|
+
* Initial release
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Guillaume Luccisano - g-mai|: guillaume.luccisano
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
= BrB - Easy and Fast distributed ruby
|
2
|
+
|
3
|
+
BrB is a simple, fully transparent and extremely fast interface for doing simple distributed Ruby.
|
4
|
+
The core of the architecture is provided by EventMachine (a fast and reliable IO event library).
|
5
|
+
|
6
|
+
BrB was built in order to achieve these 4 main goals :
|
7
|
+
* Simple and fast message passing between distant Ruby processes.
|
8
|
+
* Message passing with of return values when needed.
|
9
|
+
* Being extremely fast in order to handle more than a few thousand messages per second.
|
10
|
+
* Being completely transparent for developer.
|
11
|
+
|
12
|
+
The principle is simple and inspired from Drb (standard distributed ruby library) :
|
13
|
+
A process exposes an object over the network and any ruby process (after having established a connection tunnel) can directly call a method on the exposed object. BrB handles that part, so it’s fully transparent in the Ruby code.
|
14
|
+
|
15
|
+
BrB only support message passing with Marshable dumpable object : String, symbol, Array, hash, Number, Object etc...
|
16
|
+
That mean you can not send file descriptor, Thread or another funky things like that :)
|
17
|
+
|
18
|
+
For any question, use the Ruby BrB google group: http://groups.google.com/group/ruby-brb
|
19
|
+
|
20
|
+
== Main Functionalities
|
21
|
+
|
22
|
+
* Unlimited objects exposed
|
23
|
+
* Processes can expose object and be client to exposed object too at the same time
|
24
|
+
* Do not wait for return by default : just do simple message passing
|
25
|
+
* Handle return values without blocking with the usage of a simple block
|
26
|
+
* Blocking wait for a return value if needed by simply adding <em>_block</em> at the end of the method name
|
27
|
+
* Transmission of Exception when blocking call
|
28
|
+
* Thread safe if used correctly with Event Machine
|
29
|
+
|
30
|
+
== How it works
|
31
|
+
|
32
|
+
First of all, a process declare himself as a sever and expose any object on a given address and port.
|
33
|
+
Then, any number of distant processes can create a <em>Tunnel</em> with that server and can expose an object in exchange too.
|
34
|
+
After connection are ready, just call method on the tunnel. It will just act like normal method calling on the exposed object !
|
35
|
+
|
36
|
+
== What BrB is designed for ?
|
37
|
+
|
38
|
+
* Doing Simple message passing between ruby process.
|
39
|
+
* Connecting hundred of ruby process transparently.
|
40
|
+
* Building a real-time scalable (game) server
|
41
|
+
* Taking important load on a server easily just by distributing the load on multiple BrB instance.
|
42
|
+
* Taking advantage of multi-core and multi-threaded systems.
|
43
|
+
|
44
|
+
== TODO
|
45
|
+
* Writing more examples
|
46
|
+
* Publish Benchmarks VS drb
|
47
|
+
* Improve logging mechanism
|
48
|
+
* Clean up
|
49
|
+
|
50
|
+
== Contributors
|
51
|
+
|
52
|
+
* kwi (Guillaume Luccisano)
|
53
|
+
* bwalton (Brian Walton)
|
54
|
+
* dpree (Jens Bissinger)
|
55
|
+
|
56
|
+
|
57
|
+
Copyright (c) 2009-2010 Guillaume Luccisano - g-mai|: guillaume.luccisano, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
|
5
|
+
spec_files = Rake::FileList["spec/**/*_spec.rb"]
|
6
|
+
|
7
|
+
desc "Run specs for current Rails version"
|
8
|
+
Spec::Rake::SpecTask.new do |t|
|
9
|
+
t.spec_files = spec_files
|
10
|
+
t.spec_opts = ["-c --format specdoc"]
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :spec
|
14
|
+
|
15
|
+
desc "Run simple core"
|
16
|
+
task :simple_core_example do
|
17
|
+
require 'examples/simple_core'
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Run simple client (call simple_core_before)"
|
21
|
+
task :simple_client_example do
|
22
|
+
require 'examples/simple_client'
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../init.rb')
|
2
|
+
|
3
|
+
port = 5555
|
4
|
+
host = 'localhost'
|
5
|
+
|
6
|
+
# Connecting to the core server, retrieving its interface object : core
|
7
|
+
# We do not want to expose an object, so the first parameter is nil
|
8
|
+
core = BrB::Tunnel.create(nil, "brb://#{host}:#{port}", :verbose => true)
|
9
|
+
|
10
|
+
# Calling 10 times an non blocking method on the distant core server
|
11
|
+
10.times do
|
12
|
+
core.simple_api_method # Do not wait for response
|
13
|
+
end
|
14
|
+
|
15
|
+
# Calling 10 times again long treatment time distant methods
|
16
|
+
10.times do
|
17
|
+
core.simple_long_api_method # Do not wait for response
|
18
|
+
end
|
19
|
+
|
20
|
+
# Calling a blocking method with _block on the distant core server :
|
21
|
+
puts " >> Calling 1s call, and wait for response..."
|
22
|
+
r = core.simple_api_method_block
|
23
|
+
puts " > Api response : #{r}"
|
24
|
+
|
25
|
+
puts " >> Calling long call, and wait for response..."
|
26
|
+
r = core.simple_long_api_method_block
|
27
|
+
puts " > Api long response : #{r}"
|
28
|
+
|
29
|
+
## Calling method with a callback block for handling the return value
|
30
|
+
core.simple_api_method do |r|
|
31
|
+
puts " > Get the callback response : #{r}"
|
32
|
+
end
|
33
|
+
|
34
|
+
puts " >> Callback method has been called continue .."
|
35
|
+
sleep 2
|
36
|
+
|
37
|
+
core.stop_service
|
38
|
+
|
39
|
+
# Our job is over, close event machine :
|
40
|
+
EM.stop
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../init.rb')
|
2
|
+
|
3
|
+
class ExposedCoreObject
|
4
|
+
|
5
|
+
def simple_api_method
|
6
|
+
puts "#{Thread.current} > In simple api method, now sleeping"
|
7
|
+
yield if block_given?
|
8
|
+
sleep 1
|
9
|
+
puts "#{Thread.current} > Done sleeping in simple api method, return"
|
10
|
+
return 'OK'
|
11
|
+
end
|
12
|
+
|
13
|
+
def simple_long_api_method
|
14
|
+
puts "#{Thread.current} > In simple long api method, now sleeping"
|
15
|
+
sleep 10
|
16
|
+
puts "#{Thread.current} > Done sleeping in long api method, return"
|
17
|
+
return 'OK LONG'
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
Thread.abort_on_exception = true
|
23
|
+
|
24
|
+
port = 5555
|
25
|
+
host = 'localhost'
|
26
|
+
|
27
|
+
puts " > Starting the core on brb://#{host}:#{port}"
|
28
|
+
BrB::Service.start_service(:object => ExposedCoreObject.new, :verbose => true, :host => host, :port => port)
|
29
|
+
EM.reactor_thread.join
|
data/init.rb
ADDED
data/lib/brb.rb
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'brb', 'logger.rb')
|
2
|
+
require File.join(File.dirname(__FILE__), 'brb', 'exception.rb')
|
3
|
+
require File.join(File.dirname(__FILE__), 'brb', 'event_machine.rb')
|
4
|
+
require File.join(File.dirname(__FILE__), 'brb', 'service.rb')
|
5
|
+
require File.join(File.dirname(__FILE__), 'brb', 'tunnel.rb')
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Define a BrB::Protocol using event machine
|
2
|
+
require 'eventmachine'
|
3
|
+
|
4
|
+
module BrB
|
5
|
+
class EventMachine
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
private
|
10
|
+
# If EM::run has not been called yet, start the EM reactor in another thread.
|
11
|
+
def ensure_em_is_started!
|
12
|
+
if !EM::reactor_running?
|
13
|
+
# Launch event machine reactor
|
14
|
+
q = Queue.new
|
15
|
+
Thread.new do
|
16
|
+
EM::run do
|
17
|
+
q << true # Set to the calling thread that the reactor is running
|
18
|
+
#EM::set_quantum(20)
|
19
|
+
#EventMachine::epoll
|
20
|
+
end
|
21
|
+
end
|
22
|
+
# Wait for event machine running :
|
23
|
+
q.pop
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
public
|
29
|
+
def open(uri, klass, opts = {})
|
30
|
+
host, port = parse_uri(uri)
|
31
|
+
begin
|
32
|
+
ensure_em_is_started!
|
33
|
+
|
34
|
+
q = Queue.new
|
35
|
+
EM.schedule do
|
36
|
+
q << EM::connect(host, port, klass, opts.merge(:uri => "brb://#{host}:#{port}"))
|
37
|
+
end
|
38
|
+
|
39
|
+
# Wait for socket connection with the q.pop
|
40
|
+
return q.pop
|
41
|
+
|
42
|
+
rescue Exception => e
|
43
|
+
BrB.logger.error e.backtrace.join("\n")
|
44
|
+
raise "#{e} - #{uri}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def open_server(uri, klass, opts = {})
|
49
|
+
host, port = parse_uri(uri)
|
50
|
+
max = 80 # Nb try before giving up
|
51
|
+
begin
|
52
|
+
uri = "brb://#{host}:#{port}"
|
53
|
+
ensure_em_is_started!
|
54
|
+
|
55
|
+
# Schedule server creation for thread safety
|
56
|
+
q = Queue.new
|
57
|
+
EM.schedule do
|
58
|
+
q << EM::start_server(host, port, klass, opts.merge(:uri => uri))
|
59
|
+
end
|
60
|
+
|
61
|
+
# Wait for server creation with the q.pop
|
62
|
+
return uri, q.pop
|
63
|
+
|
64
|
+
rescue Exception => e
|
65
|
+
max -= 1
|
66
|
+
port += 1
|
67
|
+
retry if max > 0
|
68
|
+
BrB.logger.error e.backtrace.join("\n")
|
69
|
+
raise "#{e} - BrB Tcp Event machine Can not bind on #{host}:#{port}"
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Protocol < EventMachine
|
77
|
+
|
78
|
+
class << self
|
79
|
+
|
80
|
+
def parse_uri(uri)
|
81
|
+
if /^brb:\/\/(.+):([0-9]+)$/ =~ uri
|
82
|
+
[$1, $2.to_i]
|
83
|
+
else
|
84
|
+
raise "Bad tcp BrB url: '#{uri}'"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
data/lib/brb/logger.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
module BrB
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# returns the default logger instance
|
7
|
+
def default_logger
|
8
|
+
Logger.new(STDOUT)
|
9
|
+
end
|
10
|
+
|
11
|
+
# set a custom logger instance
|
12
|
+
def logger=(custom_logger)
|
13
|
+
@@logger = custom_logger
|
14
|
+
end
|
15
|
+
|
16
|
+
# returns the logger instance
|
17
|
+
def logger
|
18
|
+
# use default logger if no custom logger is set
|
19
|
+
@@logger = default_logger unless defined? @@logger
|
20
|
+
|
21
|
+
# this overwrites the original method with a static definition
|
22
|
+
eval %Q{
|
23
|
+
def logger
|
24
|
+
@@logger
|
25
|
+
end
|
26
|
+
}
|
27
|
+
@@logger
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# alias to BrB.logger
|
32
|
+
def logger
|
33
|
+
BrB.logger
|
34
|
+
end
|
35
|
+
end
|
data/lib/brb/request.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
module BrB
|
2
|
+
module Request
|
3
|
+
|
4
|
+
MessageRequestCode = :s
|
5
|
+
CallbackRequestCode = :c
|
6
|
+
ReturnCode = :r
|
7
|
+
|
8
|
+
def is_brb_request_blocking?(meth)
|
9
|
+
if m = meth.to_s and m.rindex('_block') == (m.size - 6)
|
10
|
+
return true
|
11
|
+
end
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
# Execute a request on a distant object
|
16
|
+
def new_brb_out_request(meth, *args, &blck)
|
17
|
+
Thread.current[:brb_nb_out] ||= 0
|
18
|
+
Thread.current[:brb_nb_out] += 1
|
19
|
+
|
20
|
+
raise BrBCallbackWithBlockingMethodException.new if is_brb_request_blocking?(meth) and block_given?
|
21
|
+
|
22
|
+
block = (is_brb_request_blocking?(meth) or block_given?) ? Thread.current.to_s.to_sym : nil
|
23
|
+
if block
|
24
|
+
args << block
|
25
|
+
args << Thread.current[:brb_nb_out]
|
26
|
+
end
|
27
|
+
|
28
|
+
if block_given?
|
29
|
+
# Simulate a method with _block in order to make BrB send the answer
|
30
|
+
meth = "#{meth}_block".to_sym
|
31
|
+
end
|
32
|
+
|
33
|
+
args.size > 0 ? brb_send([MessageRequestCode, meth, args]) : brb_send([MessageRequestCode, meth])
|
34
|
+
|
35
|
+
if block_given?
|
36
|
+
# Declare the callback
|
37
|
+
declare_callback(block, Thread.current[:brb_nb_out], &blck)
|
38
|
+
|
39
|
+
elsif block # Block until the request return
|
40
|
+
|
41
|
+
#TimeMonitor.instance.watch_thread!(@timeout_rcv_value || 45)
|
42
|
+
begin
|
43
|
+
r = recv(block, Thread.current[:brb_nb_out], &blck)
|
44
|
+
rescue Exception => e
|
45
|
+
raise e
|
46
|
+
ensure
|
47
|
+
#TimeMonitor.instance.remove_thread!
|
48
|
+
end
|
49
|
+
if r.kind_of? Exception
|
50
|
+
raise r
|
51
|
+
end
|
52
|
+
return r
|
53
|
+
end
|
54
|
+
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
# Execute a request on the local object
|
59
|
+
def new_brb_in_request(meth, *args)
|
60
|
+
client_info = {
|
61
|
+
:ip_address => @ip_address,
|
62
|
+
:port => @port
|
63
|
+
}
|
64
|
+
|
65
|
+
if is_brb_request_blocking?(meth)
|
66
|
+
|
67
|
+
m = meth.to_s
|
68
|
+
m = m[0, m.size - 6].to_sym
|
69
|
+
|
70
|
+
idrequest = args.pop
|
71
|
+
thread = args.pop
|
72
|
+
|
73
|
+
args << client_info
|
74
|
+
begin
|
75
|
+
# r = ((args.size > 0) ? @object.send(m, *args) : @object.send(m))
|
76
|
+
r = @object.send(m, *args)
|
77
|
+
brb_send([ReturnCode, r, thread, idrequest])
|
78
|
+
rescue Exception => e
|
79
|
+
brb_send([ReturnCode, e, thread, idrequest])
|
80
|
+
BrB.logger.error e.to_s
|
81
|
+
BrB.logger.error e.backtrace.join("\n")
|
82
|
+
#raise e
|
83
|
+
end
|
84
|
+
else
|
85
|
+
args << client_info
|
86
|
+
|
87
|
+
begin
|
88
|
+
# (args.size > 0) ? @object.send(meth, *args) : @object.send(meth)
|
89
|
+
@object.send(meth, *args)
|
90
|
+
rescue Exception => e
|
91
|
+
BrB.logger.error "#{e.to_s} => By calling #{meth} on #{@object.class} with args : #{args.inspect}"
|
92
|
+
BrB.logger.error e.backtrace.join("\n")
|
93
|
+
raise e
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/brb/service.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#
|
2
|
+
# Brb Main class used to do basic distributed ruby, Simple but fast
|
3
|
+
# Use two distinct canal, one for the command reception, and the other one for send return value
|
4
|
+
#
|
5
|
+
module BrB
|
6
|
+
class Service
|
7
|
+
@@uri = nil
|
8
|
+
@@em_signature = nil
|
9
|
+
@@verbose = false
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
public
|
14
|
+
|
15
|
+
# Start a server hosted on the object given,
|
16
|
+
# If an uri is given, automatcilay connect to the distant brb object
|
17
|
+
def start_service(opts = {}, &block)
|
18
|
+
return if @@em_signature
|
19
|
+
|
20
|
+
@@verbose = opts[:verbose]
|
21
|
+
BrB.logger.level = @@verbose ? Logger::INFO : Logger::WARN
|
22
|
+
|
23
|
+
addr = opts[:uri] || "brb://#{opts[:host] || 'localhost'}:#{opts[:port] || 6200}"
|
24
|
+
|
25
|
+
BrB.logger.info " [BrB] Start service on #{addr} ..."
|
26
|
+
@@uri, @@em_signature = BrB::Protocol::open_server(addr, BrB::Tunnel::Handler, opts.merge(:block => block))
|
27
|
+
BrB.logger.info " [BrB] Service started on #{@@uri}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def uri
|
31
|
+
@@uri
|
32
|
+
end
|
33
|
+
|
34
|
+
# Stop the Brb Service
|
35
|
+
def stop_service
|
36
|
+
return if !@@em_signature or !EM::reactor_running?
|
37
|
+
|
38
|
+
BrB.logger.info " [BrB] Stop service on #{@@uri}"
|
39
|
+
sign = @@em_signature
|
40
|
+
q = Queue.new # Creation of a Queue for waiting server to stop
|
41
|
+
EM::schedule do
|
42
|
+
q << EM::stop_server(sign)
|
43
|
+
end
|
44
|
+
q.pop
|
45
|
+
@@em_signature = nil
|
46
|
+
@@uri = nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# Deprecated old method
|
50
|
+
def instance
|
51
|
+
BrB.logger.warn "DEPRECATION WARNING: BrB::Service::instance is deprecated => Just use BrB::Service"
|
52
|
+
self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/brb/tunnel.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'eventmachine'
|
3
|
+
require File.join(File.dirname(__FILE__), 'request.rb')
|
4
|
+
require File.join(File.dirname(__FILE__), 'tunnel', 'shared.rb')
|
5
|
+
|
6
|
+
module BrB
|
7
|
+
module Tunnel
|
8
|
+
|
9
|
+
# Create a BrB Tunnel by connecting to a distant BrB service
|
10
|
+
# Pass a block if you want to get register and unregister events
|
11
|
+
# The first parameter object is the object you want to expose in the BrB tunnel
|
12
|
+
def self.create(object, uri = nil, opts = {}, &block)
|
13
|
+
BrB::Protocol.open(uri, BrB::Tunnel::Handler, opts.merge(:object => object, :block => block))
|
14
|
+
end
|
15
|
+
|
16
|
+
# Brb interface Handler for Tunnel over Event machine
|
17
|
+
class Handler < ::EventMachine::Connection
|
18
|
+
attr_reader :uri
|
19
|
+
|
20
|
+
include BrB::Request
|
21
|
+
include BrB::Tunnel::Shared
|
22
|
+
|
23
|
+
def initialize(opts = {})
|
24
|
+
super
|
25
|
+
@object = opts[:object]
|
26
|
+
@verbose = opts[:verbose]
|
27
|
+
BrB.logger.level = @verbose ? Logger::INFO : Logger::WARN
|
28
|
+
@timeout_rcv_value = opts[:timeout] || 30 # Currently not implemented due to the lack of performance of ruby Timeout
|
29
|
+
@close_after_timeout = opts[:close_after_timeout] || false
|
30
|
+
@uri = opts[:uri]
|
31
|
+
@replock = Mutex.new
|
32
|
+
@responses = {}
|
33
|
+
@block = opts[:block]
|
34
|
+
|
35
|
+
@queue = Queue.new
|
36
|
+
@buffer = ''
|
37
|
+
|
38
|
+
# Callbacks handling :
|
39
|
+
@callbacks = {}
|
40
|
+
@callbacks_mutex = Mutex.new
|
41
|
+
end
|
42
|
+
|
43
|
+
# EventMachine Callback, called after connection has been initialized
|
44
|
+
def post_init
|
45
|
+
@port, @ip_address = Socket.unpack_sockaddr_in(get_peername)
|
46
|
+
|
47
|
+
BrB.logger.info " [BrB] Tunnel initialized on #{@uri}"
|
48
|
+
@active = true
|
49
|
+
if @block
|
50
|
+
EM.defer do
|
51
|
+
@block.call(:register, self)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def close_connection(after_writing = false)
|
57
|
+
@active = false
|
58
|
+
super
|
59
|
+
end
|
60
|
+
|
61
|
+
# EventMachine unbind event
|
62
|
+
# The connection has been closed
|
63
|
+
def unbind
|
64
|
+
BrB.logger.info ' [BrB] Tunnel service closed'
|
65
|
+
@active = false
|
66
|
+
if @block
|
67
|
+
EM.defer do
|
68
|
+
@block.call(:unregister, self)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Stop the service
|
74
|
+
def stop_service
|
75
|
+
BrB.logger.info ' [BrB] Stopping Tunnel service...'
|
76
|
+
@active = false
|
77
|
+
EM.schedule do
|
78
|
+
close_connection
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return true if the tunnel is currently active
|
83
|
+
def active?
|
84
|
+
@active
|
85
|
+
end
|
86
|
+
|
87
|
+
# When no method is found on tunnel interface, create an brb out request
|
88
|
+
def method_missing(meth, *args, &block)
|
89
|
+
return nil if !@active
|
90
|
+
new_brb_out_request(meth, *args, &block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module BrB
|
4
|
+
module Tunnel
|
5
|
+
module Shared
|
6
|
+
def make_proxy(r)
|
7
|
+
if r.is_a?(Array)
|
8
|
+
t = []
|
9
|
+
r.each do |obj|
|
10
|
+
t << if obj.is_a? Array
|
11
|
+
make_proxy(obj)
|
12
|
+
elsif !obj.is_a?(Symbol) and !obj.is_a?(String) and obj and !(Marshal::dump(obj) rescue nil)
|
13
|
+
#BrB.logger.debug " - > Make proxy for : #{obj.class}"
|
14
|
+
obj.to_s.to_sym
|
15
|
+
else
|
16
|
+
obj
|
17
|
+
end
|
18
|
+
end
|
19
|
+
return t
|
20
|
+
else
|
21
|
+
return r.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def brb_send(r)
|
26
|
+
return nil if !@active
|
27
|
+
s = Marshal::dump(r) rescue Marshal::dump(make_proxy(r))
|
28
|
+
|
29
|
+
s = [s.size].pack('N') + s
|
30
|
+
EM.schedule do
|
31
|
+
send_data s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
SizeOfPackedInt = [1].pack('N').size
|
36
|
+
|
37
|
+
def load_request
|
38
|
+
return nil if @buffer.size < SizeOfPackedInt
|
39
|
+
len = @buffer.unpack('N').first + SizeOfPackedInt
|
40
|
+
if @buffer.size < len
|
41
|
+
return nil
|
42
|
+
end
|
43
|
+
|
44
|
+
obj = Marshal::load(@buffer[SizeOfPackedInt, len])
|
45
|
+
@buffer.slice!(0,len)
|
46
|
+
return obj
|
47
|
+
end
|
48
|
+
|
49
|
+
def receive_data(data)
|
50
|
+
@buffer << data
|
51
|
+
|
52
|
+
while obj = load_request
|
53
|
+
if obj[0] == BrB::Request::ReturnCode
|
54
|
+
|
55
|
+
# Return if we have a callback handling the return :
|
56
|
+
next if treat_callback_return(obj[1], obj[2], obj[3])
|
57
|
+
|
58
|
+
# No callback, so blocking thread is waiting :
|
59
|
+
@replock.lock
|
60
|
+
@responses[obj[2]] ||= Queue.new
|
61
|
+
@replock.unlock
|
62
|
+
@responses[obj[2]] << [obj[1], obj[3]]
|
63
|
+
else
|
64
|
+
@queue << obj
|
65
|
+
|
66
|
+
EM.defer do
|
67
|
+
treat_request(@queue.pop)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def treat_request(obj)
|
75
|
+
if obj.size == 2
|
76
|
+
new_brb_in_request(obj[1])
|
77
|
+
else
|
78
|
+
new_brb_in_request(obj[1], *(obj.last))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Declare a new callback to call for a given request
|
83
|
+
# Thread safe code
|
84
|
+
def declare_callback(key, nb_out, &block)
|
85
|
+
@callbacks_mutex.lock
|
86
|
+
|
87
|
+
@callbacks[key] ||= {}
|
88
|
+
@callbacks[key][nb_out] = block
|
89
|
+
|
90
|
+
ensure
|
91
|
+
@callbacks_mutex.unlock
|
92
|
+
end
|
93
|
+
|
94
|
+
# Return associated callback if present
|
95
|
+
# And if present, delete the associate callback from the table
|
96
|
+
# Thread safe code
|
97
|
+
def get_callback(key, nb_out)
|
98
|
+
@callbacks_mutex.lock
|
99
|
+
|
100
|
+
if @callbacks[key] and b = @callbacks[key].delete(nb_out)
|
101
|
+
return b
|
102
|
+
end
|
103
|
+
|
104
|
+
ensure
|
105
|
+
@callbacks_mutex.unlock
|
106
|
+
end
|
107
|
+
|
108
|
+
# Call a callback if present, return true if exists
|
109
|
+
# Non blocking action, use EM.defer
|
110
|
+
def treat_callback_return(ret, key, nb_out)
|
111
|
+
|
112
|
+
if b = get_callback(key, nb_out)
|
113
|
+
EM.defer do
|
114
|
+
# With arity, handle multiple block arguments or no arguments
|
115
|
+
b.arity == 1 ? b.call(ret) : (b.arity == 0 ? b.call : b.call(*ret))
|
116
|
+
end
|
117
|
+
|
118
|
+
# A callback has been found and called, return true
|
119
|
+
return true
|
120
|
+
end
|
121
|
+
|
122
|
+
# No callback, do nothing
|
123
|
+
return nil
|
124
|
+
end
|
125
|
+
|
126
|
+
# Blocking method that wait on the @responses table an answer
|
127
|
+
def recv(key, nb_out)
|
128
|
+
begin
|
129
|
+
@replock.lock
|
130
|
+
r = @responses[key] ||= Queue.new
|
131
|
+
@replock.unlock
|
132
|
+
while rep = r.pop
|
133
|
+
if rep[1] == nb_out # On check ke c'est bien la réponse que l'on attend
|
134
|
+
|
135
|
+
# Call the callback
|
136
|
+
if block_given?
|
137
|
+
yield(rep[0])
|
138
|
+
end
|
139
|
+
|
140
|
+
return rep[0]
|
141
|
+
end
|
142
|
+
if rep[1] > nb_out
|
143
|
+
return nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
rescue Exception => e
|
147
|
+
if @close_after_timeout == true
|
148
|
+
stop_service
|
149
|
+
sleep 1
|
150
|
+
raise e
|
151
|
+
else
|
152
|
+
raise e
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class CustomLogger
|
4
|
+
attr_accessor :level, :history
|
5
|
+
def initialize
|
6
|
+
@history = []
|
7
|
+
end
|
8
|
+
def info(msg)
|
9
|
+
@history << msg
|
10
|
+
end
|
11
|
+
alias :error :info
|
12
|
+
alias :warn :info
|
13
|
+
alias :debug :info
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :brb_logger do
|
17
|
+
before(:each) do
|
18
|
+
@original_logger = BrB.logger
|
19
|
+
end
|
20
|
+
|
21
|
+
after(:each) do
|
22
|
+
BrB.logger = @original_logger
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should be assigned a default logger' do
|
26
|
+
BrB.logger.should_not be_nil
|
27
|
+
BrB.logger.class.should == Logger
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should be possible to use a custom logger' do
|
31
|
+
BrB.logger = CustomLogger.new
|
32
|
+
BrB.logger.info('foo')
|
33
|
+
BrB.logger.history.last.should == 'foo'
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe :brb_massive_usage do
|
4
|
+
before(:all) do
|
5
|
+
@brb = BrB::Service
|
6
|
+
@brb.stop_service
|
7
|
+
@brb_test = BrBTest.new
|
8
|
+
open_service(@brb_test)
|
9
|
+
@clients = []
|
10
|
+
20.times do
|
11
|
+
@clients << connect_to_the_service(self, @brb.uri) do |type, tunnel|
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def random_client
|
17
|
+
@clients[rand(@clients.size)]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Start the service
|
21
|
+
it "should the service be started" do
|
22
|
+
@clients.each do |cl|
|
23
|
+
cl.should_not be_nil
|
24
|
+
cl.active?.should be_true
|
25
|
+
cl.uri.should == @brb.uri
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should works with massive simple messaging" do
|
30
|
+
nb_call_before = @brb_test.nb_call || 0
|
31
|
+
nb_call_to_do = 500
|
32
|
+
|
33
|
+
@clients.each do |cl|
|
34
|
+
nb_call_to_do.times do
|
35
|
+
cl.noarg
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
sleep 5
|
40
|
+
# Wait a little in order to be sure all the stack is processed
|
41
|
+
@brb_test.last_call.should == :noarg
|
42
|
+
@brb_test.nb_call.should == (nb_call_to_do * @clients.size) + nb_call_before
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should works with massive callbacks" do
|
46
|
+
block_called = 0
|
47
|
+
nb_callbacks = 1000
|
48
|
+
nb_callbacks.times do |i|
|
49
|
+
random_client.return_same_value(i) do |callback_return_value|
|
50
|
+
callback_return_value.should == i
|
51
|
+
block_called += 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
sleep 2
|
56
|
+
# Wait a little in order to be sure the method is called
|
57
|
+
@brb_test.last_call.should == :return_same_value
|
58
|
+
block_called.should == nb_callbacks
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should works with massive simple messaging including blocking messaging and callbacks" do
|
62
|
+
nb_call_before = @brb_test.nb_call || 0
|
63
|
+
nb_call_to_do = 500
|
64
|
+
nb_call_blocking_to_do = 50
|
65
|
+
|
66
|
+
t = Thread.new do
|
67
|
+
@clients.each do |cl|
|
68
|
+
nb_call_blocking_to_do.times do
|
69
|
+
val = Time.now.to_f
|
70
|
+
cl.return_same_value_block(val).should == val
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
block_called = 0
|
76
|
+
nb_callbacks = 1000
|
77
|
+
nb_callbacks.times do |i|
|
78
|
+
random_client.return_same_value(i) do |callback_return_value|
|
79
|
+
callback_return_value.should == i
|
80
|
+
block_called += 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
@clients.each do |cl|
|
86
|
+
nb_call_to_do.times do
|
87
|
+
cl.noarg
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
sleep 5
|
92
|
+
block_called.should == nb_callbacks
|
93
|
+
t.join
|
94
|
+
# Wait a little in order to be sure all the stack is processed
|
95
|
+
@brb_test.nb_call.should == nb_callbacks + (nb_call_to_do * @clients.size + nb_call_blocking_to_do * @clients.size) + nb_call_before
|
96
|
+
end
|
97
|
+
|
98
|
+
# Finally, stop the service
|
99
|
+
it "should stop the service after usage" do
|
100
|
+
@brb.stop_service
|
101
|
+
@brb.uri.should be_nil
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe :brb_service do
|
4
|
+
before(:all) do
|
5
|
+
@brb = BrB::Service
|
6
|
+
@brb.stop_service
|
7
|
+
@brb_test = BrBTest.new
|
8
|
+
open_service(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Start the service
|
12
|
+
it "should open a service on localhost:6200" do
|
13
|
+
@brb.uri.should_not be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
# Finally, stop the service
|
17
|
+
it "should stop the service" do
|
18
|
+
@brb.stop_service
|
19
|
+
@brb.uri.should be_nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should start again the service after a stop" do
|
23
|
+
open_service(self)
|
24
|
+
@brb.stop_service
|
25
|
+
open_service(self)
|
26
|
+
@brb.uri.should_not be_nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
$last_unregistered = nil
|
4
|
+
$last_registered = nil
|
5
|
+
|
6
|
+
describe :brb_tunnel do
|
7
|
+
before(:all) do
|
8
|
+
@brb = BrB::Service
|
9
|
+
@brb.stop_service
|
10
|
+
@brb_test = BrBTest.new
|
11
|
+
open_service(@brb_test)
|
12
|
+
@client = connect_to_the_service(self, @brb.uri) do |type, tunnel|
|
13
|
+
if type == :unregister
|
14
|
+
$last_unregistered = tunnel
|
15
|
+
elsif type == :register
|
16
|
+
$last_registered = tunnel
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Start the service
|
22
|
+
it "should the service be started" do
|
23
|
+
@client.should_not be_nil
|
24
|
+
@client.active?.should be_true
|
25
|
+
@client.uri.should == @brb.uri
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have get the register message" do
|
29
|
+
sleep 0.2 # Be sure to get the message
|
30
|
+
$last_registered.class.should == @client.class
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should correctly call simple distant method without args and without return" do
|
34
|
+
@client.noarg
|
35
|
+
sleep 0.2
|
36
|
+
# Wait a little in order to be sure the method is called
|
37
|
+
@brb_test.last_call.should == :noarg
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should correctly call simple distant method without args and without return multipe times" do
|
41
|
+
nb_call_before = @brb_test.nb_call
|
42
|
+
nb_call_to_do = 50
|
43
|
+
|
44
|
+
nb_call_to_do.times do
|
45
|
+
@client.noarg
|
46
|
+
end
|
47
|
+
sleep 0.2
|
48
|
+
# Wait a little in order to be sure the method is called
|
49
|
+
@brb_test.last_call.should == :noarg
|
50
|
+
@brb_test.nb_call.should == nb_call_to_do + nb_call_before
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should correctly call distant method with one argument" do
|
54
|
+
@client.very_long(:hello)
|
55
|
+
sleep 0.2
|
56
|
+
# Wait a little in order to be sure the method is called
|
57
|
+
@brb_test.last_args.should == [:hello]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should correctly call distant method with multiple arguments" do
|
61
|
+
args = [:one, :two, 3, "four"]
|
62
|
+
@client.fourargs(*args)
|
63
|
+
sleep 0.2
|
64
|
+
# Wait a little in order to be sure the method is called
|
65
|
+
@brb_test.last_args.should == args
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should correctly return arguments symbol value" do
|
69
|
+
@client.one_arg_with_return_block(:hello).should == :hello
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should correctly return arguments string value" do
|
73
|
+
@client.one_arg_with_return_block('hello').should == 'hello'
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should correctly return arguments Fixnum value" do
|
77
|
+
@client.one_arg_with_return_block(42).should == 42
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should correctly return arguments Float value" do
|
81
|
+
@client.one_arg_with_return_block(42.42).should == 42.42
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should correctly return arguments Table value" do
|
85
|
+
@client.one_arg_with_return_block([:one, :two, 3, "four"]).should == [:one, :two, 3, "four"]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should correctly return arguments Hash value" do
|
89
|
+
h = {:yoyo => :titi, "salut" => 45}
|
90
|
+
@client.one_arg_with_return_block(h).should == h
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should correctly return multiple values" do
|
94
|
+
r1, r2 = @client.return_same_value_twice_block(:ret, :ret2)
|
95
|
+
r1.should == :ret
|
96
|
+
r2.should == :ret2
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should dump to symbol undumpable value by using the proxy" do
|
100
|
+
@client.return_same_value_block(Thread.current).class.should == Symbol
|
101
|
+
@client.return_same_value_block(Thread.current).should == Thread.current.to_s.to_sym
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should transmit with success exception when blocking" do
|
105
|
+
e = nil
|
106
|
+
begin
|
107
|
+
@client.notavalidmeth_block
|
108
|
+
rescue Exception => e
|
109
|
+
end
|
110
|
+
e.should be_a NameError
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should use block as non blocking callback with return value" do
|
114
|
+
block_called = nil
|
115
|
+
@client.return_same_value(:arg) do |v|
|
116
|
+
v.should == :arg
|
117
|
+
block_called = true
|
118
|
+
end
|
119
|
+
sleep 0.2
|
120
|
+
# Wait a little in order to be sure the method is called
|
121
|
+
@brb_test.last_call.should == :return_same_value
|
122
|
+
block_called.should == true
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should correctly handle multiple values return with callbacks" do
|
126
|
+
block_called = nil
|
127
|
+
@client.return_same_value_twice(:ret, :ret2) do |r1, r2|
|
128
|
+
r1.should == :ret
|
129
|
+
r2.should == :ret2
|
130
|
+
block_called = true
|
131
|
+
end
|
132
|
+
sleep 0.2
|
133
|
+
# Wait a little in order to be sure the method is called
|
134
|
+
@brb_test.last_call.should == :return_same_value_twice
|
135
|
+
block_called.should == true
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should correctly handle no block args return with callbacks" do
|
139
|
+
block_called = nil
|
140
|
+
@client.return_same_value_twice(:ret, :ret2) do
|
141
|
+
block_called = true
|
142
|
+
end
|
143
|
+
sleep 0.2
|
144
|
+
# Wait a little in order to be sure the method is called
|
145
|
+
@brb_test.last_call.should == :return_same_value_twice
|
146
|
+
block_called.should == true
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should raise an exception when calling a blocking method with a callback" do
|
150
|
+
e = nil
|
151
|
+
begin
|
152
|
+
@client.return_same_value_block(:arg) do |v|
|
153
|
+
end
|
154
|
+
rescue Exception => e
|
155
|
+
end
|
156
|
+
e.should_not be_nil
|
157
|
+
end
|
158
|
+
|
159
|
+
# Finally, stop the service
|
160
|
+
it "should stop the service after usage" do
|
161
|
+
@brb.stop_service
|
162
|
+
@brb.uri.should be_nil
|
163
|
+
end
|
164
|
+
|
165
|
+
# Finally, stop the client tunnel
|
166
|
+
it "should stop the tunnel after usage" do
|
167
|
+
@client.stop_service
|
168
|
+
@client.active?.should_not be_true
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should have get the unregister message" do
|
172
|
+
sleep 0.2 # Be sure to get the message
|
173
|
+
$last_unregistered.class.should == @client.class
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
|
4
|
+
Thread.abort_on_exception = true
|
5
|
+
|
6
|
+
require File.dirname(__FILE__) + '/../init.rb'
|
7
|
+
|
8
|
+
def open_service(object, host = 'localhost', port = 6200)
|
9
|
+
BrB::Service.start_service(:object => object, :verbose => false, :host => host, :port => port)
|
10
|
+
end
|
11
|
+
|
12
|
+
def connect_to_the_service(object_exposed, uri, &block)
|
13
|
+
BrB::Tunnel.create(object_exposed, uri, :verbose => false, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
class BrBTest
|
17
|
+
attr_reader :last_call
|
18
|
+
attr_reader :last_args
|
19
|
+
attr_reader :nb_call
|
20
|
+
|
21
|
+
def increment_nb_call(call_name, *args)
|
22
|
+
@last_call = call_name
|
23
|
+
@last_args = args
|
24
|
+
@nb_call ||= 0
|
25
|
+
@nb_call += 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def very_long(ar)
|
29
|
+
increment_nb_call(:very_long, ar)
|
30
|
+
end
|
31
|
+
|
32
|
+
def fourargs(arg1, arg2, arg3, arg4)
|
33
|
+
increment_nb_call(:fourargs, arg1, arg2, arg3, arg4)
|
34
|
+
end
|
35
|
+
|
36
|
+
def noarg
|
37
|
+
increment_nb_call(:noarg)
|
38
|
+
end
|
39
|
+
|
40
|
+
def one_arg_with_return(ar)
|
41
|
+
increment_nb_call(:one_arg_with_return)
|
42
|
+
return ar
|
43
|
+
end
|
44
|
+
|
45
|
+
def return_same_value(val)
|
46
|
+
increment_nb_call(:return_same_value)
|
47
|
+
return val
|
48
|
+
end
|
49
|
+
|
50
|
+
def return_same_value_twice(val, val2)
|
51
|
+
increment_nb_call(:return_same_value_twice)
|
52
|
+
return val, val2
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vitobotta-brb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Guillaume Luccisano
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-06-26 00:00:00.000000000 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: eventmachine
|
17
|
+
requirement: &2156366080 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>'
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0.12'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2156366080
|
26
|
+
description: BrB is a simple, fully transparent and extremely fast interface for doing
|
27
|
+
simple distributed ruby and message passing
|
28
|
+
email: guillaume.luccisano@gmail.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- examples/simple_client.rb
|
34
|
+
- examples/simple_core.rb
|
35
|
+
- lib/brb/event_machine.rb
|
36
|
+
- lib/brb/exception.rb
|
37
|
+
- lib/brb/logger.rb
|
38
|
+
- lib/brb/request.rb
|
39
|
+
- lib/brb/service.rb
|
40
|
+
- lib/brb/tunnel/shared.rb
|
41
|
+
- lib/brb/tunnel.rb
|
42
|
+
- lib/brb.rb
|
43
|
+
- spec/brb/brb_logger_spec.rb
|
44
|
+
- spec/brb/brb_massive_usage_spec.rb
|
45
|
+
- spec/brb/brb_service_spec.rb
|
46
|
+
- spec/brb/brb_tunnel_spec.rb
|
47
|
+
- spec/spec_helper.rb
|
48
|
+
- CHANGELOG.rdoc
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- MIT-LICENSE
|
52
|
+
- Rakefile
|
53
|
+
- README.rdoc
|
54
|
+
- init.rb
|
55
|
+
has_rdoc: true
|
56
|
+
homepage: http://github.com/kwi/BrB
|
57
|
+
licenses: []
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 1.3.4
|
74
|
+
requirements:
|
75
|
+
- eventmachine
|
76
|
+
rubyforge_project: vitobotta-brb
|
77
|
+
rubygems_version: 1.6.2
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: BrB is a simple, fully transparent and extremely fast interface for doing
|
81
|
+
simple distributed ruby
|
82
|
+
test_files: []
|