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,48 @@
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
+ module MessageReceiver
23
+ def on_message(msg, *ctx)
24
+ case msg[0]
25
+ when REQUEST
26
+ on_request(msg[1], msg[2], msg[3], *ctx)
27
+ when RESPONSE
28
+ on_response(msg[1], msg[2], msg[3], *ctx)
29
+ when NOTIFY
30
+ on_notify(msg[1], msg[2], *ctx)
31
+ else
32
+ raise RPCError.new("unknown message type #{msg[0]}")
33
+ end
34
+ end
35
+
36
+ #def on_request(msgid, method, param)
37
+ #end
38
+
39
+ #def on_notify(method, param)
40
+ #end
41
+
42
+ #def on_response(msgid, error, result)
43
+ #end
44
+ end
45
+
46
+
47
+ end
48
+ end
@@ -0,0 +1,242 @@
1
+ #
2
+ # MessagePack-RPC for Ruby TCP transport
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 TCPTransport
23
+ def initialize
24
+ @reconnect_limit = 5 # FIXME default reconnect_limit
25
+ end
26
+
27
+ attr_accessor :reconnect_limit
28
+
29
+ # Transport interface
30
+ def build_transport(session, address)
31
+ TCPClientTransport.new(session, address, @reconnect_limit)
32
+ end
33
+
34
+ class BasicSocket < Rev::TCPSocket
35
+ def initialize(io)
36
+ super(io)
37
+ @pac = MessagePack::Unpacker.new
38
+ end
39
+
40
+ # from Rev::TCPSocket
41
+ def on_read(data)
42
+ @pac.feed(data)
43
+ @pac.each {|obj|
44
+ on_message(obj)
45
+ }
46
+ end
47
+
48
+ include MessageReceiver
49
+ end
50
+ end
51
+
52
+
53
+ class TCPClientTransport
54
+ def initialize(session, address, reconnect_limit)
55
+ @session = session
56
+ @address = address
57
+
58
+ @pending = ""
59
+ @sockpool = []
60
+ @connecting = 0
61
+ @reconnect_limit = reconnect_limit
62
+ end
63
+
64
+ # ClientTransport interface
65
+ def send_data(data)
66
+ if @sockpool.empty?
67
+ if @connecting == 0
68
+ try_connect
69
+ @connecting = 1
70
+ end
71
+ @pending << data
72
+ else
73
+ # FIXME pesudo connection load balance
74
+ # sock = @sockpool.choice
75
+ sock = @sockpool.first
76
+ sock.send_data(data)
77
+ end
78
+ end
79
+
80
+ # ClientTransport interface
81
+ def close
82
+ @sockpool.reject! {|sock|
83
+ sock.detach if sock.attached?
84
+ sock.close
85
+ true
86
+ }
87
+ @sockpool = []
88
+ @connecting = 0
89
+ @pending = ""
90
+ self
91
+ end
92
+
93
+ # from TCPClientTransport::ClientSocket::on_connect
94
+ def on_connect(sock)
95
+ @sockpool.push(sock)
96
+ sock.send_pending(@pending)
97
+ @pending = ""
98
+ @connecting = 0
99
+ end
100
+
101
+ # from TCPClientTransport::ClientSocket::on_connect_failed
102
+ def on_connect_failed(sock)
103
+ if @connecting < @reconnect_limit
104
+ try_connect
105
+ @connecting += 1
106
+ else
107
+ @connecting = 0
108
+ @pending = ""
109
+ @deflate.reset if @deflate
110
+ @session.on_connect_failed
111
+ end
112
+ end
113
+
114
+ # from TCPClientTransport::ClientSocket::on_close
115
+ def on_close(sock)
116
+ @sockpool.delete(sock)
117
+ end
118
+
119
+ private
120
+ def try_connect
121
+ host, port = *@address
122
+ sock = ClientSocket.connect(host, port, self, @session) # async connect
123
+ @session.loop.attach(sock)
124
+ end
125
+
126
+ class ClientSocket < TCPTransport::BasicSocket
127
+ def initialize(io, transport, session)
128
+ super(io)
129
+ @t = transport
130
+ @s = session
131
+ end
132
+
133
+ # MessageSendable interface
134
+ def send_data(data)
135
+ write data
136
+ end
137
+
138
+ # from TCPClientTransport::on_connect
139
+ def send_pending(data)
140
+ write data
141
+ end
142
+
143
+ # MessageReceiver interface
144
+ def on_request(msgid, method, param)
145
+ raise RPCError.new("request message on client session")
146
+ end
147
+
148
+ # MessageReceiver interface
149
+ def on_notify(method, param)
150
+ raise RPCError.new("notify message on client session")
151
+ end
152
+
153
+ # MessageReceiver interface
154
+ def on_response(msgid, error, result)
155
+ @s.on_response(self, msgid, error, result)
156
+ end
157
+
158
+ # from Rev::TCPSocket
159
+ def on_connect
160
+ return unless @t
161
+ @t.on_connect(self)
162
+ end
163
+
164
+ # from Rev::TCPSocket
165
+ def on_connect_failed
166
+ return unless @t
167
+ @t.on_connect_failed(self)
168
+ rescue
169
+ nil
170
+ end
171
+
172
+ # from Rev::TCPSocket
173
+ def on_close
174
+ return unless @t
175
+ @t.on_close(self)
176
+ @t = nil
177
+ @s = nil
178
+ rescue
179
+ nil
180
+ end
181
+ end
182
+ end
183
+
184
+
185
+ class TCPServerTransport
186
+ def initialize(address)
187
+ @address = address
188
+ @lsock = nil
189
+ end
190
+
191
+ # ServerTransport interface
192
+ def listen(server)
193
+ @server = server
194
+ host, port = *@address.unpack
195
+ @lsock = Rev::TCPServer.new(host, port, ServerSocket, @server)
196
+ begin
197
+ @server.loop.attach(@lsock)
198
+ rescue
199
+ @lsock.close
200
+ raise
201
+ end
202
+ end
203
+
204
+ # ServerTransport interface
205
+ def close
206
+ return unless @lsock
207
+ @lsock.detach if @lsock.attached?
208
+ @lsock.close
209
+ end
210
+
211
+ private
212
+ class ServerSocket < TCPTransport::BasicSocket
213
+ def initialize(io, server)
214
+ super(io)
215
+ @server = server
216
+ end
217
+
218
+ # MessageSendable interface
219
+ def send_data(data)
220
+ write data
221
+ end
222
+
223
+ # MessageReceiver interface
224
+ def on_request(msgid, method, param)
225
+ @server.on_request(self, msgid, method, param)
226
+ end
227
+
228
+ # MessageReceiver interface
229
+ def on_notify(method, param)
230
+ @server.on_notify(method, param)
231
+ end
232
+
233
+ # MessageReceiver interface
234
+ def on_response(msgid, error, result)
235
+ raise RPCError.new("response message on server session")
236
+ end
237
+ end
238
+ end
239
+
240
+
241
+ end
242
+ end
@@ -0,0 +1,192 @@
1
+ #
2
+ # MessagePack-RPC for Ruby UDP transport
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 UDPTransport
23
+ def initialize
24
+ end
25
+
26
+ # Transport interface
27
+ def build_transport(session, address)
28
+ UDPClientTransport.new(session, address)
29
+ end
30
+
31
+ class BasicSocket < Rev::IOWatcher
32
+ def initialize(io)
33
+ super(io)
34
+ @io = io
35
+ end
36
+
37
+ attr_reader :io
38
+
39
+ def on_readable
40
+ begin
41
+ data, addr = @io.recvfrom(64*1024) # FIXME buffer size
42
+ rescue Errno::EAGAIN
43
+ return
44
+ end
45
+
46
+ # FIXME multiple objects in one message
47
+ obj = MessagePack.unpack(data)
48
+ on_message(obj, addr)
49
+ end
50
+
51
+ include MessageReceiver
52
+ end
53
+ end
54
+
55
+
56
+ class UDPClientTransport
57
+ def initialize(session, address)
58
+ io = UDPSocket.new
59
+ io.connect(*address)
60
+
61
+ begin
62
+ @sock = ClientSocket.new(io, session)
63
+ rescue
64
+ io.close
65
+ raise
66
+ end
67
+
68
+ begin
69
+ session.loop.attach(@sock)
70
+ rescue
71
+ @sock.close
72
+ raise
73
+ end
74
+ end
75
+
76
+ # ClientTransport interface
77
+ def send_data(data)
78
+ @sock.send_data(data)
79
+ end
80
+
81
+ # ClientTransport interface
82
+ def close
83
+ @sock.detach if @sock.attached?
84
+ @sock.close
85
+ end
86
+
87
+ private
88
+ class ClientSocket < UDPTransport::BasicSocket
89
+ def initialize(io, session)
90
+ super(io)
91
+ @s = session
92
+ end
93
+
94
+ # MessageSendable interface
95
+ def send_data(data)
96
+ @io.send(data, 0)
97
+ end
98
+
99
+ # MessageReceiver interface
100
+ def on_request(msgid, method, param, addr)
101
+ raise RPCError.new("request message on client session")
102
+ end
103
+
104
+ # MessageReceiver interface
105
+ def on_notify(method, param, addr)
106
+ raise RPCError.new("notify message on client session")
107
+ end
108
+
109
+ # MessageReceiver interface
110
+ def on_response(msgid, error, result, addr)
111
+ @s.on_response(self, msgid, error, result)
112
+ end
113
+ end
114
+ end
115
+
116
+
117
+ class UDPServerTransport
118
+ def initialize(address)
119
+ @address = address
120
+ @sock = nil
121
+ end
122
+
123
+ # ServerTransport interface
124
+ def listen(server)
125
+ @server = server
126
+ host, port = *@address.unpack
127
+ io = UDPSocket.new
128
+ io.bind(*@address)
129
+
130
+ begin
131
+ @sock = ServerSocket.new(io, @server)
132
+ rescue
133
+ io.close
134
+ raise
135
+ end
136
+
137
+ begin
138
+ @server.loop.attach(@sock)
139
+ rescue
140
+ @sock.close
141
+ raise
142
+ end
143
+ end
144
+
145
+ # ServerTransport interface
146
+ def close
147
+ return unless @lsock
148
+ @lsock.detach if @lsock.attached?
149
+ @lsock.close
150
+ end
151
+
152
+ private
153
+ class ServerSocket < UDPTransport::BasicSocket
154
+ def initialize(io, server)
155
+ super(io)
156
+ @server = server
157
+ end
158
+
159
+ # MessageReceiver interface
160
+ def on_request(msgid, method, param, addr)
161
+ sender = ResponseSender.new(@io, addr[3], addr[1])
162
+ @server.on_request(sender, msgid, method, param)
163
+ end
164
+
165
+ # MessageReceiver interface
166
+ def on_notify(method, param, addr)
167
+ @server.on_notify(method, param)
168
+ end
169
+
170
+ # MessageReceiver interface
171
+ def on_response(msgid, error, result, addr)
172
+ raise RPCError.new("response message on server session")
173
+ end
174
+ end
175
+
176
+ class ResponseSender
177
+ def initialize(io, host, port)
178
+ @io = io
179
+ @host = host
180
+ @port = port
181
+ end
182
+
183
+ # MessageSendable interface
184
+ def send_data(data)
185
+ @io.send(data, 0, @host, @port)
186
+ end
187
+ end
188
+ end
189
+
190
+
191
+ end
192
+ end