sync_service 0.0.8
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/.autotest +5 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/Gemfile +13 -0
- data/Guardfile +5 -0
- data/README.md +66 -0
- data/Rakefile +29 -0
- data/examples/application.rb +17 -0
- data/examples/client.rb +29 -0
- data/examples/config.ru +7 -0
- data/examples/php/client.php +17 -0
- data/examples/php/jsonRPCClient.php +165 -0
- data/examples/python/README +5 -0
- data/examples/python/client.py +16 -0
- data/examples/server.rb +4 -0
- data/lib/mobme/infrastructure/rpc/adaptor.rb +31 -0
- data/lib/mobme/infrastructure/rpc/base.rb +15 -0
- data/lib/mobme/infrastructure/rpc/error.rb +3 -0
- data/lib/mobme/infrastructure/rpc/runner.rb +21 -0
- data/lib/mobme/infrastructure/rpc/version.rb +14 -0
- data/lib/rpc/.gitignore +2 -0
- data/lib/rpc/CHANGELOG +10 -0
- data/lib/rpc/Gemfile +19 -0
- data/lib/rpc/LICENSE +20 -0
- data/lib/rpc/README.textile +7 -0
- data/lib/rpc/examples/em-http-request-json/client.rb +39 -0
- data/lib/rpc/examples/helpers.rb +15 -0
- data/lib/rpc/examples/net-http-json/client.rb +34 -0
- data/lib/rpc/examples/net-http-json/console.rb +13 -0
- data/lib/rpc/examples/server.ru +42 -0
- data/lib/rpc/examples/socket-json/client.rb +36 -0
- data/lib/rpc/examples/socket-json/server.rb +41 -0
- data/lib/rpc/lib/rpc.rb +166 -0
- data/lib/rpc/lib/rpc/clients/amqp/coolio.rb +0 -0
- data/lib/rpc/lib/rpc/clients/amqp/eventmachine.rb +0 -0
- data/lib/rpc/lib/rpc/clients/amqp/socket.rb +0 -0
- data/lib/rpc/lib/rpc/clients/em-http-request.rb +58 -0
- data/lib/rpc/lib/rpc/clients/net-http.rb +55 -0
- data/lib/rpc/lib/rpc/clients/redis.rb +0 -0
- data/lib/rpc/lib/rpc/clients/socket.rb +50 -0
- data/lib/rpc/lib/rpc/encoders/json.rb +142 -0
- data/lib/rpc/lib/rpc/encoders/xml.rb +0 -0
- data/lib/rpc/rpc.gemspec +34 -0
- data/lib/sync_service.rb +20 -0
- data/spec/adaptor_spec.rb +104 -0
- data/spec/base_spec.rb +61 -0
- data/spec/error_spec.rb +14 -0
- data/spec/runner_spec.rb +31 -0
- data/spec/spec_helper.rb +9 -0
- data/sync_service.gemspec +32 -0
- metadata +218 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module MobME::Infrastructure::RPC
|
|
2
|
+
class Runner
|
|
3
|
+
def self.start(application, host, port, route)
|
|
4
|
+
begin
|
|
5
|
+
require "thin"
|
|
6
|
+
rescue LoadError
|
|
7
|
+
puts "Thin must be installed to use the server, please add thin to your Gemfile"
|
|
8
|
+
exit
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
Thin::Server.start(host, port) do
|
|
12
|
+
# Since no logger is specified, this will log apache-style strings to STDERR for each request.
|
|
13
|
+
use Rack::CommonLogger
|
|
14
|
+
|
|
15
|
+
map route do
|
|
16
|
+
run Adaptor.new(application)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/rpc/.gitignore
ADDED
data/lib/rpc/CHANGELOG
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
= Version 0.3
|
|
2
|
+
* [FEATURE] Added TCP/IP communication layer.
|
|
3
|
+
|
|
4
|
+
= Version 0.2
|
|
5
|
+
* [FEATURE] Full JSON-RPC 2.0 support (added batch, errors and notifications).
|
|
6
|
+
|
|
7
|
+
= Version 0.1
|
|
8
|
+
* [FEATURE] Net::HTTP(S) client.
|
|
9
|
+
* [FEATURE] EM HTTP Request client.
|
|
10
|
+
* [FEATURE] JSON-RPC encoder.
|
data/lib/rpc/Gemfile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
source "http://gemcutter.org"
|
|
4
|
+
|
|
5
|
+
group(:examples) do
|
|
6
|
+
gem "rack"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
group(:em) do
|
|
10
|
+
gem "em-http-request"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# group(:amqp) do
|
|
14
|
+
# gem "amq-client"
|
|
15
|
+
# end
|
|
16
|
+
|
|
17
|
+
group(:test) do
|
|
18
|
+
gem "rspec", ">=2.0.0"
|
|
19
|
+
end
|
data/lib/rpc/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2011 Jakub Stastny aka botanicus
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
|
|
5
|
+
|
|
6
|
+
require "rpc"
|
|
7
|
+
|
|
8
|
+
RPC.logging = true
|
|
9
|
+
|
|
10
|
+
client = RPC::Clients::EmHttpRequest.new("http://127.0.0.1:8081")
|
|
11
|
+
|
|
12
|
+
RPC::Client.new(client) do |client|
|
|
13
|
+
# Get result of an existing method.
|
|
14
|
+
client.server_timestamp do |result, error|
|
|
15
|
+
puts "Server timestamp is #{result}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Get result of a non-existing method via method_missing.
|
|
19
|
+
client.send(:+, 1) do |result, error|
|
|
20
|
+
puts "Method missing works: #{result}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Synchronous error handling.
|
|
24
|
+
client.buggy_method do |result, error|
|
|
25
|
+
STDERR.puts "EXCEPTION CAUGHT:"
|
|
26
|
+
STDERR.puts "#{error.class} #{error.message}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Notification isn't supported, because HTTP works in
|
|
30
|
+
# request/response mode, so it does behave in the same
|
|
31
|
+
# manner as RPC via method_missing. Sense of this is
|
|
32
|
+
# only to check, that it won't blow up.
|
|
33
|
+
puts "Sending a notification ..."
|
|
34
|
+
client.notification(:log, "Some shit.")
|
|
35
|
+
|
|
36
|
+
# Batch.
|
|
37
|
+
result = client.batch([[:log, ["Message"], nil], [:a_method, []]])
|
|
38
|
+
puts "Batch result: #{result}"
|
|
39
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class RemoteObject
|
|
4
|
+
def server_timestamp
|
|
5
|
+
Time.now.to_i
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def buggy_method
|
|
9
|
+
raise "This exception is expected."
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def method_missing(name, *args)
|
|
13
|
+
"[SERVER] received method #{name} with #{args.inspect}"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
|
|
5
|
+
|
|
6
|
+
require "rpc"
|
|
7
|
+
|
|
8
|
+
RPC.logging = true
|
|
9
|
+
|
|
10
|
+
client = RPC::Client.setup("http://127.0.0.1:8081")
|
|
11
|
+
|
|
12
|
+
# Get result of an existing method.
|
|
13
|
+
puts "Server timestamp is #{client.server_timestamp}"
|
|
14
|
+
|
|
15
|
+
# Get result of a non-existing method via method_missing.
|
|
16
|
+
puts "Method missing works: #{client + 1}"
|
|
17
|
+
|
|
18
|
+
# Synchronous error handling.
|
|
19
|
+
begin
|
|
20
|
+
client.buggy_method
|
|
21
|
+
rescue Exception => exception
|
|
22
|
+
STDERR.puts "EXCEPTION CAUGHT: #{exception.inspect}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Notification isn't supported, because HTTP works in
|
|
26
|
+
# request/response mode, so it does behave in the same
|
|
27
|
+
# manner as RPC via method_missing. Sense of this is
|
|
28
|
+
# only to check, that it won't blow up.
|
|
29
|
+
puts "Sending a notification ..."
|
|
30
|
+
client.notification(:log, "Some shit.")
|
|
31
|
+
|
|
32
|
+
# Batch.
|
|
33
|
+
result = client.batch([[:log, ["Message"], nil], [:a_method, []]])
|
|
34
|
+
puts "Batch result: #{result}"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
|
|
5
|
+
|
|
6
|
+
require "rpc"
|
|
7
|
+
require "irb"
|
|
8
|
+
|
|
9
|
+
@client = RPC::Client.setup("http://127.0.0.1:8081")
|
|
10
|
+
|
|
11
|
+
puts "~ RPC Client initialised, use @client to access it."
|
|
12
|
+
|
|
13
|
+
IRB.start(__FILE__)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env rackup --port 8081
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
# http://groups.google.com/group/json-rpc/web/json-rpc-over-http
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
|
7
|
+
|
|
8
|
+
require "rpc"
|
|
9
|
+
require "rack/request"
|
|
10
|
+
|
|
11
|
+
require_relative "helpers"
|
|
12
|
+
|
|
13
|
+
RPC.logging = true
|
|
14
|
+
# RPC.development = true
|
|
15
|
+
|
|
16
|
+
class RpcRunner
|
|
17
|
+
def server
|
|
18
|
+
@server ||= RPC::Server.new(RemoteObject.new)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def call(env)
|
|
22
|
+
request = Rack::Request.new(env)
|
|
23
|
+
command = request.body.read
|
|
24
|
+
binary = self.server.execute(command)
|
|
25
|
+
if binary.match(/NoMethodError/)
|
|
26
|
+
response(404, binary)
|
|
27
|
+
else
|
|
28
|
+
response(200, binary)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def response(status, body)
|
|
33
|
+
headers = {
|
|
34
|
+
"Content-Type" => "application/json-rpc",
|
|
35
|
+
"Content-Length" => body.bytesize.to_s}
|
|
36
|
+
[status, headers, [body]]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
map("/") do
|
|
41
|
+
run RpcRunner.new
|
|
42
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
|
|
5
|
+
|
|
6
|
+
require "rpc"
|
|
7
|
+
|
|
8
|
+
RPC.logging = true
|
|
9
|
+
|
|
10
|
+
# TODO: the second argument could be +/- guessed (amqp -> amqp adapter, ip -> socket)
|
|
11
|
+
# TODO: IP isn't any existing URI scheme, on the other hand there are so many not existing URI schemes today that I don't think it matters (rsync://, git://, javascript:// and I could go on)
|
|
12
|
+
client = RPC::Client.setup("ip://localhost:2200", RPC::Clients::Socket)
|
|
13
|
+
|
|
14
|
+
# Get result of an existing method.
|
|
15
|
+
puts "Server timestamp is #{client.server_timestamp}"
|
|
16
|
+
|
|
17
|
+
# Get result of a non-existing method via method_missing.
|
|
18
|
+
puts "Method missing works: #{client + 1}"
|
|
19
|
+
|
|
20
|
+
# Synchronous error handling.
|
|
21
|
+
begin
|
|
22
|
+
client.buggy_method
|
|
23
|
+
rescue Exception => exception
|
|
24
|
+
STDERR.puts "EXCEPTION CAUGHT: #{exception.inspect}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Notification isn't supported, because HTTP works in
|
|
28
|
+
# request/response mode, so it does behave in the same
|
|
29
|
+
# manner as RPC via method_missing. Sense of this is
|
|
30
|
+
# only to check, that it won't blow up.
|
|
31
|
+
puts "Sending a notification ..."
|
|
32
|
+
client.notification(:log, "Some shit.")
|
|
33
|
+
|
|
34
|
+
# Batch.
|
|
35
|
+
result = client.batch([[:log, ["Message"], nil], [:a_method, []]])
|
|
36
|
+
puts "Batch result: #{result}"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
|
|
5
|
+
|
|
6
|
+
require "rpc"
|
|
7
|
+
require "socket"
|
|
8
|
+
|
|
9
|
+
require_relative "../helpers"
|
|
10
|
+
|
|
11
|
+
RPC.logging = true
|
|
12
|
+
# RPC.development = true
|
|
13
|
+
|
|
14
|
+
# Helpers.
|
|
15
|
+
def wait_for_client(server_socket)
|
|
16
|
+
# Block for incoming connection from client by accept method.
|
|
17
|
+
# The return value of accept contains the new client socket
|
|
18
|
+
# object and the remote socket address
|
|
19
|
+
client, client_sockaddr = server_socket.accept
|
|
20
|
+
|
|
21
|
+
trap(:TERM) { server_socket.close }
|
|
22
|
+
|
|
23
|
+
[client, client_sockaddr]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
server_socket = TCPServer.new("127.0.0.1", 2200)
|
|
27
|
+
|
|
28
|
+
client, client_sockaddr = wait_for_client(server_socket)
|
|
29
|
+
|
|
30
|
+
server = RPC::Server.new(RemoteObject.new)
|
|
31
|
+
|
|
32
|
+
begin
|
|
33
|
+
while data = client.readline.chomp
|
|
34
|
+
result = server.execute(data)
|
|
35
|
+
client.puts(result)
|
|
36
|
+
end
|
|
37
|
+
rescue Errno::ECONNRESET, EOFError
|
|
38
|
+
# This occurs when client closes the connection. We can safely ignore it.
|
|
39
|
+
client, client_sockaddr = wait_for_client(server_socket)
|
|
40
|
+
retry
|
|
41
|
+
end
|
data/lib/rpc/lib/rpc.rb
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module RPC
|
|
4
|
+
module Clients
|
|
5
|
+
autoload :NetHttp, "rpc/clients/net-http"
|
|
6
|
+
autoload :EmHttpRequest, "rpc/clients/em-http-request"
|
|
7
|
+
autoload :Socket, "rpc/clients/socket"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module Encoders
|
|
11
|
+
autoload :Json, "rpc/encoders/json"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.logging
|
|
15
|
+
@logging ||= $DEBUG
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.logging=(boolean)
|
|
19
|
+
@logging = boolean
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.log(message)
|
|
23
|
+
STDERR.puts(message) if self.logging
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.development=(boolean)
|
|
27
|
+
@development = boolean
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.development?
|
|
31
|
+
!! @development
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.full_const_get(const_name)
|
|
35
|
+
parts = const_name.sub(/^::/, "").split("::")
|
|
36
|
+
parts.reduce(Object) do |constant, part|
|
|
37
|
+
constant.const_get(part)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class Server
|
|
42
|
+
def initialize(subject, encoder = RPC::Encoders::Json::Server.new)
|
|
43
|
+
@subject, @encoder = subject, encoder
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def execute(encoded_command)
|
|
47
|
+
@encoder.execute(encoded_command, @subject)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
module ExceptionsMixin
|
|
52
|
+
attr_accessor :server_backtrace
|
|
53
|
+
|
|
54
|
+
# NOTE: We can't use super to get the client backtrace,
|
|
55
|
+
# because backtrace is generated only if there is none
|
|
56
|
+
# yet and because we are redefining the backtrace method,
|
|
57
|
+
# there always will be some backtrace.
|
|
58
|
+
def backtrace
|
|
59
|
+
@backtrace ||= begin
|
|
60
|
+
caller(3) + ["... server ..."] + self.server_backtrace
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class Client < BasicObject
|
|
66
|
+
def self.setup(uri, client_class = Clients::NetHttp, encoder = Encoders::Json::Client.new)
|
|
67
|
+
client = client_class.new(uri)
|
|
68
|
+
self.new(client, encoder)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def initialize(client, encoder = Encoders::Json::Client.new, &block)
|
|
72
|
+
@client, @encoder = client, encoder
|
|
73
|
+
|
|
74
|
+
if block
|
|
75
|
+
@client.run do
|
|
76
|
+
block.call(self)
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
@client.connect
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def notification(*args)
|
|
84
|
+
data = @encoder.notification(*args)
|
|
85
|
+
@client.send(data)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def batch(*args)
|
|
89
|
+
data = @encoder.batch(*args)
|
|
90
|
+
@client.send(data)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# 1) Sync: it'll return the value.
|
|
94
|
+
# 2) Async: you have to add #subscribe
|
|
95
|
+
|
|
96
|
+
# TODO: this should be refactored and moved to the encoder,
|
|
97
|
+
# because result["error"] and similar are JSON-RPC-specific.
|
|
98
|
+
def method_missing(method, *args, &callback)
|
|
99
|
+
binary = @encoder.encode(method, *args)
|
|
100
|
+
|
|
101
|
+
if @client.async? && ! callback # Assume notification.
|
|
102
|
+
@client.send(binary)
|
|
103
|
+
elsif @client.async? && callback
|
|
104
|
+
@client.send(binary) do |encoded_result|
|
|
105
|
+
result = @encoder.decode(encoded_result)
|
|
106
|
+
|
|
107
|
+
if result.respond_to?(:merge) # Hash, only one result.
|
|
108
|
+
callback.call(result["result"], get_exception(result["error"]))
|
|
109
|
+
else # Array, multiple results.
|
|
110
|
+
result.map do |result|
|
|
111
|
+
callback.call(result["result"], get_exception(result["error"]))
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
else
|
|
116
|
+
::Kernel.raise("You can't specify callback for a synchronous client.") if callback
|
|
117
|
+
|
|
118
|
+
encoded_result = @client.send(binary)
|
|
119
|
+
|
|
120
|
+
if encoded_result.nil?
|
|
121
|
+
::Kernel.raise("Bug in #{@client.class}#send(data), it can never return nil in the sync mode!")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
result = @encoder.decode(encoded_result)
|
|
125
|
+
|
|
126
|
+
if result.respond_to?(:merge) # Hash, only one result.
|
|
127
|
+
result_or_raise(result)
|
|
128
|
+
else # Array, multiple results.
|
|
129
|
+
result.map do |result|
|
|
130
|
+
result_or_raise(result)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def result_or_raise(result)
|
|
137
|
+
if error = result["error"]
|
|
138
|
+
exception = self.get_exception(error)
|
|
139
|
+
::Kernel.raise(exception)
|
|
140
|
+
else
|
|
141
|
+
result["result"]
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def get_exception(error)
|
|
146
|
+
return unless error
|
|
147
|
+
exception = error["error"]
|
|
148
|
+
resolved_class = ::RPC.full_const_get(exception["class"])
|
|
149
|
+
klass = resolved_class || ::RuntimeError
|
|
150
|
+
message = resolved_class ? exception["message"] : error["message"]
|
|
151
|
+
case klass.instance_method(:initialize).arity
|
|
152
|
+
when 2
|
|
153
|
+
instance = klass.new(message, nil)
|
|
154
|
+
else
|
|
155
|
+
instance = klass.new(message)
|
|
156
|
+
end
|
|
157
|
+
instance.extend(::RPC::ExceptionsMixin)
|
|
158
|
+
instance.server_backtrace = exception["backtrace"]
|
|
159
|
+
instance
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def close_connection
|
|
163
|
+
@client.disconnect
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|