msgpack-rpc 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/ChangeLog +0 -0
- data/README +29 -0
- data/Rakefile +132 -0
- data/lib/msgpack/rpc.rb +436 -0
- data/test/msgpack_rpc_test.rb +224 -0
- data/test/test_helper.rb +3 -0
- metadata +92 -0
data/AUTHORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
FURUHASHI Sadayuki <frsyuki _at_ users.sourceforge.jp>
|
data/ChangeLog
ADDED
File without changes
|
data/README
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
= MessagePack-RPC
|
3
|
+
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
|
8
|
+
== Installation
|
9
|
+
|
10
|
+
=== Archive Installation
|
11
|
+
|
12
|
+
rake install
|
13
|
+
|
14
|
+
=== Gem Installation
|
15
|
+
|
16
|
+
gem install msgpack-rpc
|
17
|
+
|
18
|
+
|
19
|
+
== Features/Problems
|
20
|
+
|
21
|
+
|
22
|
+
== Synopsis
|
23
|
+
|
24
|
+
|
25
|
+
== Copyright
|
26
|
+
|
27
|
+
Author:: frsyuki <frsyuki@users.sourceforge.jp>
|
28
|
+
Copyright:: Copyright (c) 2009 frsyuki
|
29
|
+
License:: Apache License, Version 2.0
|
data/Rakefile
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
require 'rake/contrib/rubyforgepublisher'
|
9
|
+
require 'rake/contrib/sshpublisher'
|
10
|
+
require 'fileutils'
|
11
|
+
include FileUtils
|
12
|
+
|
13
|
+
NAME = "msgpack-rpc"
|
14
|
+
AUTHOR = "FURUHASHI Sadayuki"
|
15
|
+
EMAIL = "frsyuki _at_ users.sourceforge.jp"
|
16
|
+
DESCRIPTION = "RPC library using MessagePack, a ainary-based efficient data interchange format."
|
17
|
+
RUBYFORGE_PROJECT = "msgpack"
|
18
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
19
|
+
BIN_FILES = %w( )
|
20
|
+
VERS = "0.1.0"
|
21
|
+
|
22
|
+
#REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
|
23
|
+
REV = nil
|
24
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config']
|
25
|
+
RDOC_OPTS = [
|
26
|
+
'--title', "#{NAME} documentation",
|
27
|
+
"--charset", "utf-8",
|
28
|
+
"--opname", "index.html",
|
29
|
+
"--line-numbers",
|
30
|
+
"--main", "README",
|
31
|
+
"--inline-source",
|
32
|
+
]
|
33
|
+
|
34
|
+
task :default => [:test]
|
35
|
+
task :package => [:clean]
|
36
|
+
|
37
|
+
Rake::TestTask.new("test") do |t|
|
38
|
+
t.libs << "test"
|
39
|
+
t.pattern = "test/**/*_test.rb"
|
40
|
+
t.verbose = true
|
41
|
+
end
|
42
|
+
|
43
|
+
spec = Gem::Specification.new do |s|
|
44
|
+
s.name = NAME
|
45
|
+
s.version = VERS
|
46
|
+
s.platform = Gem::Platform::RUBY
|
47
|
+
#s.has_rdoc = true
|
48
|
+
s.extra_rdoc_files = ["README", "ChangeLog", "AUTHORS"]
|
49
|
+
s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
|
50
|
+
s.summary = DESCRIPTION
|
51
|
+
s.description = DESCRIPTION
|
52
|
+
s.author = AUTHOR
|
53
|
+
s.email = EMAIL
|
54
|
+
s.homepage = HOMEPATH
|
55
|
+
s.executables = BIN_FILES
|
56
|
+
s.rubyforge_project = RUBYFORGE_PROJECT
|
57
|
+
s.bindir = "bin"
|
58
|
+
s.require_path = "lib"
|
59
|
+
s.test_files = Dir["test/test_*.rb"]
|
60
|
+
|
61
|
+
s.add_dependency "msgpack", ">= 0.3.1"
|
62
|
+
s.add_dependency "rev", ">= 0.3.0"
|
63
|
+
#s.required_ruby_version = '>= 1.8.2'
|
64
|
+
|
65
|
+
s.files = %w(README ChangeLog Rakefile) +
|
66
|
+
Dir.glob("{bin,doc,test,lib,templates,generator,extras,website,script}/**/*") +
|
67
|
+
Dir.glob("ext/**/*.{h,c,rb}") +
|
68
|
+
Dir.glob("examples/**/*.rb") +
|
69
|
+
Dir.glob("tools/*.rb")
|
70
|
+
|
71
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
72
|
+
end
|
73
|
+
|
74
|
+
Rake::GemPackageTask.new(spec) do |p|
|
75
|
+
p.need_tar = true
|
76
|
+
p.gem_spec = spec
|
77
|
+
end
|
78
|
+
|
79
|
+
task :install do
|
80
|
+
name = "#{NAME}-#{VERS}.gem"
|
81
|
+
sh %{rake package}
|
82
|
+
sh %{sudo gem install pkg/#{name}}
|
83
|
+
end
|
84
|
+
|
85
|
+
task :uninstall => [:clean] do
|
86
|
+
sh %{sudo gem uninstall #{NAME}}
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
#Rake::RDocTask.new do |rdoc|
|
91
|
+
# rdoc.rdoc_dir = 'html'
|
92
|
+
# rdoc.options += RDOC_OPTS
|
93
|
+
# rdoc.template = "resh"
|
94
|
+
# #rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
95
|
+
# if ENV['DOC_FILES']
|
96
|
+
# rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
|
97
|
+
# else
|
98
|
+
# rdoc.rdoc_files.include('README', 'ChangeLog')
|
99
|
+
# rdoc.rdoc_files.include('lib/**/*.rb')
|
100
|
+
# rdoc.rdoc_files.include('ext/**/*.c')
|
101
|
+
# end
|
102
|
+
#end
|
103
|
+
|
104
|
+
desc "Publish to RubyForge"
|
105
|
+
task :rubyforge => [:rdoc, :package] do
|
106
|
+
require 'rubyforge'
|
107
|
+
Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, 'frsyuki').upload
|
108
|
+
end
|
109
|
+
|
110
|
+
desc 'Package and upload the release to rubyforge.'
|
111
|
+
task :release => [:clean, :package] do |t|
|
112
|
+
v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
|
113
|
+
abort "Versions don't match #{v} vs #{VERS}" unless v == VERS
|
114
|
+
pkg = "pkg/#{NAME}-#{VERS}"
|
115
|
+
|
116
|
+
rf = RubyForge.new
|
117
|
+
puts "Logging in"
|
118
|
+
rf.login
|
119
|
+
|
120
|
+
c = rf.userconfig
|
121
|
+
# c["release_notes"] = description if description
|
122
|
+
# c["release_changes"] = changes if changes
|
123
|
+
c["preformatted"] = true
|
124
|
+
|
125
|
+
files = [
|
126
|
+
"#{pkg}.tgz",
|
127
|
+
"#{pkg}.gem"
|
128
|
+
].compact
|
129
|
+
|
130
|
+
puts "Releasing #{NAME} v. #{VERS}"
|
131
|
+
rf.add_release RUBYFORGE_PROJECT, NAME, VERS, *files
|
132
|
+
end
|
data/lib/msgpack/rpc.rb
ADDED
@@ -0,0 +1,436 @@
|
|
1
|
+
#
|
2
|
+
# MessagePack RPC for Ruby
|
3
|
+
#
|
4
|
+
# Copyright (C) 2009 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
|
+
require 'msgpack'
|
19
|
+
require 'rev'
|
20
|
+
|
21
|
+
module MessagePack
|
22
|
+
module RPC
|
23
|
+
|
24
|
+
|
25
|
+
class Error < StandardError
|
26
|
+
end
|
27
|
+
|
28
|
+
class RPCError < Error
|
29
|
+
def initialize(msg)
|
30
|
+
super(msg)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class RemoteError < RPCError
|
35
|
+
def initialize(msg, result = nil)
|
36
|
+
super(msg)
|
37
|
+
@result = result
|
38
|
+
end
|
39
|
+
attr_reader :result
|
40
|
+
end
|
41
|
+
|
42
|
+
class TimeoutError < Error
|
43
|
+
def initialize
|
44
|
+
super("request timed out")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
class Responder
|
50
|
+
def initialize(socket, msgid)
|
51
|
+
@socket = socket
|
52
|
+
@msgid = msgid
|
53
|
+
end
|
54
|
+
|
55
|
+
def result(retval, err = nil)
|
56
|
+
@socket.send_response(@msgid, retval, err)
|
57
|
+
end
|
58
|
+
|
59
|
+
def error(err)
|
60
|
+
result(nil, err)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
REQUEST = 0
|
66
|
+
RESPONSE = 1
|
67
|
+
NOTIFY = 2
|
68
|
+
|
69
|
+
|
70
|
+
module RPCSocket
|
71
|
+
def session=(s)
|
72
|
+
@session = s
|
73
|
+
s.add_socket(self)
|
74
|
+
end
|
75
|
+
|
76
|
+
def on_message(msg)
|
77
|
+
if msg[0] == REQUEST
|
78
|
+
on_request(msg[1], msg[2], msg[3])
|
79
|
+
elsif msg[0] == RESPONSE
|
80
|
+
on_response(msg[1], msg[3], msg[2])
|
81
|
+
elsif msg[0] == REQUEST
|
82
|
+
on_notify(msg[1], msg[2])
|
83
|
+
else
|
84
|
+
raise RPCError.new("unknown message type #{msg[0]}")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def on_close
|
89
|
+
return unless @session
|
90
|
+
@session.on_close(self)
|
91
|
+
@session = nil
|
92
|
+
rescue
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def on_request(msgid, method, param)
|
97
|
+
return unless @session
|
98
|
+
@session.on_request(method, param, Responder.new(self,msgid))
|
99
|
+
end
|
100
|
+
|
101
|
+
def on_notify(method, param)
|
102
|
+
return unless @session
|
103
|
+
@session.on_notify(method, param)
|
104
|
+
end
|
105
|
+
|
106
|
+
def on_response(msgid, res, err)
|
107
|
+
return unless @session
|
108
|
+
@session.on_response(msgid, res, err)
|
109
|
+
end
|
110
|
+
|
111
|
+
def send_request(msgid, method, param)
|
112
|
+
send_message [REQUEST, msgid, method, param]
|
113
|
+
end
|
114
|
+
|
115
|
+
def send_response(msgid, retval, err)
|
116
|
+
send_message [RESPONSE, msgid, err, retval]
|
117
|
+
end
|
118
|
+
|
119
|
+
def send_notify(method, param)
|
120
|
+
send_message [NOTIFY, method, param]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
class RevSocket < ::Rev::TCPSocket
|
126
|
+
include RPCSocket
|
127
|
+
|
128
|
+
def initialize(*args)
|
129
|
+
@buffer = ''
|
130
|
+
@nread = 0
|
131
|
+
@mpac = MessagePack::Unpacker.new
|
132
|
+
super
|
133
|
+
end
|
134
|
+
|
135
|
+
def on_read(data)
|
136
|
+
@buffer << data
|
137
|
+
|
138
|
+
while true
|
139
|
+
@nread = @mpac.execute(@buffer, @nread)
|
140
|
+
|
141
|
+
if @mpac.finished?
|
142
|
+
msg = @mpac.data
|
143
|
+
|
144
|
+
@mpac.reset
|
145
|
+
@buffer.slice!(0, @nread)
|
146
|
+
@nread = 0
|
147
|
+
|
148
|
+
on_message(msg) # RPCSocket#on_message
|
149
|
+
|
150
|
+
next unless @buffer.empty?
|
151
|
+
end
|
152
|
+
|
153
|
+
break
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def send_message(msg)
|
158
|
+
write msg.to_msgpack
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
class ClientSession
|
164
|
+
|
165
|
+
class BasicRequest
|
166
|
+
def initialize(session, loop)
|
167
|
+
@error = nil
|
168
|
+
@result = nil
|
169
|
+
@session = session
|
170
|
+
@timeout = session.timeout
|
171
|
+
@loop = loop
|
172
|
+
end
|
173
|
+
attr_reader :loop
|
174
|
+
attr_accessor :result, :error
|
175
|
+
|
176
|
+
def call(err, res)
|
177
|
+
@error = err
|
178
|
+
@result = res
|
179
|
+
@session = nil
|
180
|
+
end
|
181
|
+
|
182
|
+
def join
|
183
|
+
while @session
|
184
|
+
@loop.run_once
|
185
|
+
end
|
186
|
+
self
|
187
|
+
end
|
188
|
+
|
189
|
+
def step_timeout
|
190
|
+
if @timeout < 1
|
191
|
+
true
|
192
|
+
else
|
193
|
+
@timeout -= 1
|
194
|
+
false
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
def initialize(loop)
|
201
|
+
@sock = nil
|
202
|
+
@reqtable = {}
|
203
|
+
@seqid = 0
|
204
|
+
@loop = loop
|
205
|
+
@timeout = 60 # FIXME default timeout time
|
206
|
+
end
|
207
|
+
attr_accessor :timeout
|
208
|
+
|
209
|
+
def add_socket(sock)
|
210
|
+
@sock = sock
|
211
|
+
end
|
212
|
+
|
213
|
+
def send(method, *args)
|
214
|
+
send_real(method, args, BasicRequest.new(self,@loop))
|
215
|
+
end
|
216
|
+
|
217
|
+
def callback(method, *args, &block)
|
218
|
+
send_real(method, args, block)
|
219
|
+
end
|
220
|
+
|
221
|
+
def call(method, *args)
|
222
|
+
req = send(method, *args)
|
223
|
+
req.join
|
224
|
+
if req.error
|
225
|
+
raise TimeoutError.new if req.error == :TimeoutError
|
226
|
+
raise RemoteError.new(req.error, req.result)
|
227
|
+
end
|
228
|
+
req.result
|
229
|
+
end
|
230
|
+
|
231
|
+
def notify(method, *args)
|
232
|
+
notify_real(method, args)
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
def on_response(msgid, result, error)
|
237
|
+
if req = @reqtable.delete(msgid)
|
238
|
+
req.call error, result
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def on_notify(method, param)
|
243
|
+
raise RPCError.new("unexpected notify message")
|
244
|
+
end
|
245
|
+
|
246
|
+
def on_request(method, param, res)
|
247
|
+
raise RPCError.new("unexpected request message")
|
248
|
+
end
|
249
|
+
|
250
|
+
def on_close(sock)
|
251
|
+
@sock = nil
|
252
|
+
end
|
253
|
+
|
254
|
+
def close
|
255
|
+
@sock.close if @sock
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
def step_timeout
|
260
|
+
reqs = []
|
261
|
+
@reqtable.reject! {|msgid, req|
|
262
|
+
if req.step_timeout
|
263
|
+
reqs.push req
|
264
|
+
end
|
265
|
+
}
|
266
|
+
reqs.each {|req| req.call :TimeoutError, nil }
|
267
|
+
end
|
268
|
+
|
269
|
+
private
|
270
|
+
def send_real(method, param, req)
|
271
|
+
method = method.to_s unless method.is_a?(Integer)
|
272
|
+
msgid = @seqid
|
273
|
+
@seqid += 1; if @seqid >= 1<<31 then @seqid = 0 end
|
274
|
+
@sock.send_request msgid, method, param
|
275
|
+
@reqtable[msgid] = req
|
276
|
+
end
|
277
|
+
|
278
|
+
def notify_real(method, param)
|
279
|
+
method = method.to_s unless method.is_a?(Integer)
|
280
|
+
@sock.send_notify method, param
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
class ServerSession
|
286
|
+
def initialize(obj, accept = obj.public_methods)
|
287
|
+
@obj = obj
|
288
|
+
@accept = accept.map {|m| m.to_s }
|
289
|
+
end
|
290
|
+
|
291
|
+
def add_socket(sock)
|
292
|
+
# do nothing
|
293
|
+
end
|
294
|
+
|
295
|
+
def on_request(method, param, res)
|
296
|
+
begin
|
297
|
+
unless @accept.include?(method)
|
298
|
+
raise NoMethodError, "method `#{method}' is not accepted"
|
299
|
+
end
|
300
|
+
ret = @obj.send(method, *param)
|
301
|
+
rescue
|
302
|
+
res.error($!.to_s)
|
303
|
+
return
|
304
|
+
end
|
305
|
+
res.result(ret)
|
306
|
+
end
|
307
|
+
|
308
|
+
def on_notify(method, param)
|
309
|
+
# FIXME notify support
|
310
|
+
raise RPCError.new("unexpected notify message")
|
311
|
+
end
|
312
|
+
|
313
|
+
def on_response(msgid, error, result)
|
314
|
+
raise RPCError.new("unexpected response message")
|
315
|
+
end
|
316
|
+
|
317
|
+
def on_close(sock)
|
318
|
+
# do nothing
|
319
|
+
@sock = nil
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
Loop = ::Rev::Loop
|
324
|
+
|
325
|
+
module LoopUtil
|
326
|
+
class Timer < Rev::TimerWatcher
|
327
|
+
def initialize(interval, repeating, &block)
|
328
|
+
@block = block
|
329
|
+
super(interval, repeating)
|
330
|
+
end
|
331
|
+
def on_timer
|
332
|
+
@block.call
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def start_timer(interval, repeating, &block)
|
337
|
+
@loop.attach Timer.new(interval, repeating, &block)
|
338
|
+
end
|
339
|
+
|
340
|
+
def run
|
341
|
+
@loop.run
|
342
|
+
end
|
343
|
+
|
344
|
+
def stop
|
345
|
+
@loop.stop
|
346
|
+
# attach dummy timer
|
347
|
+
@loop.attach Rev::TimerWatcher.new(0, false)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
|
352
|
+
class Client
|
353
|
+
def initialize(host, port, loop = Loop.new)
|
354
|
+
@loop = loop
|
355
|
+
@host = host
|
356
|
+
@port = port
|
357
|
+
@rsock = RevSocket.connect(host, port)
|
358
|
+
@s = ClientSession.new(loop)
|
359
|
+
@rsock.session = @s
|
360
|
+
loop.attach(@rsock)
|
361
|
+
@timer = Timer.new(1, true) { @s.step_timeout }
|
362
|
+
loop.attach(@timer)
|
363
|
+
end
|
364
|
+
attr_reader :loop, :host, :port
|
365
|
+
|
366
|
+
def close
|
367
|
+
@timer.detach
|
368
|
+
@rsock.detach
|
369
|
+
@s.close
|
370
|
+
end
|
371
|
+
|
372
|
+
def send(method, *args)
|
373
|
+
@s.send(method, *args)
|
374
|
+
end
|
375
|
+
|
376
|
+
def callback(method, *args, &block)
|
377
|
+
@s.callback(method, *args, &block)
|
378
|
+
end
|
379
|
+
|
380
|
+
def call(method, *args)
|
381
|
+
@s.call(method, *args)
|
382
|
+
end
|
383
|
+
|
384
|
+
def notify(method, *args)
|
385
|
+
@s.notify(method, *args)
|
386
|
+
end
|
387
|
+
|
388
|
+
def timeout
|
389
|
+
@s.timeout
|
390
|
+
end
|
391
|
+
|
392
|
+
def timeout=(time)
|
393
|
+
@s.timeout = time
|
394
|
+
end
|
395
|
+
|
396
|
+
include LoopUtil
|
397
|
+
end
|
398
|
+
|
399
|
+
|
400
|
+
class Server
|
401
|
+
class Socket < RevSocket
|
402
|
+
def initialize(*args)
|
403
|
+
accept = args.pop
|
404
|
+
obj = args.pop
|
405
|
+
self.session = ServerSession.new(obj, accept)
|
406
|
+
super(*args)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
def initialize(loop = Loop.new)
|
411
|
+
@loop = loop
|
412
|
+
@socks = []
|
413
|
+
end
|
414
|
+
attr_reader :loop
|
415
|
+
|
416
|
+
def listen(host, port, obj, accept = obj.public_methods)
|
417
|
+
lsock = ::Rev::TCPServer.new(host, port, Server::Socket, obj, accept)
|
418
|
+
@socks.push lsock
|
419
|
+
@loop.attach(lsock)
|
420
|
+
end
|
421
|
+
|
422
|
+
def close
|
423
|
+
@socks.reject! {|lsock|
|
424
|
+
lsock.detach
|
425
|
+
lsock.close
|
426
|
+
true
|
427
|
+
}
|
428
|
+
end
|
429
|
+
|
430
|
+
include LoopUtil
|
431
|
+
end
|
432
|
+
|
433
|
+
|
434
|
+
end # module RPC
|
435
|
+
end # module MessagePack
|
436
|
+
|
@@ -0,0 +1,224 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
$port = 65500
|
6
|
+
|
7
|
+
class MessagePackRPCTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
class MyServer
|
10
|
+
def hello
|
11
|
+
"ok"
|
12
|
+
end
|
13
|
+
|
14
|
+
def sum(a, b)
|
15
|
+
a + b
|
16
|
+
end
|
17
|
+
|
18
|
+
def exception
|
19
|
+
raise "raised"
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def hidden
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def test_listen
|
29
|
+
port = $port += 1
|
30
|
+
|
31
|
+
svr = MessagePack::RPC::Server.new
|
32
|
+
svr.listen("0.0.0.0", port, MyServer.new)
|
33
|
+
svr.close
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def test_call
|
38
|
+
port = $port += 1
|
39
|
+
|
40
|
+
svr = MessagePack::RPC::Server.new
|
41
|
+
svr.listen("0.0.0.0", port, MyServer.new)
|
42
|
+
Thread.start do
|
43
|
+
svr.run
|
44
|
+
end
|
45
|
+
|
46
|
+
cli = MessagePack::RPC::Client.new("127.0.0.1", port)
|
47
|
+
|
48
|
+
result = cli.call(:hello)
|
49
|
+
assert_equal(result, "ok")
|
50
|
+
|
51
|
+
result = cli.call(:sum, 1, 2)
|
52
|
+
assert_equal(result, 3)
|
53
|
+
|
54
|
+
cli.close
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def test_send
|
59
|
+
port = $port += 1
|
60
|
+
|
61
|
+
svr = MessagePack::RPC::Server.new
|
62
|
+
svr.listen("0.0.0.0", port, MyServer.new)
|
63
|
+
Thread.start do
|
64
|
+
svr.run
|
65
|
+
end
|
66
|
+
|
67
|
+
cli = MessagePack::RPC::Client.new("127.0.0.1", port)
|
68
|
+
|
69
|
+
req1 = cli.send(:hello)
|
70
|
+
req2 = cli.send(:sum, 1, 2)
|
71
|
+
|
72
|
+
req1.join
|
73
|
+
req2.join
|
74
|
+
|
75
|
+
assert_equal(req1.result, "ok")
|
76
|
+
assert_nil(req1.error)
|
77
|
+
assert_equal(req2.result, 3)
|
78
|
+
assert_nil(req2.error)
|
79
|
+
|
80
|
+
cli.close
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def test_callback
|
85
|
+
port = $port += 1
|
86
|
+
|
87
|
+
svr = MessagePack::RPC::Server.new
|
88
|
+
svr.listen("0.0.0.0", port, MyServer.new)
|
89
|
+
Thread.start do
|
90
|
+
svr.run
|
91
|
+
end
|
92
|
+
|
93
|
+
count = 0
|
94
|
+
|
95
|
+
cli = MessagePack::RPC::Client.new("127.0.0.1", port)
|
96
|
+
|
97
|
+
cli.callback(:hello) do |error, result|
|
98
|
+
assert_equal(result, "ok")
|
99
|
+
assert_nil(error)
|
100
|
+
count += 1
|
101
|
+
end
|
102
|
+
|
103
|
+
cli.callback(:sum, 1, 2) do |error, result|
|
104
|
+
assert_equal(result, 3)
|
105
|
+
assert_nil(error)
|
106
|
+
count += 1
|
107
|
+
end
|
108
|
+
|
109
|
+
while count < 2
|
110
|
+
cli.loop.run_once
|
111
|
+
end
|
112
|
+
|
113
|
+
cli.close
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def test_hidden
|
118
|
+
port = $port += 1
|
119
|
+
|
120
|
+
svr = MessagePack::RPC::Server.new
|
121
|
+
svr.listen("0.0.0.0", port, MyServer.new)
|
122
|
+
Thread.start do
|
123
|
+
svr.run
|
124
|
+
end
|
125
|
+
|
126
|
+
count = 0
|
127
|
+
|
128
|
+
cli = MessagePack::RPC::Client.new("127.0.0.1", port)
|
129
|
+
|
130
|
+
rejected = false
|
131
|
+
begin
|
132
|
+
cli.call(:hidden)
|
133
|
+
rescue MessagePack::RPC::RemoteError
|
134
|
+
rejected = true
|
135
|
+
end
|
136
|
+
|
137
|
+
assert_equal(rejected, true)
|
138
|
+
|
139
|
+
cli.close
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
def test_exception
|
144
|
+
port = $port += 1
|
145
|
+
|
146
|
+
svr = MessagePack::RPC::Server.new
|
147
|
+
svr.listen("0.0.0.0", port, MyServer.new)
|
148
|
+
Thread.start do
|
149
|
+
svr.run
|
150
|
+
end
|
151
|
+
|
152
|
+
cli = MessagePack::RPC::Client.new("127.0.0.1", port)
|
153
|
+
|
154
|
+
raised = false
|
155
|
+
begin
|
156
|
+
cli.call(:exception)
|
157
|
+
rescue MessagePack::RPC::RemoteError
|
158
|
+
assert_equal($!.message, "raised")
|
159
|
+
raised = true
|
160
|
+
end
|
161
|
+
|
162
|
+
assert_equal(raised, true)
|
163
|
+
|
164
|
+
cli.close
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
def test_loop
|
169
|
+
port = $port += 1
|
170
|
+
|
171
|
+
loop = MessagePack::RPC::Loop.new
|
172
|
+
|
173
|
+
svr = MessagePack::RPC::Server.new(loop)
|
174
|
+
svr.listen("0.0.0.0", port, MyServer.new)
|
175
|
+
|
176
|
+
cli = MessagePack::RPC::Client.new("127.0.0.1", port, loop)
|
177
|
+
cli.timeout = 1
|
178
|
+
|
179
|
+
count = 0
|
180
|
+
|
181
|
+
cli.callback(:hello) do |error, result|
|
182
|
+
assert_equal(result, "ok")
|
183
|
+
assert_nil(error)
|
184
|
+
count += 1
|
185
|
+
end
|
186
|
+
|
187
|
+
cli.callback(:sum, 1, 2) do |error, result|
|
188
|
+
assert_equal(result, 3)
|
189
|
+
assert_nil(error)
|
190
|
+
count += 1
|
191
|
+
end
|
192
|
+
|
193
|
+
while count < 2
|
194
|
+
loop.run_once
|
195
|
+
end
|
196
|
+
|
197
|
+
cli.close
|
198
|
+
svr.close
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
def test_timeout
|
203
|
+
port = $port += 1
|
204
|
+
|
205
|
+
lsock = TCPServer.new("0.0.0.0", port)
|
206
|
+
|
207
|
+
cli = MessagePack::RPC::Client.new("127.0.0.1", port)
|
208
|
+
cli.timeout = 1
|
209
|
+
|
210
|
+
timeout = false
|
211
|
+
begin
|
212
|
+
cli.call(:hello)
|
213
|
+
rescue MessagePack::RPC::TimeoutError
|
214
|
+
timeout = true
|
215
|
+
end
|
216
|
+
|
217
|
+
assert_equal(timeout, true)
|
218
|
+
|
219
|
+
cli.close
|
220
|
+
lsock.close
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: msgpack-rpc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- FURUHASHI Sadayuki
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-18 00:00:00 +09:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: msgpack
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.3.1
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rev
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.0
|
34
|
+
version:
|
35
|
+
description: RPC library using MessagePack, a ainary-based efficient data interchange format.
|
36
|
+
email: frsyuki _at_ users.sourceforge.jp
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README
|
43
|
+
- ChangeLog
|
44
|
+
- AUTHORS
|
45
|
+
files:
|
46
|
+
- README
|
47
|
+
- ChangeLog
|
48
|
+
- Rakefile
|
49
|
+
- test/msgpack_rpc_test.rb
|
50
|
+
- test/test_helper.rb
|
51
|
+
- lib/msgpack
|
52
|
+
- lib/msgpack/rpc.rb
|
53
|
+
- AUTHORS
|
54
|
+
has_rdoc: false
|
55
|
+
homepage: http://msgpack.rubyforge.org
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options:
|
58
|
+
- --title
|
59
|
+
- msgpack-rpc documentation
|
60
|
+
- --charset
|
61
|
+
- utf-8
|
62
|
+
- --opname
|
63
|
+
- index.html
|
64
|
+
- --line-numbers
|
65
|
+
- --main
|
66
|
+
- README
|
67
|
+
- --inline-source
|
68
|
+
- --exclude
|
69
|
+
- ^(examples|extras)/
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
version:
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project: msgpack
|
87
|
+
rubygems_version: 1.3.1
|
88
|
+
signing_key:
|
89
|
+
specification_version: 2
|
90
|
+
summary: RPC library using MessagePack, a ainary-based efficient data interchange format.
|
91
|
+
test_files:
|
92
|
+
- test/test_helper.rb
|