pipe_rpc 0.2.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rakeTasks +7 -0
- data/.rspec +3 -0
- data/.travis.yml +3 -0
- data/Gemfile +3 -0
- data/README.md +59 -0
- data/Rakefile +2 -0
- data/lib/hash.rb +5 -0
- data/lib/pipe_rpc/client.rb +30 -0
- data/lib/pipe_rpc/error.rb +6 -0
- data/lib/pipe_rpc/error_response.rb +77 -0
- data/lib/pipe_rpc/hub/message.rb +57 -0
- data/lib/pipe_rpc/hub/requester.rb +31 -0
- data/lib/pipe_rpc/hub/responder.rb +90 -0
- data/lib/pipe_rpc/hub.rb +104 -0
- data/lib/pipe_rpc/request.rb +16 -0
- data/lib/pipe_rpc/result_response.rb +32 -0
- data/lib/pipe_rpc/socket.rb +45 -0
- data/lib/pipe_rpc/version.rb +3 -0
- data/lib/pipe_rpc.rb +16 -0
- data/pipe_rpc.gemspec +27 -0
- metadata +137 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2ad289824f7ad565af6f419ddf007c4bd1745e37
|
4
|
+
data.tar.gz: d6511143979b1c2a998eb3072042a596d264307e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a13574ab492318a87acb1c82b5f74eb6a7a4e28e4022106725ce3c405de8a56528d08d54493386b0e5d4fb5e5a025d4d77577c3065aa0cea4081529076380542
|
7
|
+
data.tar.gz: eeeb48e3f988525d562d66a5cd64d3f88d7df8edef572f10d4df391b00a53616e7b08ed9935ccd05923b7321ff60fac816f091f15c0d0dfc1c59cd22335077a6
|
data/.gitignore
ADDED
data/.rakeTasks
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Settings><!--This file was automatically generated by Ruby plugin.
|
3
|
+
You are allowed to:
|
4
|
+
1. Remove rake task
|
5
|
+
2. Add existing rake tasks
|
6
|
+
To add existing rake tasks automatically delete this file and reload the project.
|
7
|
+
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build local_rpc-0.1.0.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Build and install local_rpc-0.1.0.gem into system gems" fullCmd="install" taksId="install" /><RakeTask description="Create tag v0.1.0 and build and push local_rpc-0.1.0.gem to Rubygems" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# PipeRpc
|
2
|
+
|
3
|
+
PipeRpc was designed so parent und child processes can call each other's methods. It uses a json protocol similar to JSON-RPC.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'pipe_rpc'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install pipe_rpc
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'pipe_rpc'
|
25
|
+
|
26
|
+
request_read, request_write = IO.pipe
|
27
|
+
response_read, response_write = IO.pipe
|
28
|
+
|
29
|
+
pid = fork do
|
30
|
+
request_write.close
|
31
|
+
response_read.close
|
32
|
+
|
33
|
+
class Server
|
34
|
+
def add(a, b)
|
35
|
+
a + b
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
hub = PipeRpc::Hub.new(input: request_read, output: response_write)
|
40
|
+
hub.add_server(default: Server.new)
|
41
|
+
|
42
|
+
loop do
|
43
|
+
hub.handle_message # blocks until message available
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
request_read.close
|
49
|
+
response_write.close
|
50
|
+
|
51
|
+
hub = PipeRpc::Hub.new(output: request_write, input: response_read)
|
52
|
+
client = hub.client_for(:default)
|
53
|
+
|
54
|
+
puts client.add(3, 5)
|
55
|
+
ensure
|
56
|
+
Process.kill 9, pid
|
57
|
+
Process.wait pid
|
58
|
+
end
|
59
|
+
```
|
data/Rakefile
ADDED
data/lib/hash.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
class Client < BasicObject
|
3
|
+
def initialize(hub, args = {})
|
4
|
+
@hub = hub
|
5
|
+
@server = args.fetch(:server, :default).to_sym
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(method, *args)
|
9
|
+
backtrace = ::Kernel.respond_to?(:caller) ? ::Kernel.caller(1) : []
|
10
|
+
|
11
|
+
@hub.request(server: @server, method: method, arguments: args) do |result|
|
12
|
+
if result.is_a? ::StandardError
|
13
|
+
result.set_backtrace(result.backtrace.to_a + backtrace.to_a) if result.respond_to? :set_backtrace
|
14
|
+
::Kernel.raise result
|
15
|
+
else
|
16
|
+
result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
# Method won't return until we got a result because @hub.request starts a loop and blocks!
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"<Client:#{@server.to_s}>"
|
24
|
+
end
|
25
|
+
|
26
|
+
def is_a?(object)
|
27
|
+
object == Client
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
class ErrorResponse
|
3
|
+
def initialize(args = {})
|
4
|
+
@id = args.fetch(:id, nil)
|
5
|
+
error = args.fetch(:error)
|
6
|
+
@code = error.fetch(:code)
|
7
|
+
@message = msg_for(@code) || error.fetch(:message, 'Unknown error')
|
8
|
+
@data = error.fetch(:data, nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :id, :code, :message, :data
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
{ id: id, error: { code: code, message: message, data: data } }
|
15
|
+
end
|
16
|
+
|
17
|
+
def native_error(request = nil)
|
18
|
+
@request = request
|
19
|
+
error_for(@code)
|
20
|
+
end
|
21
|
+
|
22
|
+
def result_for(*args)
|
23
|
+
native_error(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def msg_for(code)
|
29
|
+
case code
|
30
|
+
when -32700 then 'Parse error'
|
31
|
+
when -32600 then 'Invalid Request'
|
32
|
+
when -32601 then 'Method not found'
|
33
|
+
when -32602 then 'Invalid arguments'
|
34
|
+
when -32603 then 'Internal error'
|
35
|
+
when -32604 then 'Server not found'
|
36
|
+
when -32605 then 'Reflected error'
|
37
|
+
else nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def error_for(code)
|
42
|
+
case code
|
43
|
+
when -32601 then no_method_error
|
44
|
+
when -32602 then argument_error
|
45
|
+
when -32604 then no_server_error
|
46
|
+
when -32605 then reflected_error
|
47
|
+
else internal_error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def no_method_error
|
52
|
+
method = @data.fetch(:method)
|
53
|
+
args = @data.fetch(:args)
|
54
|
+
NoMethodError.new("undefined method `#{method}' for <Client:#{@request.server}>", method, args)
|
55
|
+
end
|
56
|
+
|
57
|
+
def argument_error
|
58
|
+
ArgumentError.new(@data.fetch(:message))
|
59
|
+
end
|
60
|
+
|
61
|
+
def no_server_error
|
62
|
+
NoServerError.new("undefined server `#{@request.server}'")
|
63
|
+
end
|
64
|
+
|
65
|
+
def internal_error
|
66
|
+
InternalError.new("#{@data[:message]}").tap do |error|
|
67
|
+
error.set_backtrace(@data[:backtrace]) if error.respond_to? :set_backtrace
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def reflected_error
|
72
|
+
ReflectedError.new("#{@data[:message]}").tap do |error|
|
73
|
+
error.set_backtrace(@data[:backtrace]) if error.respond_to? :set_backtrace
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
class Hub
|
3
|
+
class Message
|
4
|
+
def initialize(hub, message)
|
5
|
+
@hub = hub
|
6
|
+
@message = message
|
7
|
+
end
|
8
|
+
|
9
|
+
def notification?
|
10
|
+
@message.has_key? :method and not id?
|
11
|
+
end
|
12
|
+
|
13
|
+
def request?
|
14
|
+
@message.has_key? :method and id?
|
15
|
+
end
|
16
|
+
|
17
|
+
def response?
|
18
|
+
(result? or error_message?) and id?
|
19
|
+
end
|
20
|
+
|
21
|
+
def error?
|
22
|
+
error_message? and not id?
|
23
|
+
end
|
24
|
+
|
25
|
+
def handler
|
26
|
+
@handler ||= type.new(@message)
|
27
|
+
rescue => e
|
28
|
+
@hub.send_error(id: nil, code: -32600, data: { message: e.message })
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def result?
|
35
|
+
@message.has_key? :result
|
36
|
+
end
|
37
|
+
|
38
|
+
def error_message?
|
39
|
+
@message.has_key? :error
|
40
|
+
end
|
41
|
+
|
42
|
+
def type
|
43
|
+
if error_message?
|
44
|
+
ErrorResponse
|
45
|
+
elsif result?
|
46
|
+
ResultResponse
|
47
|
+
else
|
48
|
+
Request
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def id?
|
53
|
+
not @message[:id].nil?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
class Hub
|
3
|
+
class Requester
|
4
|
+
def initialize(hub)
|
5
|
+
@hub = hub
|
6
|
+
@requests = {}
|
7
|
+
@uid = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def next_uid
|
11
|
+
@uid += 1
|
12
|
+
end
|
13
|
+
|
14
|
+
def notification(signature)
|
15
|
+
Request.new(signature)
|
16
|
+
end
|
17
|
+
|
18
|
+
def request(signature, &on_response)
|
19
|
+
request = Request.new(signature.merge(id: next_uid))
|
20
|
+
@requests[request.id] = { request: request, on_response: on_response }
|
21
|
+
request
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle_response(response)
|
25
|
+
request = @requests.delete(response.id)
|
26
|
+
raise InternalError.new("no request for response(id: #{response.id})") unless request
|
27
|
+
request[:on_response].call response.result_for(request[:request])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
class Hub
|
3
|
+
class Responder
|
4
|
+
def initialize(hub)
|
5
|
+
@hub = hub
|
6
|
+
@servers = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_server(servers)
|
10
|
+
servers.each{ |name, server| @servers[name.to_sym] = server }
|
11
|
+
end
|
12
|
+
|
13
|
+
def rmv_server(server_name)
|
14
|
+
@servers.delete(server_name.to_sym)
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_request(&on_request)
|
18
|
+
@on_request = on_request
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle_notification(notification)
|
22
|
+
handle_request(notification) {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def handle_request(request, &on_result)
|
26
|
+
id, server, method, args = request.id, @servers[request.server], request.method, request.arguments
|
27
|
+
|
28
|
+
unless server
|
29
|
+
@hub.send_error(id: id, code: -32604)
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
async = proc do |result|
|
34
|
+
on_result.call ResultResponse.new(id: id, result: result)
|
35
|
+
end
|
36
|
+
|
37
|
+
@on_request.call(server, method, args) if @on_request
|
38
|
+
|
39
|
+
# methods returning the async block as result state that they are asynchronous!
|
40
|
+
method_lineno = __LINE__+1
|
41
|
+
result = server.__send__(method, *args, &async)
|
42
|
+
|
43
|
+
# directly return result for synchronous calls
|
44
|
+
async.call(result) unless result == async
|
45
|
+
|
46
|
+
rescue NoMethodError => e
|
47
|
+
backtrace = e.backtrace.to_a
|
48
|
+
code = itself_caused_no_method_error?(backtrace, method_lineno) ? -32601 : -32603
|
49
|
+
@hub.send_error(id: id, code: code, data: { message: e.message, method: e.name,
|
50
|
+
args: e.args, backtrace: backtrace })
|
51
|
+
|
52
|
+
rescue ArgumentError => e
|
53
|
+
backtrace = e.backtrace.to_a
|
54
|
+
code = itself_caused_argument_error?(backtrace, method_lineno) ? -32602 : -32603
|
55
|
+
@hub.send_error(id: id, code: code, data: { message: e.message, backtrace: backtrace })
|
56
|
+
|
57
|
+
rescue InternalError => e # raised on the other side
|
58
|
+
backtrace = e.backtrace.to_a
|
59
|
+
@hub.send_error(id: id, code: -32605, data: { message: e.message, backtrace: backtrace })
|
60
|
+
|
61
|
+
rescue => e
|
62
|
+
backtrace = e.backtrace.to_a
|
63
|
+
@hub.send_error(id: id, code: -32603, data: { message: e.message, backtrace: backtrace })
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def itself_caused_no_method_error?(backtrace, ref_lineno)
|
69
|
+
if Object.const_defined?(:MRUBY_VERSION)
|
70
|
+
!backtrace[0]
|
71
|
+
else
|
72
|
+
itself_caused_error?(backtrace[0], ref_lineno)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def itself_caused_argument_error?(backtrace, ref_lineno)
|
77
|
+
if Object.const_defined?(:MRUBY_VERSION)
|
78
|
+
!backtrace[0]
|
79
|
+
else
|
80
|
+
itself_caused_error?(backtrace[1], ref_lineno)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def itself_caused_error?(backtrace_loc, ref_lineno)
|
85
|
+
file, lineno, = backtrace_loc.split(':')
|
86
|
+
(file == __FILE__) and (lineno.to_i == ref_lineno)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/pipe_rpc/hub.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
class Hub
|
3
|
+
def initialize(args)
|
4
|
+
@channel = args[:input]
|
5
|
+
@socket = Socket.new(self, args)
|
6
|
+
@requester = Requester.new(self)
|
7
|
+
@responder = Responder.new(self)
|
8
|
+
@clients = {}
|
9
|
+
self.loop_iteration = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :channel
|
13
|
+
attr_accessor :logger
|
14
|
+
|
15
|
+
def log(msg)
|
16
|
+
if logger == :reflect
|
17
|
+
notify(server: :reflect_logger, method: :log, arguments: [msg])
|
18
|
+
elsif logger.respond_to? :debug
|
19
|
+
logger.debug msg
|
20
|
+
elsif logger
|
21
|
+
logger.call msg
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_server(servers)
|
26
|
+
@responder.add_server(servers)
|
27
|
+
end
|
28
|
+
|
29
|
+
def rmv_server(server_name)
|
30
|
+
@responder.rmv_server(server_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_incoming_request(&on_request)
|
34
|
+
@responder.on_request(&on_request)
|
35
|
+
end
|
36
|
+
|
37
|
+
def client_for(server_name)
|
38
|
+
@clients[server_name] ||= Client.new(self, server: server_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def loop_iteration=(proc)
|
42
|
+
@loop_iteration = proc
|
43
|
+
end
|
44
|
+
|
45
|
+
def on_sent(&on_sent)
|
46
|
+
@socket.on_write(&on_sent)
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_received(&on_received)
|
50
|
+
@socket.on_read(&on_received)
|
51
|
+
end
|
52
|
+
|
53
|
+
def notify(signature)
|
54
|
+
@socket.write @requester.notification(signature)
|
55
|
+
end
|
56
|
+
|
57
|
+
def request(signature, &on_result)
|
58
|
+
result = nil
|
59
|
+
result_ready = false
|
60
|
+
|
61
|
+
request = @requester.request(signature) do |*response|
|
62
|
+
result = on_result.call(*response)
|
63
|
+
result_ready = true
|
64
|
+
end
|
65
|
+
@socket.write request
|
66
|
+
|
67
|
+
loop do
|
68
|
+
return result if result_ready
|
69
|
+
@loop_iteration ? @loop_iteration.call : handle_message
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def send_error(error = {})
|
74
|
+
@socket.write ErrorResponse.new(id: error.delete(:id), error: error)
|
75
|
+
end
|
76
|
+
|
77
|
+
def handle_message
|
78
|
+
message = next_message # blocks
|
79
|
+
|
80
|
+
return unless message
|
81
|
+
|
82
|
+
if message.notification?
|
83
|
+
@responder.handle_notification(message.handler)
|
84
|
+
elsif message.request?
|
85
|
+
@responder.handle_request(message.handler) { |response| @socket.write response }
|
86
|
+
elsif message.response?
|
87
|
+
@requester.handle_response(message.handler)
|
88
|
+
elsif message.error?
|
89
|
+
raise message.handler.native_error
|
90
|
+
else
|
91
|
+
send_error(id: nil, code: -32600, data: { message: 'no request, result or error' })
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def next_message
|
98
|
+
Message.new(self, @socket.read) # blocks
|
99
|
+
rescue => e
|
100
|
+
send_error(id: nil, code: -32700, data: { message: e.message })
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
class Request
|
3
|
+
def initialize(args)
|
4
|
+
@server = args.fetch(:server, :default).to_sym
|
5
|
+
@method = args.fetch(:method).to_sym
|
6
|
+
@arguments = args.fetch(:arguments, [])
|
7
|
+
@id = args.fetch(:id, nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :server, :method, :arguments, :id
|
11
|
+
|
12
|
+
def to_h
|
13
|
+
{ server: server, method: method, arguments: arguments, id: id }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
class ResultResponse
|
3
|
+
def initialize(args = {})
|
4
|
+
@result = sanitize(args.fetch(:result))
|
5
|
+
@id = args.fetch(:id)
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :result, :id
|
9
|
+
|
10
|
+
def result_for(request)
|
11
|
+
result
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_h
|
15
|
+
{ id: id, result: result }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def sanitize(result)
|
21
|
+
if true == result or false == result or nil == result or result.is_a?(String) or result.is_a?(Numeric)
|
22
|
+
result
|
23
|
+
elsif result.is_a?(Array)
|
24
|
+
result.map{ |v| sanitize(v) }
|
25
|
+
elsif result.is_a?(Hash)
|
26
|
+
Hash[result.map{ |k,v| [sanitize(k), sanitize(v)] }]
|
27
|
+
else
|
28
|
+
result.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
class Socket
|
3
|
+
def initialize(hub, args = {})
|
4
|
+
@hub = hub
|
5
|
+
@input = args.fetch(:input)
|
6
|
+
@output = args.fetch(:output)
|
7
|
+
on_write{}
|
8
|
+
on_read{}
|
9
|
+
end
|
10
|
+
|
11
|
+
def read
|
12
|
+
symbolize_message_keys(JSON.load(@input.gets)).tap do |message|
|
13
|
+
next if message[:server] == 'reflect_logger'
|
14
|
+
@hub.log "received: #{message.inspect}"
|
15
|
+
@on_read.call(message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def write(obj)
|
20
|
+
raise InternalError.new('Output pipe broke') if @output.closed?
|
21
|
+
@output.puts(JSON.dump(obj.to_h.tap do |message|
|
22
|
+
next if @hub.logger == :reflect
|
23
|
+
@hub.log "sent: #{message.inspect}"
|
24
|
+
@on_write.call(message)
|
25
|
+
end))
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_write(&on_write)
|
29
|
+
@on_write = on_write || proc{}
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_read(&on_read)
|
33
|
+
@on_read = on_read || proc{}
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def symbolize_message_keys(message)
|
39
|
+
hash = message.symbolize_keys
|
40
|
+
hash[:error] = hash[:error].symbolize_keys if hash[:error]
|
41
|
+
hash[:error][:data] = hash[:error][:data].symbolize_keys if hash[:error] and hash[:error][:data]
|
42
|
+
hash
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/pipe_rpc.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module PipeRpc
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'json'
|
5
|
+
require_relative 'hash'
|
6
|
+
require_relative "pipe_rpc/version"
|
7
|
+
require_relative "pipe_rpc/error"
|
8
|
+
require_relative "pipe_rpc/request"
|
9
|
+
require_relative "pipe_rpc/result_response"
|
10
|
+
require_relative "pipe_rpc/error_response"
|
11
|
+
require_relative "pipe_rpc/socket"
|
12
|
+
require_relative "pipe_rpc/client"
|
13
|
+
require_relative "pipe_rpc/hub"
|
14
|
+
require_relative "pipe_rpc/hub/message"
|
15
|
+
require_relative "pipe_rpc/hub/requester"
|
16
|
+
require_relative "pipe_rpc/hub/responder"
|
data/pipe_rpc.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pipe_rpc/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "pipe_rpc"
|
8
|
+
spec.version = PipeRpc::VERSION
|
9
|
+
spec.authors = ["Christopher Aue"]
|
10
|
+
spec.email = ["mail@christopheraue.net"]
|
11
|
+
|
12
|
+
spec.summary = %q{RPC between parent and child process over pipes}
|
13
|
+
spec.description = %q{PipeRpc was designed so parent und child processes can call each other's
|
14
|
+
methods. It uses a json protocol similar to JSON-RPC.}
|
15
|
+
spec.homepage = "https://github.com/christopheraue/ruby-pipe_rpc"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "json"
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.8"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.4"
|
25
|
+
spec.add_development_dependency "rspec-its"
|
26
|
+
spec.add_development_dependency "rspec-mocks-matchers-send_message", "~> 0.2"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pipe_rpc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christopher Aue
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.8'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.8'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-its
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-mocks-matchers-send_message
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.2'
|
83
|
+
description: |-
|
84
|
+
PipeRpc was designed so parent und child processes can call each other's
|
85
|
+
methods. It uses a json protocol similar to JSON-RPC.
|
86
|
+
email:
|
87
|
+
- mail@christopheraue.net
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".rakeTasks"
|
94
|
+
- ".rspec"
|
95
|
+
- ".travis.yml"
|
96
|
+
- Gemfile
|
97
|
+
- README.md
|
98
|
+
- Rakefile
|
99
|
+
- lib/hash.rb
|
100
|
+
- lib/pipe_rpc.rb
|
101
|
+
- lib/pipe_rpc/client.rb
|
102
|
+
- lib/pipe_rpc/error.rb
|
103
|
+
- lib/pipe_rpc/error_response.rb
|
104
|
+
- lib/pipe_rpc/hub.rb
|
105
|
+
- lib/pipe_rpc/hub/message.rb
|
106
|
+
- lib/pipe_rpc/hub/requester.rb
|
107
|
+
- lib/pipe_rpc/hub/responder.rb
|
108
|
+
- lib/pipe_rpc/request.rb
|
109
|
+
- lib/pipe_rpc/result_response.rb
|
110
|
+
- lib/pipe_rpc/socket.rb
|
111
|
+
- lib/pipe_rpc/version.rb
|
112
|
+
- pipe_rpc.gemspec
|
113
|
+
homepage: https://github.com/christopheraue/ruby-pipe_rpc
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.4.5.1
|
134
|
+
signing_key:
|
135
|
+
specification_version: 4
|
136
|
+
summary: RPC between parent and child process over pipes
|
137
|
+
test_files: []
|