oleganza-emrpc 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README +129 -0
- data/Rakefile +156 -0
- data/TODO +47 -0
- data/bin/emrpc +4 -0
- data/lib/emrpc.rb +15 -0
- data/lib/emrpc/archive/reference_savior.rb +48 -0
- data/lib/emrpc/archive/ring.rb +44 -0
- data/lib/emrpc/blocking_api.rb +3 -0
- data/lib/emrpc/blocking_api/method_proxy.rb +57 -0
- data/lib/emrpc/blocking_api/multithreaded_client.rb +52 -0
- data/lib/emrpc/blocking_api/singlethreaded_client.rb +68 -0
- data/lib/emrpc/client.rb +28 -0
- data/lib/emrpc/console.rb +32 -0
- data/lib/emrpc/evented_api.rb +14 -0
- data/lib/emrpc/evented_api/connection_mixin.rb +14 -0
- data/lib/emrpc/evented_api/debug_connection.rb +52 -0
- data/lib/emrpc/evented_api/debug_pid_callbacks.rb +39 -0
- data/lib/emrpc/evented_api/default_callbacks.rb +40 -0
- data/lib/emrpc/evented_api/evented_wrapper.rb +28 -0
- data/lib/emrpc/evented_api/local_connection.rb +48 -0
- data/lib/emrpc/evented_api/pid.rb +198 -0
- data/lib/emrpc/evented_api/protocol_mapper.rb +57 -0
- data/lib/emrpc/evented_api/reconnecting_pid.rb +105 -0
- data/lib/emrpc/evented_api/remote_connection.rb +73 -0
- data/lib/emrpc/evented_api/remote_pid.rb +38 -0
- data/lib/emrpc/evented_api/subscribable.rb +56 -0
- data/lib/emrpc/evented_api/timer.rb +23 -0
- data/lib/emrpc/protocols.rb +2 -0
- data/lib/emrpc/protocols/fast_message_protocol.rb +99 -0
- data/lib/emrpc/protocols/marshal_protocol.rb +33 -0
- data/lib/emrpc/server.rb +17 -0
- data/lib/emrpc/util.rb +7 -0
- data/lib/emrpc/util/blank_slate.rb +25 -0
- data/lib/emrpc/util/codec.rb +114 -0
- data/lib/emrpc/util/combine_modules.rb +11 -0
- data/lib/emrpc/util/em2rev.rb +48 -0
- data/lib/emrpc/util/em_start_stop_timeouts.rb +62 -0
- data/lib/emrpc/util/parsed_uri.rb +15 -0
- data/lib/emrpc/util/safe_run.rb +23 -0
- data/lib/emrpc/util/timers.rb +17 -0
- data/lib/emrpc/version.rb +3 -0
- data/spec/blocking_api/method_proxy_spec.rb +33 -0
- data/spec/blocking_api/multithreaded_client_spec.rb +52 -0
- data/spec/blocking_api/scenario_spec.rb +35 -0
- data/spec/blocking_api/singlethreaded_client_spec.rb +63 -0
- data/spec/blocking_api/spec_helper.rb +1 -0
- data/spec/blocking_api_test.rb +98 -0
- data/spec/evented_api/connection_mixin_spec.rb +34 -0
- data/spec/evented_api/default_callbacks_spec.rb +26 -0
- data/spec/evented_api/evented_wrapper_spec.rb +50 -0
- data/spec/evented_api/pid_spec.rb +194 -0
- data/spec/evented_api/reconnecting_pid_spec.rb +76 -0
- data/spec/evented_api/remote_connection_spec.rb +147 -0
- data/spec/evented_api/remote_pid_spec.rb +84 -0
- data/spec/evented_api/scenario_spec.rb +138 -0
- data/spec/evented_api/spec_helper.rb +10 -0
- data/spec/evented_api/subscribable_spec.rb +53 -0
- data/spec/server_spec.rb +7 -0
- data/spec/spec_helper.rb +96 -0
- data/spec/util/blank_slate_spec.rb +7 -0
- data/spec/util/codec_spec.rb +183 -0
- data/spec/util/fast_message_protocol_spec.rb +60 -0
- data/spec/util/marshal_protocol_spec.rb +50 -0
- data/spec/util/parsed_uri_spec.rb +19 -0
- data/spec/util/spec_helper.rb +1 -0
- metadata +164 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module EMRPC
|
2
|
+
class LocalConnection
|
3
|
+
include ConnectionMixin
|
4
|
+
|
5
|
+
# Helper class representing abstract connection channel.
|
6
|
+
class Channel
|
7
|
+
attr_accessor :conn12, :conn21
|
8
|
+
def initialize(pid1, pid2, conn12 = nil)
|
9
|
+
@conn21 = LocalConnection.new(pid2, pid1, self)
|
10
|
+
@conn12 = conn12 || LocalConnection.new(pid1, pid2, self)
|
11
|
+
end
|
12
|
+
def unbind
|
13
|
+
@conn12.unbind
|
14
|
+
@conn21.unbind
|
15
|
+
end
|
16
|
+
def connection
|
17
|
+
@conn12
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :channel
|
22
|
+
|
23
|
+
def initialize(local_pid, remote_pid, channel = nil)
|
24
|
+
@channel = channel || Channel.new(local_pid, remote_pid, self)
|
25
|
+
@local_pid = local_pid
|
26
|
+
@remote_pid = local_pid.connection_established(remote_pid, self)
|
27
|
+
end
|
28
|
+
|
29
|
+
def unbind
|
30
|
+
lpid = @local_pid
|
31
|
+
rpid = @remote_pid
|
32
|
+
@local_pid = nil
|
33
|
+
@remote_pid = nil
|
34
|
+
lpid.connection_unbind(rpid, self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def close_connection
|
38
|
+
@channel.unbind
|
39
|
+
end
|
40
|
+
alias close_connection_after_writing close_connection
|
41
|
+
|
42
|
+
LOCALNODE_ADDRESS = 'emrpc://localnode/'.parsed_uri.freeze
|
43
|
+
def address
|
44
|
+
LOCALNODE_ADDRESS
|
45
|
+
end
|
46
|
+
|
47
|
+
end # LocalConnection
|
48
|
+
end # EMRPC
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'uri'
|
2
|
+
module EMRPC
|
3
|
+
# Pid is a abbreviation for "process id". Pid represents so-called lightweight process (like in Erlang OTP)
|
4
|
+
# Pids can be created, connected, disconnected, spawned, killed.
|
5
|
+
# When pid is created, it exists on its own.
|
6
|
+
# When someone connects to the pid, connection is established.
|
7
|
+
# When pid is killed, all its connections are unbinded.
|
8
|
+
|
9
|
+
module Pid
|
10
|
+
attr_accessor :uuid, :connections, :killed, :options
|
11
|
+
attr_accessor :_em_server_signature, :_protocol, :_bind_address
|
12
|
+
include DefaultCallbacks
|
13
|
+
include ProtocolMapper
|
14
|
+
|
15
|
+
# FIXME: doesn't override user-defined callbacks
|
16
|
+
include DebugPidCallbacks if $DEBUG
|
17
|
+
|
18
|
+
# shorthand for console testing
|
19
|
+
def self.new(*attributes)
|
20
|
+
# We create random global const to workaround Marshal.dump issue:
|
21
|
+
# >> Marshal.dump(Class.new.new)
|
22
|
+
# TypeError: can't dump anonymous class #<Class:0x5b5338>
|
23
|
+
#
|
24
|
+
const_set("DynamicPidClass#{rand(2**128).to_s(16).upcase}", Class.new {
|
25
|
+
include Pid
|
26
|
+
attr_accessor(*attributes)
|
27
|
+
}).new
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(*args, &blk)
|
31
|
+
@uuid = _random_uuid
|
32
|
+
@options = {:uuid => @uuid}
|
33
|
+
_common_init
|
34
|
+
super(*args, &blk) rescue nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def spawn(cls, *args, &blk)
|
38
|
+
pid = cls.new(*args, &blk)
|
39
|
+
connect(pid)
|
40
|
+
pid
|
41
|
+
end
|
42
|
+
|
43
|
+
def tcp_spawn(addr, cls, *args, &blk)
|
44
|
+
pid = spawn(cls, *args, &blk)
|
45
|
+
pid.bind(addr)
|
46
|
+
pid
|
47
|
+
end
|
48
|
+
|
49
|
+
def thread_spawn(cls, *args, &blk)
|
50
|
+
# TODO: think about thread-safe passing messages back to sender.
|
51
|
+
end
|
52
|
+
|
53
|
+
def bind(addr)
|
54
|
+
raise "Pid is already binded!" if @_em_server_signature
|
55
|
+
@_bind_address = addr.parsed_uri
|
56
|
+
this = self
|
57
|
+
@_em_server_signature = make_server_connection(@_bind_address, _protocol) do |conn|
|
58
|
+
conn.local_pid = this
|
59
|
+
conn.address = addr
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# 1. Connect to the pid.
|
64
|
+
# 2. When connection is established, asks for uuid.
|
65
|
+
# 3. When uuid is received, triggers callback on the client.
|
66
|
+
# (See Protocol for details)
|
67
|
+
def connect(addr, connected_callback = nil, disconnected_callback = nil)
|
68
|
+
c = if addr.is_a?(Pid) && pid = addr
|
69
|
+
LocalConnection.new(self, pid)
|
70
|
+
else
|
71
|
+
this = self
|
72
|
+
make_client_connection(addr, _protocol) do |conn|
|
73
|
+
conn.local_pid = this
|
74
|
+
conn.address = addr
|
75
|
+
end
|
76
|
+
end
|
77
|
+
c.connected_callback = connected_callback
|
78
|
+
c.disconnected_callback = disconnected_callback
|
79
|
+
c
|
80
|
+
end
|
81
|
+
|
82
|
+
def disconnect(pid, disconnected_callback = nil)
|
83
|
+
c = @connections[pid.uuid]
|
84
|
+
c.disconnected_callback = disconnected_callback if disconnected_callback
|
85
|
+
c.close_connection_after_writing
|
86
|
+
end
|
87
|
+
|
88
|
+
def kill
|
89
|
+
return if @killed
|
90
|
+
if @_em_server_signature
|
91
|
+
EventMachine.stop_server(@_em_server_signature)
|
92
|
+
end
|
93
|
+
@connections.each do |uuid, conn|
|
94
|
+
conn.close_connection_after_writing
|
95
|
+
end
|
96
|
+
@connections.clear
|
97
|
+
@killed = true
|
98
|
+
end
|
99
|
+
|
100
|
+
# TODO:
|
101
|
+
# When connecting to a spawned pid, we should transparantly discard TCP connection
|
102
|
+
# in favor of local connection.
|
103
|
+
def connection_established(pid, conn)
|
104
|
+
@connections[pid.uuid] ||= conn
|
105
|
+
__send__(conn.connected_callback, pid)
|
106
|
+
@connections[pid.uuid].remote_pid || pid # looks like hack, but it is not.
|
107
|
+
end
|
108
|
+
|
109
|
+
def connection_unbind(pid, conn)
|
110
|
+
@connections.delete(pid.uuid)
|
111
|
+
__send__(conn.disconnected_callback, pid)
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Util
|
116
|
+
#
|
117
|
+
def options=(opts)
|
118
|
+
@options = opts
|
119
|
+
@options[:uuid] = @uuid
|
120
|
+
@options
|
121
|
+
end
|
122
|
+
|
123
|
+
def killed?
|
124
|
+
@killed
|
125
|
+
end
|
126
|
+
|
127
|
+
def find_pid(uuid)
|
128
|
+
return self if uuid == @uuid
|
129
|
+
((conn = @connections[uuid]) and conn.remote_pid) or raise "Pid #{_uid} was not found in a #{self.inspect}"
|
130
|
+
end
|
131
|
+
|
132
|
+
def marshal_dump
|
133
|
+
@uuid
|
134
|
+
end
|
135
|
+
|
136
|
+
def marshal_load(uuid)
|
137
|
+
_common_init
|
138
|
+
@uuid = uuid
|
139
|
+
end
|
140
|
+
|
141
|
+
def connection_uuids
|
142
|
+
(@connections || {}).keys
|
143
|
+
end
|
144
|
+
|
145
|
+
def pid_class_name
|
146
|
+
"Pid"
|
147
|
+
end
|
148
|
+
|
149
|
+
def inspect
|
150
|
+
return "#<#{pid_class_name}:#{_uid} KILLED>" if @killed
|
151
|
+
"#<#{pid_class_name}:#{_uid} connected to #{connection_uuids.map{|u|_uid(u)}.inspect}>"
|
152
|
+
end
|
153
|
+
|
154
|
+
def ==(other)
|
155
|
+
other.is_a?(Pid) && other.uuid == @uuid
|
156
|
+
end
|
157
|
+
|
158
|
+
# shorter uuid for pretty output
|
159
|
+
def _uid(uuid = @uuid)
|
160
|
+
uuid && uuid[0,6]
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Private, but accessible from outside methods are prefixed with underscore.
|
165
|
+
#
|
166
|
+
|
167
|
+
def _protocol
|
168
|
+
@_protocol ||= self.__send__(:_protocol=, RemoteConnection)
|
169
|
+
end
|
170
|
+
|
171
|
+
def _protocol=(p)
|
172
|
+
@_protocol = Util.combine_modules(
|
173
|
+
p,
|
174
|
+
MarshalProtocol.new(Marshal),
|
175
|
+
FastMessageProtocol,
|
176
|
+
$DEBUG ? DebugConnection : Module.new
|
177
|
+
)
|
178
|
+
end
|
179
|
+
|
180
|
+
# TODO: remove this in favor of using codec.rb
|
181
|
+
def _send_dirty(*args)
|
182
|
+
args._initialize_pids_recursively_d4d309bd!(self)
|
183
|
+
send(*args)
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
def _common_init
|
189
|
+
@connections = {} # pid.uuid -> connection
|
190
|
+
end
|
191
|
+
|
192
|
+
def _random_uuid
|
193
|
+
# FIXME: insert real uuid generating here!
|
194
|
+
rand(2**128).to_s(16)
|
195
|
+
end
|
196
|
+
|
197
|
+
end # Pid
|
198
|
+
end # EMRPC
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module EMRPC
|
2
|
+
module ProtocolMapper
|
3
|
+
#
|
4
|
+
# Configuration
|
5
|
+
#
|
6
|
+
MAP = Hash.new
|
7
|
+
|
8
|
+
def self.register_protocol(scheme, suffix)
|
9
|
+
MAP[scheme] = suffix
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
# Default mapping
|
14
|
+
register_protocol "emrpc", :emrpc_tcp
|
15
|
+
register_protocol "unix", :emrpc_unix
|
16
|
+
register_protocol "emrpc+unix", :emrpc_unix
|
17
|
+
register_protocol "http", :http_json
|
18
|
+
|
19
|
+
#
|
20
|
+
# Abstract API
|
21
|
+
#
|
22
|
+
def make_client_connection(*args, &blk)
|
23
|
+
make_some_connection(:client, *args, &blk)
|
24
|
+
end
|
25
|
+
|
26
|
+
def make_server_connection(*args, &blk)
|
27
|
+
make_some_connection(:server, *args, &blk)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def make_some_connection(sfx, addr, handler, &blk)
|
32
|
+
addr = addr.parsed_uri
|
33
|
+
pfx = MAP[addr.scheme]
|
34
|
+
__send__("#{pfx}_#{sfx}_connection", addr, handler, &blk)
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Particular protocols
|
39
|
+
#
|
40
|
+
def emrpc_tcp_client_connection(addr, handler, &blk)
|
41
|
+
EventMachine.connect(addr.host, addr.port, handler, &blk)
|
42
|
+
end
|
43
|
+
|
44
|
+
def emrpc_tcp_server_connection(addr, handler, &blk)
|
45
|
+
EventMachine.start_server(addr.host, addr.port, handler, &blk)
|
46
|
+
end
|
47
|
+
|
48
|
+
def emrpc_unix_client_connection(addr, handler, &blk)
|
49
|
+
EventMachine.connect_unix_domain(addr.path, handler, &blk)
|
50
|
+
end
|
51
|
+
|
52
|
+
def emrpc_unix_server_connection(addr, handler, &blk)
|
53
|
+
EventMachine.start_unix_domain_server(addr.path, handler, &blk)
|
54
|
+
end
|
55
|
+
|
56
|
+
end # ProtocolMapper
|
57
|
+
end # EMRPC
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module EMRPC
|
2
|
+
# ReconnectingPid collects all messages in the backlog buffer and tries to reconnect.
|
3
|
+
# Calls self.on_raise() with the following exceptions:
|
4
|
+
# *
|
5
|
+
#
|
6
|
+
class ReconnectingPid
|
7
|
+
include Pid
|
8
|
+
|
9
|
+
DEFAULT_MAX_BACKLOG = 256
|
10
|
+
DEFAULT_MAX_ATTEMPTS = 5
|
11
|
+
DEFAULT_TIMEOUT = 5 # sec.
|
12
|
+
DEFAULT_TIMER = Timers::EVENTED
|
13
|
+
|
14
|
+
# Arguments:
|
15
|
+
# address Address if a pid or the pid itself to connect to.
|
16
|
+
#
|
17
|
+
# Options:
|
18
|
+
# :max_backlog Maximum backlog size. BacklogError is raised when backlog becomes larger than
|
19
|
+
# the specified size. Default is 256 messages.
|
20
|
+
#
|
21
|
+
# :max_attempts Maximum number of connection attempts. AttemptsError is raised when this number is exceeded.
|
22
|
+
# Counter is set to zero after each successful connection. Default is 5 attempts.
|
23
|
+
#
|
24
|
+
# :timeout Time interval in seconds. TimeoutError is raised when connection was not established
|
25
|
+
# in the specified amount of time. Default is 5 seconds.
|
26
|
+
#
|
27
|
+
# :timer Proc which runs a periodic timer. Default is Timers::EVENTED. See EMRPC::Timers for more info.
|
28
|
+
#
|
29
|
+
def initialize(address, options = {})
|
30
|
+
super(address, options)
|
31
|
+
|
32
|
+
@address = address
|
33
|
+
|
34
|
+
# Options
|
35
|
+
|
36
|
+
@max_backlog = options[:max_backlog] || DEFAULT_MAX_BACKLOG
|
37
|
+
@max_attempts = options[:max_attempts] || DEFAULT_MAX_ATTEMPTS
|
38
|
+
@timeout = options[:timeout] || DEFAULT_TIMEOUT
|
39
|
+
@timer = options[:timer] || DEFAULT_TIMER
|
40
|
+
|
41
|
+
# Gentlemen, start your engines!
|
42
|
+
|
43
|
+
@attempts = 1
|
44
|
+
@backlog = Array.new
|
45
|
+
@timeout_thread = @timer.call([ @timeout, 1 ].max, method(:timer_action))
|
46
|
+
connect(address)
|
47
|
+
end
|
48
|
+
|
49
|
+
def send(*args)
|
50
|
+
if rpid = @rpid
|
51
|
+
rpid.send(*args)
|
52
|
+
else
|
53
|
+
@backlog.push(args)
|
54
|
+
if @backlog.size > @max_backlog
|
55
|
+
on_raise(self, BacklogError.new("Backlog exceeded maximum size of #{@max_backlog} messages"))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def flush!
|
61
|
+
while args = @backlog.shift
|
62
|
+
send(*args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def connected(rpid)
|
67
|
+
@rpid = rpid
|
68
|
+
@attempts = 1
|
69
|
+
flush!
|
70
|
+
end
|
71
|
+
|
72
|
+
def disconnected(rpid)
|
73
|
+
@rpid = nil
|
74
|
+
connect(@address) unless killed?
|
75
|
+
end
|
76
|
+
|
77
|
+
def connection_failed(conn)
|
78
|
+
a = (@attempts += 1)
|
79
|
+
if a > @max_attempts
|
80
|
+
on_raise(self, AttemptsError.new("Maximum number of #{@max_attempts} connecting attempts exceeded"))
|
81
|
+
end
|
82
|
+
connect(@address)
|
83
|
+
end
|
84
|
+
|
85
|
+
def timer_action
|
86
|
+
if @rpid
|
87
|
+
@state = nil
|
88
|
+
return
|
89
|
+
end
|
90
|
+
|
91
|
+
if @state == :timeout
|
92
|
+
@state = nil
|
93
|
+
on_raise(self, TimeoutError.new("Failed to reconnect with #{@timeout} sec. timeout"))
|
94
|
+
else
|
95
|
+
@state = :timeout
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class ReconnectingError < StandardError; end
|
100
|
+
class BacklogError < ReconnectingError; end
|
101
|
+
class AttemptsError < ReconnectingError; end
|
102
|
+
class TimeoutError < ReconnectingError; end
|
103
|
+
|
104
|
+
end # ReconnectingPid
|
105
|
+
end # EMRPC
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module EMRPC
|
2
|
+
module RemoteConnection
|
3
|
+
include ConnectionMixin
|
4
|
+
attr_accessor :address
|
5
|
+
|
6
|
+
#
|
7
|
+
# IMPORTANT: server doesn't trigger #connection_completed callback.
|
8
|
+
#
|
9
|
+
def post_init
|
10
|
+
# setup single-shot version of receive_marshalled_message
|
11
|
+
class <<self
|
12
|
+
alias_method :receive_marshalled_message, :receive_handshake_message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Handshake protocol
|
18
|
+
#
|
19
|
+
def connection_completed
|
20
|
+
send_handshake_message(@local_pid.options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def send_handshake_message(arg)
|
24
|
+
@__sent_handshake = true
|
25
|
+
send_marshalled_message([:handshake, arg])
|
26
|
+
end
|
27
|
+
|
28
|
+
def receive_handshake_message(msg)
|
29
|
+
prefix, options = msg
|
30
|
+
lpid = @local_pid
|
31
|
+
prefix == :handshake or return lpid.handshake_failed(self, msg)
|
32
|
+
rpid = RemotePid.new(self, options)
|
33
|
+
# restore receive_marshalled_message
|
34
|
+
class <<self
|
35
|
+
alias_method :receive_marshalled_message, :receive_regular_message
|
36
|
+
end
|
37
|
+
unless @__sent_handshake # server-side
|
38
|
+
send_handshake_message(@local_pid.options)
|
39
|
+
end
|
40
|
+
@remote_pid = lpid.connection_established(rpid, self)
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Regular protocol
|
45
|
+
#
|
46
|
+
def send_raw_message(args)
|
47
|
+
send_marshalled_message(args.encode_b381b571_1ab2_5889_8221_855dbbc76242(@local_pid))
|
48
|
+
end
|
49
|
+
|
50
|
+
def receive_regular_message(msg)
|
51
|
+
lpid = @local_pid
|
52
|
+
lpid.__send__(*(msg.decode_b381b571_1ab2_5889_8221_855dbbc76242(lpid)))
|
53
|
+
end
|
54
|
+
|
55
|
+
def rescue_marshal_error(e)
|
56
|
+
raise e
|
57
|
+
end
|
58
|
+
|
59
|
+
def unbind
|
60
|
+
if @remote_pid
|
61
|
+
# pid has been succesfully connected one day, but connection was lost.
|
62
|
+
# we don't put +_unregister_pid+ into +connection_lost+ callback to avoid unneccessary +super+ calls in callbacks.
|
63
|
+
rpid = @remote_pid
|
64
|
+
@remote_pid = nil
|
65
|
+
@local_pid.connection_unbind(rpid, self)
|
66
|
+
else
|
67
|
+
# there were no connection, connecting failed.
|
68
|
+
@local_pid.connection_failed(self)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end # RemoteConnection
|
73
|
+
end # EMRPC
|