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,144 @@
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
+ class Address
23
+ # +--+----+
24
+ # | 2| 4 |
25
+ # +--+----+
26
+ # port network byte order
27
+ # IPv4 address
28
+ #
29
+ # +--+----------------+
30
+ # | 2| 16 |
31
+ # +--+----------------+
32
+ # port network byte order
33
+ # IPv6 address
34
+ #
35
+
36
+ test = Socket.pack_sockaddr_in(0,'0.0.0.0')
37
+ if test[0] == "\0"[0] || test[1] == "\0"[0]
38
+ # Linux
39
+ def initialize(host, port)
40
+ raw = Socket.pack_sockaddr_in(port, host)
41
+ family = raw.unpack('S')[0]
42
+ if family == Socket::AF_INET
43
+ @serial = raw[2,6]
44
+ elsif family == Socket::AF_INET6
45
+ @serial = raw[2,2] + raw[8,16]
46
+ else
47
+ raise "Unknown address family: #{family}"
48
+ end
49
+ end
50
+ else
51
+ # BSD
52
+ def initialize(host, port)
53
+ raw = Socket.pack_sockaddr_in(port, host)
54
+ family = raw.unpack('CC')[1]
55
+ if family == Socket::AF_INET
56
+ @serial = raw[2,6]
57
+ elsif family == Socket::AF_INET6
58
+ @serial = raw[2,2] + raw[8,16]
59
+ else
60
+ raise "Unknown address family: #{family}"
61
+ end
62
+ end
63
+ end
64
+
65
+ def host
66
+ unpack[0]
67
+ end
68
+
69
+ def port
70
+ unpack[1]
71
+ end
72
+
73
+ def connectable?
74
+ port != 0
75
+ end
76
+
77
+ def sockaddr
78
+ Address.parse_sockaddr(@serial)
79
+ end
80
+
81
+ def unpack
82
+ Address.parse(@serial)
83
+ end
84
+
85
+ def self.parse_sockaddr(raw)
86
+ if raw.length == 6
87
+ addr = Socket.pack_sockaddr_in(0, '0.0.0.0')
88
+ addr[2,6] = raw[0,6]
89
+ else
90
+ addr = Socket.pack_sockaddr_in(0, '::')
91
+ addr[2,2] = raw[0,2]
92
+ addr[8,16] = raw[2,16]
93
+ end
94
+ addr
95
+ end
96
+
97
+ def self.parse(raw)
98
+ Socket.unpack_sockaddr_in(parse_sockaddr(raw)).reverse
99
+ end
100
+
101
+ def self.load(raw)
102
+ Address.new *parse(raw)
103
+ end
104
+
105
+ def dump
106
+ @serial
107
+ end
108
+
109
+ def to_msgpack(out = '')
110
+ @serial.to_msgpack(out)
111
+ end
112
+
113
+ def to_s
114
+ unpack.join(':')
115
+ end
116
+
117
+ def to_a
118
+ unpack
119
+ end
120
+
121
+ def <=>(o)
122
+ dump <=> o.dump
123
+ end
124
+
125
+ def inspect
126
+ "#<#{self.class} #{to_s} @serial=#{@serial.inspect}>"
127
+ end
128
+
129
+ def eql?(o)
130
+ o.class == Address && dump.eql?(o.dump)
131
+ end
132
+
133
+ def hash
134
+ dump.hash
135
+ end
136
+
137
+ def ==(o)
138
+ eql?(o)
139
+ end
140
+ end
141
+
142
+
143
+ end
144
+ end
@@ -0,0 +1,80 @@
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
+ # Client is usable for RPC client.
23
+ # Note that SessionPool includes LoopUtil.
24
+ class Client < Session
25
+ # 1. initialize(builder, address, loop = Loop.new)
26
+ # 2. initialize(host, port, loop = Loop.new)
27
+ #
28
+ # Creates a client.
29
+ def initialize(arg1, arg2, arg3=nil)
30
+ # 1.
31
+ if arg1.respond_to?(:build_transport)
32
+ builder = arg1
33
+ address = arg2
34
+ loop = arg3 || Loop.new
35
+ else
36
+ # 2.
37
+ builder = TCPTransport.new
38
+ address = Address.new(arg1, arg2)
39
+ loop = arg3 || Loop.new
40
+ end
41
+
42
+ super(builder, address, loop)
43
+
44
+ @timer = Timer.new(1, true, &method(:step_timeout))
45
+ loop.attach(@timer)
46
+ end
47
+
48
+ # call-seq:
49
+ # Client.open(arg1, arg2, arg3=nil) {|client| }
50
+ #
51
+ # Creates a client, call the block and close the client.
52
+ def self.open(*args, &block)
53
+ c = new(*args)
54
+ begin
55
+ block.call(c)
56
+ ensure
57
+ c.close
58
+ end
59
+ end
60
+
61
+ def close
62
+ @timer.detach if @timer.attached?
63
+ super
64
+ end
65
+
66
+ include LoopUtil
67
+ end
68
+
69
+
70
+ #:nodoc:
71
+ class Client::Base
72
+ def initialize(*args)
73
+ @base = Client.new(*args)
74
+ end
75
+ attr_reader :base
76
+ end
77
+
78
+
79
+ end
80
+ 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
+ class AsyncResult
23
+ def initialize
24
+ @responder = nil
25
+ @sent = false
26
+ end
27
+
28
+ def result(retval, err = nil)
29
+ unless @sent
30
+ if @responder
31
+ @responder.result(retval, err)
32
+ else
33
+ @result = [retval, err]
34
+ end
35
+ @sent = true
36
+ end
37
+ nil
38
+ end
39
+
40
+ def error(err)
41
+ result(nil, err)
42
+ nil
43
+ end
44
+
45
+ def set_responder(res) #:nodoc:
46
+ @responder = res
47
+ if @sent && @result
48
+ @responder.result(*@result)
49
+ @result = nil
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ class ObjectDispatcher
56
+ def initialize(obj, accept = obj.public_methods)
57
+ @obj = obj
58
+ @accept = accept.map {|m| m.is_a?(Integer) ? m : m.to_s }
59
+ end
60
+
61
+ def dispatch_request(session, method, param, responder)
62
+ begin
63
+ sent = false
64
+ early_result = nil
65
+ result = forward_method(session, method, param) do |result_|
66
+ unless result_.is_a?(AsyncResult)
67
+ responder.result(result_)
68
+ sent = true
69
+ end
70
+ early_result = result_
71
+ end
72
+
73
+ # FIXME on NoMethodError
74
+ # res.error(NO_METHOD_ERROR); return
75
+
76
+ # FIXME on ArgumentError
77
+ # res.error(ArgumentError); return
78
+
79
+ rescue
80
+ responder.error($!.to_s)
81
+ return
82
+ end
83
+
84
+ if early_result.is_a?(AsyncResult)
85
+ early_result.set_responder(responder)
86
+ elsif sent
87
+ return
88
+ elsif result.is_a?(AsyncResult)
89
+ result.set_responder(responder)
90
+ else
91
+ responder.result(result)
92
+ end
93
+ end
94
+
95
+ def dispatch_notify(session, method, param)
96
+ forward_method(session, method, param)
97
+ rescue
98
+ end
99
+
100
+ private
101
+ def forward_method(session, method, param, &block)
102
+ unless @accept.include?(method)
103
+ raise NoMethodError, "method `#{method}' is not accepted"
104
+ end
105
+ @obj.send(method, *param, &block)
106
+ end
107
+ end
108
+
109
+
110
+ end
111
+ end
@@ -0,0 +1,53 @@
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
+ class Error < StandardError
23
+ end
24
+
25
+ class RPCError < Error
26
+ def initialize(msg)
27
+ super(msg)
28
+ end
29
+ end
30
+
31
+ class RemoteError < RPCError
32
+ def initialize(msg, result = nil)
33
+ super(msg)
34
+ @result = result
35
+ end
36
+ attr_reader :result
37
+ end
38
+
39
+ class TimeoutError < Error
40
+ def initialize(msg = "request timed out")
41
+ super
42
+ end
43
+ end
44
+
45
+ class ConnectError < TimeoutError
46
+ def initialize(msg = "connect failed")
47
+ super
48
+ end
49
+ end
50
+
51
+
52
+ end
53
+ end
@@ -0,0 +1,116 @@
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
+ # Future describes result of remote procedure call that is initially not known,
23
+ # because it is not yet received.
24
+ # You can wait and get the result with get method.
25
+ class Future
26
+ def initialize(session, loop, callback = nil) #:nodoc:
27
+ @timeout = session.timeout
28
+ @loop = loop
29
+ @callback_handler = callback
30
+ @error_handler = nil
31
+ @result_handler = nil
32
+ @set = false
33
+ @error = nil
34
+ @result = nil
35
+ end
36
+ attr_reader :loop
37
+ attr_accessor :result, :error
38
+
39
+ # Wait for receiving result of remote procedure call and returns its result.
40
+ # If the remote method raises error, then this method raises RemoteError.
41
+ # If the remote procedure call failed with timeout, this method raises TimeoutError.
42
+ # Otherwise this method returns the result of remote method.
43
+ def get
44
+ join
45
+ if error.nil?
46
+ if @result_handler
47
+ return @result_handler.call(@result)
48
+ else
49
+ return @result
50
+ end
51
+ end
52
+ if @error_handler
53
+ return @error_handler.call(self)
54
+ else
55
+ raise @error if @error.is_a?(Error)
56
+ raise RemoteError.new(@error, @result)
57
+ end
58
+ end
59
+
60
+ # Wait for receiving result of remote procedure call.
61
+ # This method returns self.
62
+ # If a callback method is attached, it will be called.
63
+ def join
64
+ until @set
65
+ @loop.run_once
66
+ end
67
+ self
68
+ end
69
+
70
+ # call-seq:
71
+ # attach_callback {|future| }
72
+ #
73
+ # Attaches a callback method that is called when the result of remote method is received.
74
+ def attach_callback(proc = nil, &block)
75
+ @callback_handler = proc || block
76
+ if @callback_handler.arity == 2
77
+ # FIXME backward compatibility
78
+ handler = @callback_handler
79
+ @callback_handler = Proc.new {|future|
80
+ handler.call(future.error, future.result)
81
+ }
82
+ end
83
+ end
84
+
85
+ # For IDL
86
+ def attach_error_handler(proc = nil, &block) #:nodoc:
87
+ @error_handler = proc || block
88
+ end
89
+
90
+ # For IDL
91
+ def attach_result_handler(proc = nil, &block) #:nodoc:
92
+ @result_handler = proc || block
93
+ end
94
+
95
+ def set_result(err, res) #:nodoc:
96
+ @error = err
97
+ @result = res
98
+ if @callback_handler
99
+ @callback_handler.call(self)
100
+ end
101
+ @set = true
102
+ end
103
+
104
+ def step_timeout #:nodoc:
105
+ if @timeout < 1
106
+ true
107
+ else
108
+ @timeout -= 1
109
+ false
110
+ end
111
+ end
112
+ end
113
+
114
+
115
+ end
116
+ end