msgpack-rpc 0.3.0 → 0.4.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.
@@ -0,0 +1,87 @@
1
+ #
2
+ # MessagePack-RPC for Ruby
3
+ #
4
+ # Copyright (C) 2010 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module MessagePack
19
+ module RPC
20
+
21
+
22
+ Loop = Rev::Loop
23
+
24
+
25
+ module LoopUtil
26
+ attr_reader :loop
27
+
28
+ class Timer < Rev::TimerWatcher
29
+ def initialize(interval, repeating, &block)
30
+ @block = block
31
+ super(interval, repeating)
32
+ end
33
+ def on_timer
34
+ @block.call
35
+ end
36
+ end
37
+
38
+ def start_timer(interval, repeating, &block)
39
+ @loop.attach Timer.new(interval, repeating, &block)
40
+ end
41
+
42
+ class TaskQueue < Rev::AsyncWatcher
43
+ def initialize
44
+ @queue = []
45
+ super
46
+ end
47
+
48
+ def push(task)
49
+ @queue.push(task)
50
+ signal
51
+ end
52
+
53
+ def on_signal
54
+ while task = @queue.shift
55
+ begin
56
+ task.call
57
+ rescue
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def submit(task = nil, &block)
64
+ task ||= block
65
+ unless @queue
66
+ @queue = TaskQueue.new
67
+ @loop.attach(@queue)
68
+ end
69
+ @queue.push(task)
70
+ end
71
+
72
+ def run
73
+ @loop.run
74
+ end
75
+
76
+ def stop
77
+ @queue.detach if @queue && @queue.attached?
78
+ @loop.stop
79
+ # attach dummy timer
80
+ @loop.attach Rev::TimerWatcher.new(0, false)
81
+ nil
82
+ end
83
+ end
84
+
85
+
86
+ end
87
+ end
@@ -0,0 +1,31 @@
1
+ #
2
+ # MessagePack-RPC for Ruby
3
+ #
4
+ # Copyright (C) 2010 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module MessagePack
19
+ module RPC
20
+
21
+
22
+ REQUEST = 0 # [0, msgid, method, param]
23
+ RESPONSE = 1 # [1, msgid, error, result]
24
+ NOTIFY = 2 # [2, method, param]
25
+
26
+ NO_METHOD_ERROR = 0x01;
27
+ ARGUMENT_ERROR = 0x02;
28
+
29
+
30
+ end
31
+ end
@@ -0,0 +1,111 @@
1
+ #
2
+ # MessagePack-RPC for Ruby
3
+ #
4
+ # Copyright (C) 2010 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module MessagePack
19
+ module RPC
20
+
21
+
22
+ # Server is usable for RPC server.
23
+ # Note that Server is a SessionPool.
24
+ class Server < SessionPool
25
+ # 1. initialize(builder, loop = Loop.new)
26
+ # 2. initialize(loop = Loop.new)
27
+ def initialize(arg1=nil, arg2=nil)
28
+ super(arg1, arg2)
29
+ @dispatcher = nil
30
+ @listeners = []
31
+ end
32
+
33
+ def serve(obj, accept = obj.public_methods)
34
+ @dispatcher = ObjectDispatcher.new(obj, accept)
35
+ self
36
+ end
37
+
38
+ # 1. listen(listener, obj = nil, accept = obj.public_methods)
39
+ # 2. listen(host, port, obj = nil, accept = obj.public_methods)
40
+ def listen(arg1, arg2 = nil, arg3 = nil, arg4 = nil)
41
+ if arg1.respond_to?(:listen)
42
+ # 1.
43
+ listener = arg1
44
+ obj = arg2
45
+ accept = arg3 || obj.public_methods
46
+ else
47
+ # 2.
48
+ listener = TCPServerTransport.new(Address.new(arg1,arg2))
49
+ obj = arg3
50
+ accept = arg4 || obj.public_methods
51
+ end
52
+
53
+ unless obj.nil?
54
+ serve(obj, accept)
55
+ end
56
+
57
+ listener.listen(self)
58
+ @listeners.push(listener)
59
+ nil
60
+ end
61
+
62
+ def close
63
+ @listeners.reject! {|listener|
64
+ listener.close
65
+ true
66
+ }
67
+ super
68
+ end
69
+
70
+ # from ServerTransport
71
+ def on_request(sendable, msgid, method, param) #:nodoc:
72
+ responder = Responder.new(sendable, msgid)
73
+ @dispatcher.dispatch_request(self, method, param, responder)
74
+ end
75
+
76
+ # from ServerTransport
77
+ def on_notify(method, param) #:nodoc:
78
+ @dispatcher.dispatch_notify(self, method, param)
79
+ end
80
+ end
81
+
82
+
83
+ class Responder
84
+ def initialize(sendable, msgid)
85
+ @sendable = sendable # send_message method is required
86
+ @msgid = msgid
87
+ end
88
+
89
+ def result(retval, err = nil)
90
+ data = [RESPONSE, @msgid, err, retval].to_msgpack
91
+ @sendable.send_data(data)
92
+ end
93
+
94
+ def error(err, retval = nil)
95
+ result(retval, err)
96
+ end
97
+ end
98
+
99
+
100
+ #:nodoc:
101
+ class Server::Base
102
+ def initialize(*args)
103
+ @base = Server.new(*args)
104
+ @base.serve(self)
105
+ end
106
+ attr_reader :base
107
+ end
108
+
109
+
110
+ end
111
+ end
@@ -0,0 +1,157 @@
1
+ #
2
+ # MessagePack-RPC for Ruby
3
+ #
4
+ # Copyright (C) 2010 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module MessagePack
19
+ module RPC
20
+
21
+
22
+ # Session is a abstract class corresponds with a remote host.
23
+ # You can call remote method using call, call_async, callback or notify method.
24
+ class Session
25
+ def initialize(builder, address, loop)
26
+ @address = address
27
+ @loop = loop
28
+ @reqtable = {}
29
+ @timeout = 10 # FIXME default timeout time
30
+ @seqid = 0
31
+ @transport = builder.build_transport(self, address)
32
+ end
33
+ attr_reader :loop, :address
34
+
35
+ # Sets and gets timeout in seconds.
36
+ attr_accessor :timeout
37
+
38
+ # backward compatibility
39
+ def port #:nodoc:
40
+ @address.port;
41
+ end
42
+
43
+ # backward compatibility
44
+ def host #:nodoc:
45
+ @address.host;
46
+ end
47
+
48
+ # call-seq:
49
+ # call(symbol, *args) -> result of remote method
50
+ #
51
+ # Calls remote method.
52
+ # This method is same as call_async(method, *args).get
53
+ def call(method, *args)
54
+ call_async(method, *args).get
55
+ end
56
+
57
+ # call-seq:
58
+ # call_async(symbol, *args) -> Future
59
+ #
60
+ # Calls remote method asynchronously.
61
+ # This method is non-blocking and returns Future.
62
+ def call_async(method, *args)
63
+ future = send_request(method, args)
64
+ end
65
+
66
+ # backward compatibility
67
+ alias send call_async #:nodoc:
68
+
69
+ # call-seq:
70
+ # callback(symbol, *args) {|future| }
71
+ #
72
+ # Calls remote method asynchronously.
73
+ # The callback method is called with Future when the result is reached.
74
+ # This method is same as call_async(method, *args).attach_callback {|future| }
75
+ def callback(method, *args, &block)
76
+ future = send_request(method, args)
77
+ future.attach_callback(block)
78
+ future
79
+ end
80
+
81
+ # call-seq:
82
+ # notify(symbol, *args) -> nil
83
+ #
84
+ # Calls remote method with NOTIFY protocol.
85
+ # It doesn't require server to return results.
86
+ # This method is non-blocking and returns nil.
87
+ def notify(method, *args)
88
+ send_notify(method, args)
89
+ nil
90
+ end
91
+
92
+ # Closes underlaying Transport and destroy resources.
93
+ def close
94
+ @transport.close
95
+ @reqtable = {}
96
+ @seqid = 0
97
+ self
98
+ end
99
+
100
+ # from ClientTransport
101
+ def on_response(sock, msgid, error, result) #:nodoc:
102
+ if future = @reqtable.delete(msgid)
103
+ future.set_result(error, result)
104
+ end
105
+ end
106
+
107
+ # from ClientTransport
108
+ def on_connect_failed #:nodoc:
109
+ @reqtable.reject! {|msgid, future|
110
+ begin
111
+ future.set_result ConnectError.new, nil
112
+ rescue
113
+ end
114
+ true
115
+ }
116
+ nil
117
+ end
118
+
119
+ # from Client, SessionPool
120
+ def step_timeout #:nodoc:
121
+ timedout = []
122
+ @reqtable.reject! {|msgid, future|
123
+ if future.step_timeout
124
+ timedout.push(future)
125
+ true
126
+ end
127
+ }
128
+ timedout.each {|future|
129
+ begin
130
+ future.set_result TimeoutError.new, nil
131
+ rescue
132
+ end
133
+ }
134
+ !@reqtable.empty?
135
+ end
136
+
137
+ private
138
+ def send_request(method, param)
139
+ method = method.to_s
140
+ msgid = @seqid
141
+ @seqid += 1; if @seqid >= 1<<31 then @seqid = 0 end
142
+ data = [REQUEST, msgid, method, param].to_msgpack
143
+ @transport.send_data(data)
144
+ @reqtable[msgid] = Future.new(self, @loop)
145
+ end
146
+
147
+ def send_notify(method, param)
148
+ method = method.to_s
149
+ data = [NOTIFY, method, param].to_msgpack
150
+ @transport.send_data(data)
151
+ nil
152
+ end
153
+ end
154
+
155
+
156
+ end
157
+ end
@@ -0,0 +1,91 @@
1
+ #
2
+ # MessagePack-RPC for Ruby
3
+ #
4
+ # Copyright (C) 2010 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module MessagePack
19
+ module RPC
20
+
21
+
22
+ # SessionPool is usable for connection pooling.
23
+ # You can get pooled Session using get_session method.
24
+ # Note that SessionPool includes LoopUtil.
25
+ class SessionPool
26
+ # 1. initialize(builder, loop = Loop.new)
27
+ # 2. initialize(loop = Loop.new)
28
+ #
29
+ # Creates an SessionPool.
30
+ def initialize(arg1=nil, arg2=nil)
31
+ if arg1.respond_to?(:build_transport)
32
+ # 1.
33
+ builder = arg1
34
+ loop = arg2 || Loop.new
35
+ else
36
+ # 2.
37
+ builder = TCPTransport.new
38
+ loop = arg1 || Loop.new
39
+ end
40
+
41
+ @builder = builder
42
+ @loop = loop
43
+ @pool = {}
44
+
45
+ @timer = Timer.new(1, true, &method(:step_timeout))
46
+ loop.attach(@timer)
47
+ end
48
+
49
+ # 1. get_session(address)
50
+ # 2. get_session(host, port)
51
+ #
52
+ # Returns pooled Session.
53
+ # If there are no pooled Session for the specified address,
54
+ # this method creates the Session and pools it.
55
+ def get_session(arg1, arg2=nil)
56
+ if arg2.nil?
57
+ # 1.
58
+ addr = arg1
59
+ else
60
+ # 2.
61
+ host = arg1
62
+ port = arg2
63
+ addr = Address.new(host, port)
64
+ end
65
+
66
+ @pool[addr] ||= Session.new(@builder, addr, @loop)
67
+ end
68
+
69
+ # backward compatibility
70
+ alias get_session_addr get_session #:nodoc:
71
+
72
+ def close
73
+ @pool.reject! {|addr, s|
74
+ s.close
75
+ true
76
+ }
77
+ @timer.detach if @timer.attached?
78
+ nil
79
+ end
80
+
81
+ include LoopUtil
82
+
83
+ private
84
+ def step_timeout
85
+ @pool.each_pair {|addr,s| s.step_timeout }
86
+ end
87
+ end
88
+
89
+
90
+ end
91
+ end