DeepConnect 0.4.06
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/lib/deep-connect.rb +83 -0
- data/lib/deep-connect/accepter.rb +64 -0
- data/lib/deep-connect/class-spec-space.rb +652 -0
- data/lib/deep-connect/conf.rb +48 -0
- data/lib/deep-connect/cron.rb +91 -0
- data/lib/deep-connect/deep-fork.rb +70 -0
- data/lib/deep-connect/deep-mq.rb +62 -0
- data/lib/deep-connect/deep-space.rb +403 -0
- data/lib/deep-connect/evaluator.rb +149 -0
- data/lib/deep-connect/event.rb +551 -0
- data/lib/deep-connect/exceptions.rb +38 -0
- data/lib/deep-connect/future.rb +67 -0
- data/lib/deep-connect/organizer.rb +378 -0
- data/lib/deep-connect/port.rb +151 -0
- data/lib/deep-connect/reference.rb +422 -0
- data/lib/deep-connect/serialize.rb +127 -0
- data/lib/deep-connect/session.rb +348 -0
- data/lib/deep-connect/version.rb +8 -0
- metadata +86 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# exceptions.rb -
|
4
|
+
# Copyright (C) 1996-2010 Keiju ISHITSUKA
|
5
|
+
# (Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
#
|
7
|
+
|
8
|
+
@RCS_ID='-$Id: $-'
|
9
|
+
|
10
|
+
|
11
|
+
require "e2mmap"
|
12
|
+
|
13
|
+
module DeepConnect
|
14
|
+
extend Exception2MessageMapper
|
15
|
+
|
16
|
+
def_exception :IllegalReference, "不正なリファレンス参照です(id=%x, method=%s)"
|
17
|
+
|
18
|
+
def_exception :NoInterfaceMethod, "No interface method(%s.%s)"
|
19
|
+
|
20
|
+
def_exception :NoServiceError, "No such service(%s)"
|
21
|
+
def_exception :CantSerializable, "%sはシリアライズできません"
|
22
|
+
def_exception :CantDup, "%sはdupできません"
|
23
|
+
def_exception :CantDeepCopy, "%sはdeep copyできません"
|
24
|
+
|
25
|
+
def_exception :SessionServiceStopped, "Session service stopped"
|
26
|
+
def_exception :DisconnectClient, "%sの接続が切れました"
|
27
|
+
def_exception :ConnectCancel, "%sの接続を拒否しました"
|
28
|
+
def_exception :ConnectionRefused, "%sへの接続が拒否されました"
|
29
|
+
|
30
|
+
def_exception :InternalError, "DeepConnect internal error(%s)"
|
31
|
+
def_exception :ProtocolError, "Protocol error!!"
|
32
|
+
|
33
|
+
|
34
|
+
def self.InternalError(message)
|
35
|
+
DC.Raise InternalError, message
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# future.rb -
|
4
|
+
# Copyright (C) 1996-2010 Keiju ISHITSUKA
|
5
|
+
# (Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
#
|
7
|
+
# --
|
8
|
+
#
|
9
|
+
# v = DeepConnect::future{exp}
|
10
|
+
# v = DeepConnect::Future.future{exp}
|
11
|
+
#
|
12
|
+
#
|
13
|
+
|
14
|
+
require "thread"
|
15
|
+
require "delegate"
|
16
|
+
|
17
|
+
module DeepConnect
|
18
|
+
def future(&block)
|
19
|
+
Future.new(&block)
|
20
|
+
end
|
21
|
+
module_function :future
|
22
|
+
|
23
|
+
class Future < Delegator
|
24
|
+
|
25
|
+
NULLVALUE = :__DEEPCONNECT_FUTURE_NULLVALUE__
|
26
|
+
|
27
|
+
def self.future(&block)
|
28
|
+
Futre.new(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(&block)
|
32
|
+
super(@value = NULLVALUE)
|
33
|
+
@value_mutex = Mutex.new
|
34
|
+
@value_cv = ConditionVariable.new
|
35
|
+
Thread.start do
|
36
|
+
@value = yield
|
37
|
+
@value_cv.broadcast
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def __setobj__(dummy); end
|
42
|
+
|
43
|
+
def value
|
44
|
+
@value_mutex.synchronize do
|
45
|
+
while @value == NULLVALUE
|
46
|
+
@value_cv.wait(@value_mutex)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@value
|
50
|
+
end
|
51
|
+
alias __getobj__ value
|
52
|
+
|
53
|
+
def value?
|
54
|
+
@value != NULLVALUE
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
if @value == NULLVALUE
|
59
|
+
"#<DeepConnect::Future: (NOT ARRIVED)>"
|
60
|
+
else
|
61
|
+
"#<DeepConnect::Future: #{@value.inspect}>"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
@@ -0,0 +1,378 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# organizer.rb -
|
4
|
+
# Copyright (C) 1996-2010 Keiju ISHITSUKA
|
5
|
+
# (Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
#
|
7
|
+
|
8
|
+
require "forwardable"
|
9
|
+
require "monitor"
|
10
|
+
require "resolv"
|
11
|
+
require "ipaddr"
|
12
|
+
|
13
|
+
require "deep-connect/class-spec-space"
|
14
|
+
|
15
|
+
require "matrix"
|
16
|
+
|
17
|
+
module DeepConnect
|
18
|
+
class Organizer
|
19
|
+
@CLASS_SPEC_SPACE = ClassSpecSpace.new(:local)
|
20
|
+
|
21
|
+
extend SingleForwardable
|
22
|
+
|
23
|
+
def_delegator :@CLASS_SPEC_SPACE, :class_specs
|
24
|
+
def_delegator :@CLASS_SPEC_SPACE, :def_method_spec
|
25
|
+
def_delegator :@CLASS_SPEC_SPACE, :def_single_method_spec
|
26
|
+
def_delegator :@CLASS_SPEC_SPACE, :def_interface
|
27
|
+
def_delegator :@CLASS_SPEC_SPACE, :def_single_interface
|
28
|
+
def_delegator :@CLASS_SPEC_SPACE, :method_spec
|
29
|
+
def_delegator :@CLASS_SPEC_SPACE, :class_spec_id_of
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
require "deep-connect/accepter"
|
34
|
+
require "deep-connect/evaluator"
|
35
|
+
require "deep-connect/deep-space"
|
36
|
+
require "deep-connect/port"
|
37
|
+
require "deep-connect/event"
|
38
|
+
require "deep-connect/cron"
|
39
|
+
require "deep-connect/exceptions"
|
40
|
+
|
41
|
+
trap("SIGPIPE", "IGNORE")
|
42
|
+
|
43
|
+
module DeepConnect
|
44
|
+
|
45
|
+
class Organizer
|
46
|
+
def initialize
|
47
|
+
@shallow_connect = false
|
48
|
+
|
49
|
+
@accepter = Accepter.new(self)
|
50
|
+
@evaluator = Evaluator.new(self)
|
51
|
+
|
52
|
+
@services = {}
|
53
|
+
@services_mx = Mutex.new
|
54
|
+
@services_cv = ConditionVariable.new
|
55
|
+
|
56
|
+
@messageqs = {}
|
57
|
+
@messageqs_mx = Mutex.new
|
58
|
+
@messageqs_cv = ConditionVariable.new
|
59
|
+
|
60
|
+
@deep_spaces = {}
|
61
|
+
@deep_spaces_mon = Monitor.new
|
62
|
+
@deep_spaces_cv = @deep_spaces_mon.new_cond
|
63
|
+
|
64
|
+
@cron = Cron.new(self)
|
65
|
+
|
66
|
+
@when_connect_proc = proc{true}
|
67
|
+
@when_disconnect_proc = proc{}
|
68
|
+
|
69
|
+
@local_id_mutex = Mutex.new
|
70
|
+
@local_id_cv = ConditionVariable.new
|
71
|
+
@local_id = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_accessor :shallow_connect
|
75
|
+
alias shallow_connect? shallow_connect
|
76
|
+
|
77
|
+
attr_reader :accepter
|
78
|
+
attr_reader :evaluator
|
79
|
+
|
80
|
+
def tick
|
81
|
+
@cron.tick
|
82
|
+
end
|
83
|
+
|
84
|
+
def deep_spaces
|
85
|
+
@deep_spaces
|
86
|
+
end
|
87
|
+
|
88
|
+
def local_id
|
89
|
+
@local_id_mutex.synchronize do
|
90
|
+
while !@local_id
|
91
|
+
@local_id_cv.wait(@local_id_mutex)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
@local_id
|
95
|
+
end
|
96
|
+
|
97
|
+
def start(service)
|
98
|
+
@accepter.open(service)
|
99
|
+
@local_id = @accepter.port_number
|
100
|
+
@local_id_cv.broadcast
|
101
|
+
|
102
|
+
@accepter.start
|
103
|
+
@cron.start
|
104
|
+
end
|
105
|
+
|
106
|
+
def stop
|
107
|
+
@accepter.stop
|
108
|
+
end
|
109
|
+
|
110
|
+
IPADDR_REGEXP = /(::ffff:)?([0-9]+\.){3}[0-9]+|[0-9a-f]+:([0-9a-f]*:)[0-9a-f]*/
|
111
|
+
# client sesssion開始
|
112
|
+
def open_deep_space(host, port)
|
113
|
+
|
114
|
+
@deep_spaces_mon.synchronize do
|
115
|
+
ipaddr = nil
|
116
|
+
if IPADDR_REGEXP !~ host
|
117
|
+
Resolv.each_address(host) do |addr|
|
118
|
+
ipaddr = IPAddr.new(addr)
|
119
|
+
ipaddr = ipaddr.native.to_s
|
120
|
+
|
121
|
+
peer_id = [ipaddr, port]
|
122
|
+
if deep_space = @deep_spaces[peer_id]
|
123
|
+
return deep_space
|
124
|
+
end
|
125
|
+
end
|
126
|
+
else
|
127
|
+
ipaddr = IPAddr.new(host)
|
128
|
+
ipaddr = ipaddr.native.to_s
|
129
|
+
|
130
|
+
peer_id = [ipaddr, port]
|
131
|
+
if deep_space = @deep_spaces[peer_id]
|
132
|
+
return deep_space
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
sock = TCPSocket.new(ipaddr, port)
|
137
|
+
port = Port.new(sock)
|
138
|
+
init_session_ev = Event::InitSessionEvent.new(local_id)
|
139
|
+
port.export init_session_ev
|
140
|
+
connect_deep_space_with_port(port)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
alias open_deepspace open_deep_space
|
144
|
+
|
145
|
+
def close_deep_space(deep_space)
|
146
|
+
disconnect_deep_space(deep_space)
|
147
|
+
end
|
148
|
+
alias close_deepspace close_deep_space
|
149
|
+
|
150
|
+
def deep_space(peer_id, &block)
|
151
|
+
@deep_spaces_mon.synchronize do
|
152
|
+
if deep_space = @deep_spaces[peer_id]
|
153
|
+
return deep_space
|
154
|
+
end
|
155
|
+
|
156
|
+
# セッションを自動的に開く
|
157
|
+
begin
|
158
|
+
deep_space = open_deep_space(*peer_id)
|
159
|
+
block.call deep_space if block_given?
|
160
|
+
deep_space
|
161
|
+
rescue ConnectionRefused, Errno::ECONNREFUSED
|
162
|
+
puts "WARN: クライアント(#{peer_id}への接続が拒否されました"
|
163
|
+
return DeepSpaceNoConnection.new(peer_id)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
alias deepspace deep_space
|
168
|
+
|
169
|
+
# sessionサービス開始
|
170
|
+
def connect_deep_space_with_port(port, local_id = nil)
|
171
|
+
@deep_spaces_mon.synchronize do
|
172
|
+
deep_space = DeepSpace.new(self, port, local_id)
|
173
|
+
port.attach(deep_space.session)
|
174
|
+
# uuid = session.peer_id unless uuid
|
175
|
+
if @deep_spaces[deep_space.peer_uuid]
|
176
|
+
# ポート番号が再利用されているときは, 既存の方はすでにおなくな
|
177
|
+
# りになっている
|
178
|
+
old = @deep_spaces[deep_space.peer_uuid]
|
179
|
+
puts "INFO: port no recyicled"
|
180
|
+
puts "INFO: disconnect recycled deep_space: #{old}"
|
181
|
+
|
182
|
+
disconnect_deep_space(old, :SESSION_CLOSED)
|
183
|
+
end
|
184
|
+
unless @when_connect_proc.call deep_space, port
|
185
|
+
puts "CONNECT Canceld DeepSpace: #{deep_space.peer_uuid}" if Conf.DEBUG
|
186
|
+
connect_ev = Event::ConnectResult.new(false)
|
187
|
+
port.export connect_ev
|
188
|
+
|
189
|
+
disconnect_deep_space(deep_space)
|
190
|
+
DC::Raise ConnectCancel, deep_space
|
191
|
+
end
|
192
|
+
|
193
|
+
connect_ev = Event::ConnectResult.new(true)
|
194
|
+
port.export connect_ev
|
195
|
+
|
196
|
+
ev = port.import
|
197
|
+
if ev.kind_of?(Event::ConnectResult)
|
198
|
+
unless ev.result
|
199
|
+
DC::Raise ConnectionRefused, deep_space
|
200
|
+
end
|
201
|
+
else
|
202
|
+
DC::Raise ProtocolError, deep_space
|
203
|
+
end
|
204
|
+
|
205
|
+
@deep_spaces[deep_space.peer_uuid] = deep_space
|
206
|
+
|
207
|
+
puts "CONNECT DeepSpace: #{deep_space.peer_uuid}" if Conf.DEBUG
|
208
|
+
deep_space.connect
|
209
|
+
deep_space
|
210
|
+
end
|
211
|
+
end
|
212
|
+
alias connect_deepspace_with_port connect_deep_space_with_port
|
213
|
+
|
214
|
+
def disconnect_deep_space(deep_space, *opts)
|
215
|
+
@deep_spaces_mon.synchronize do
|
216
|
+
@deep_spaces.delete(deep_space.peer_uuid)
|
217
|
+
end
|
218
|
+
deep_space.disconnect(*opts)
|
219
|
+
@when_disconnect_proc.call(deep_space, opts)
|
220
|
+
end
|
221
|
+
|
222
|
+
def when_connected(&block)
|
223
|
+
@when_connect_proc = block
|
224
|
+
end
|
225
|
+
|
226
|
+
def when_disconnected(&block)
|
227
|
+
@when_disconnect_proc = block
|
228
|
+
end
|
229
|
+
|
230
|
+
#
|
231
|
+
def keep_alive
|
232
|
+
puts "KEEP ALIVE: Start" if Conf.DISPLAY_KEEP_ALIVE
|
233
|
+
for uuid, deep_space in @deep_spaces.dup
|
234
|
+
unless deep_space.session.keep_alive
|
235
|
+
disconnect_deep_space(deep_space, :SESSION_CLOSED)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
# services
|
242
|
+
def register_service(name, obj)
|
243
|
+
@services_mx.synchronize do
|
244
|
+
@services[name] = obj
|
245
|
+
@services_cv.broadcast
|
246
|
+
end
|
247
|
+
end
|
248
|
+
alias export register_service
|
249
|
+
|
250
|
+
def service(name, waitp = false)
|
251
|
+
@services_mx.synchronize do
|
252
|
+
until @services.key?(name)
|
253
|
+
if waitp
|
254
|
+
@services_cv.wait(@services_mx)
|
255
|
+
else
|
256
|
+
return :DEEPCONNECT_NO_SUCH_SERVICE
|
257
|
+
end
|
258
|
+
end
|
259
|
+
@services[name]
|
260
|
+
end
|
261
|
+
end
|
262
|
+
alias import service
|
263
|
+
|
264
|
+
# MQ
|
265
|
+
def export_mq(name)
|
266
|
+
@messageqs_mx.synchronize do
|
267
|
+
@messageqs[name] = DeepMQ::SV.new(self)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
alias register_mq export_mq
|
271
|
+
|
272
|
+
def get_mq(name, waitp = false)
|
273
|
+
@messageqs_mx.synchronize do
|
274
|
+
until @messageqs.key?(name)
|
275
|
+
if waitp
|
276
|
+
@messageqs_cv.wait(@messageqs_mx)
|
277
|
+
else
|
278
|
+
return nil
|
279
|
+
end
|
280
|
+
end
|
281
|
+
@messageqs[name]
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def release_object(obj)
|
286
|
+
for id, dspace in @deep_spaces.dup
|
287
|
+
dspace.release_object(obj)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def id2obj(id)
|
292
|
+
@deep_spaces_mon.synchronize do
|
293
|
+
for peer_id, s in @deep_spaces
|
294
|
+
if o = s.root(id) and !o.kind_of?(IllegalObject)
|
295
|
+
# if o = s.root(id) and o != :__DEEPCONNECT_NO_VALUE__
|
296
|
+
return o
|
297
|
+
end
|
298
|
+
end
|
299
|
+
# begin
|
300
|
+
# ObjectSpace._id2ref(id)
|
301
|
+
# rescue
|
302
|
+
# end
|
303
|
+
# sleep 5
|
304
|
+
IllegalObject.new(id)
|
305
|
+
end
|
306
|
+
# DC::InternalError "deep_spaceにid(=#{id})をobject_idとするオブジェクトが登録されていません.)"
|
307
|
+
end
|
308
|
+
|
309
|
+
@@ABSOLUTE_IMMUTABLE_CLASSES = [
|
310
|
+
NilClass,
|
311
|
+
TrueClass,
|
312
|
+
FalseClass,
|
313
|
+
Symbol,
|
314
|
+
Fixnum,
|
315
|
+
Bignum,
|
316
|
+
Range,
|
317
|
+
Rational
|
318
|
+
]
|
319
|
+
|
320
|
+
@@DEFAULT_IMMUTABLE_CLASSES = [
|
321
|
+
Numeric,
|
322
|
+
String,
|
323
|
+
Regexp,
|
324
|
+
MatchData,
|
325
|
+
Range,
|
326
|
+
Time,
|
327
|
+
File::Stat,
|
328
|
+
Matrix,
|
329
|
+
Vector,
|
330
|
+
Matrix::Scalar
|
331
|
+
]
|
332
|
+
|
333
|
+
@@IMMUTABLE_CLASSES = @@ABSOLUTE_IMMUTABLE_CLASSES +
|
334
|
+
@@DEFAULT_IMMUTABLE_CLASSES
|
335
|
+
|
336
|
+
def self.absolute_immutable_classes
|
337
|
+
@@ABSOLUTE_IMMUTABLE_CLASSES
|
338
|
+
end
|
339
|
+
def self.default_immutable_classes
|
340
|
+
@@DEFAULT_IMMUTABLE_CLASSES
|
341
|
+
end
|
342
|
+
def self.immutable_classes
|
343
|
+
@@IMMUTABLE_CLASSES
|
344
|
+
end
|
345
|
+
|
346
|
+
def_interface(Exception, :message)
|
347
|
+
|
348
|
+
def_method_spec(Exception, "VAL backtrace()")
|
349
|
+
def_interface(Exception, :backtrace)
|
350
|
+
|
351
|
+
def_method_spec(Exception, "REF set_backtrace(VAL)")
|
352
|
+
|
353
|
+
def_method_spec(Object, "VAL to_a()")
|
354
|
+
#def_method_spec(Object, "VAL to_s()")
|
355
|
+
def_method_spec(Object, "VAL to_ary()")
|
356
|
+
def_method_spec(Object, "VAL to_str()")
|
357
|
+
def_method_spec(Object, "VAL to_int()")
|
358
|
+
def_method_spec(Object, "VAL to_regexp()")
|
359
|
+
def_method_spec(Object, "VAL to_splat()")
|
360
|
+
|
361
|
+
def_method_spec(Array, :method=> :-, :args=> "VAL")
|
362
|
+
def_method_spec(Array, :method=> :&, :args=> "VAL")
|
363
|
+
def_method_spec(Array, :method=> :|, :args=> "VAL")
|
364
|
+
def_method_spec(Array, :method=> :<=>, :args=> "VAL")
|
365
|
+
def_method_spec(Array, :method=> :==, :args=> "VAL")
|
366
|
+
|
367
|
+
#def_single_method_spec(Regexp, :method=> :union, :args=> "*DVAL")
|
368
|
+
|
369
|
+
def_method_spec(Hash, "merge(VAL)")
|
370
|
+
def_method_spec(Hash, :method=> :merge!, :args=> "VAL")
|
371
|
+
def_method_spec(Hash, "replace(VAL)")
|
372
|
+
def_method_spec(Hash, "update(VAL)")
|
373
|
+
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
require "deep-connect/deep-mq"
|
378
|
+
|