msgpack-rpc 0.1.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.
- 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
|