YkLib 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.
Files changed (125) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +6 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +7 -0
  7. data/Gemfile.lock +34 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +44 -0
  10. data/Rakefile +6 -0
  11. data/YkLib.gemspec +29 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/lib/YkLib/Yk/__advance__.rb +151 -0
  15. data/lib/YkLib/Yk/__defun__.rb +44 -0
  16. data/lib/YkLib/Yk/__hook__.rb +244 -0
  17. data/lib/YkLib/Yk/__minmax__.rb +123 -0
  18. data/lib/YkLib/Yk/__stdlog.rb +329 -0
  19. data/lib/YkLib/Yk/adhocLiterals/email.rb +119 -0
  20. data/lib/YkLib/Yk/adhocLiterals/path.rb +402 -0
  21. data/lib/YkLib/Yk/adhocLiterals/tag.rb +19 -0
  22. data/lib/YkLib/Yk/adhocLiterals/url.rb +36 -0
  23. data/lib/YkLib/Yk/adhocLiterals.rb +199 -0
  24. data/lib/YkLib/Yk/auto_escseq.rb +5 -0
  25. data/lib/YkLib/Yk/auto_pstore.rb +179 -0
  26. data/lib/YkLib/Yk/bsearch.rb +120 -0
  27. data/lib/YkLib/Yk/clambda.rb +309 -0
  28. data/lib/YkLib/Yk/confLine.rb +423 -0
  29. data/lib/YkLib/Yk/create_tty_width_available.rb +24 -0
  30. data/lib/YkLib/Yk/crypt.rb +26 -0
  31. data/lib/YkLib/Yk/debug2 +1 -0
  32. data/lib/YkLib/Yk/debug2.rb +473 -0
  33. data/lib/YkLib/Yk/debugout.rb +139 -0
  34. data/lib/YkLib/Yk/email_tz.rb +533 -0
  35. data/lib/YkLib/Yk/enum_expect.rb +170 -0
  36. data/lib/YkLib/Yk/errlog.rb +5 -0
  37. data/lib/YkLib/Yk/escseq.rb +59 -0
  38. data/lib/YkLib/Yk/eval_alt.rb +281 -0
  39. data/lib/YkLib/Yk/expector.rb +93 -0
  40. data/lib/YkLib/Yk/fetch.rb +556 -0
  41. data/lib/YkLib/Yk/fetch_old.rb +290 -0
  42. data/lib/YkLib/Yk/fib.rb +158 -0
  43. data/lib/YkLib/Yk/file_aux.rb +843 -0
  44. data/lib/YkLib/Yk/file_aux2.rb +919 -0
  45. data/lib/YkLib/Yk/file_aux_old.rb +160 -0
  46. data/lib/YkLib/Yk/filemod.rb +19 -0
  47. data/lib/YkLib/Yk/force_escseq.rb +3 -0
  48. data/lib/YkLib/Yk/generator__.rb +144 -0
  49. data/lib/YkLib/Yk/generator__.rb.org +139 -0
  50. data/lib/YkLib/Yk/indenter/argless_case.rb +46 -0
  51. data/lib/YkLib/Yk/indenter/each_token.rb +671 -0
  52. data/lib/YkLib/Yk/indenter/free_case.rb +313 -0
  53. data/lib/YkLib/Yk/indenter/if_less.rb +53 -0
  54. data/lib/YkLib/Yk/indenter/independent_ensure.rb +23 -0
  55. data/lib/YkLib/Yk/indenter/independent_rescue.rb +23 -0
  56. data/lib/YkLib/Yk/indenter/operand_circumflex.rb +0 -0
  57. data/lib/YkLib/Yk/indenter/operand_period.rb +16 -0
  58. data/lib/YkLib/Yk/indenter/parenless_and.rb +37 -0
  59. data/lib/YkLib/Yk/indenter/post_test.rb +48 -0
  60. data/lib/YkLib/Yk/indenter/token.rb +1525 -0
  61. data/lib/YkLib/Yk/indenter.rb +1382 -0
  62. data/lib/YkLib/Yk/inot.rb +265 -0
  63. data/lib/YkLib/Yk/intf.rb +815 -0
  64. data/lib/YkLib/Yk/io_aux.rb +1332 -0
  65. data/lib/YkLib/Yk/ioctl.rb +60 -0
  66. data/lib/YkLib/Yk/ipcc.rb +87 -0
  67. data/lib/YkLib/Yk/ipcountry.rb +207 -0
  68. data/lib/YkLib/Yk/ipv4adr.rb +318 -0
  69. data/lib/YkLib/Yk/localmail.rb +276 -0
  70. data/lib/YkLib/Yk/method_chain.rb +359 -0
  71. data/lib/YkLib/Yk/misc_tz.rb +1716 -0
  72. data/lib/YkLib/Yk/missing_method.rb +50 -0
  73. data/lib/YkLib/Yk/mojiConv.rb +257 -0
  74. data/lib/YkLib/Yk/nostdlog.rb +4 -0
  75. data/lib/YkLib/Yk/on_marshal.rb +20 -0
  76. data/lib/YkLib/Yk/overrider.rb +47 -0
  77. data/lib/YkLib/Yk/path.rb +293 -0
  78. data/lib/YkLib/Yk/path_aux.rb +883 -0
  79. data/lib/YkLib/Yk/path_aux_alt.rb +0 -0
  80. data/lib/YkLib/Yk/path_rep.rb +1267 -0
  81. data/lib/YkLib/Yk/pg_setup.rb +917 -0
  82. data/lib/YkLib/Yk/procinfo.rb +314 -0
  83. data/lib/YkLib/Yk/proclist.rb +492 -0
  84. data/lib/YkLib/Yk/property.rb +863 -0
  85. data/lib/YkLib/Yk/ranger.rb +606 -0
  86. data/lib/YkLib/Yk/resolv_tz.rb +88 -0
  87. data/lib/YkLib/Yk/rlprompt.rb +73 -0
  88. data/lib/YkLib/Yk/rootexec.rb +48 -0
  89. data/lib/YkLib/Yk/rpm-packageproxy.rb +784 -0
  90. data/lib/YkLib/Yk/rpm-packageproxy2.rb +1430 -0
  91. data/lib/YkLib/Yk/rwhen.rb +21 -0
  92. data/lib/YkLib/Yk/selector.rb +124 -0
  93. data/lib/YkLib/Yk/set.rb +170 -0
  94. data/lib/YkLib/Yk/shellquote.rb +300 -0
  95. data/lib/YkLib/Yk/sio.rb +1001 -0
  96. data/lib/YkLib/Yk/sio0.rb +835 -0
  97. data/lib/YkLib/Yk/sio_aux.rb +1524 -0
  98. data/lib/YkLib/Yk/sio_inot.rb +86 -0
  99. data/lib/YkLib/Yk/sock_aux.rb +42 -0
  100. data/lib/YkLib/Yk/spipe.rb +843 -0
  101. data/lib/YkLib/Yk/sql_table.rb +565 -0
  102. data/lib/YkLib/Yk/stdlog.rb +4 -0
  103. data/lib/YkLib/Yk/syscommand.rb +173 -0
  104. data/lib/YkLib/Yk/sysinit.rb +75 -0
  105. data/lib/YkLib/Yk/ttyFontWidth.rb +46113 -0
  106. data/lib/YkLib/Yk/tty_char.dump +0 -0
  107. data/lib/YkLib/Yk/tty_char.rb +47 -0
  108. data/lib/YkLib/Yk/tty_char_create.rb +437031 -0
  109. data/lib/YkLib/Yk/tty_char_static.rb +437016 -0
  110. data/lib/YkLib/Yk/tty_rewrite.rb +142 -0
  111. data/lib/YkLib/Yk/tty_str.rb +461 -0
  112. data/lib/YkLib/Yk/tty_width.dat.rb +114 -0
  113. data/lib/YkLib/Yk/tty_width.rb +180 -0
  114. data/lib/YkLib/Yk/tty_width_available +569 -0
  115. data/lib/YkLib/Yk/tty_width_list +0 -0
  116. data/lib/YkLib/Yk/tty_width_list.linux +280 -0
  117. data/lib/YkLib/Yk/tty_width_list.windows +324 -0
  118. data/lib/YkLib/Yk/tz_tty +0 -0
  119. data/lib/YkLib/Yk/tz_tty.rb +0 -0
  120. data/lib/YkLib/Yk/uprepos.rb +94 -0
  121. data/lib/YkLib/Yk/userinfo.rb +91 -0
  122. data/lib/YkLib/Yk/with.rb +109 -0
  123. data/lib/YkLib/version.rb +3 -0
  124. data/lib/YkLib.rb +6 -0
  125. metadata +170 -0
@@ -0,0 +1,843 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ require 'Yk/__minmax__'
5
+ require 'Yk/proclist'
6
+ require 'Yk/path_aux'
7
+ require 'Yk/misc_tz'
8
+ require 'Yk/syscommand'
9
+ require 'Yk/io_aux'
10
+ require 'thread'
11
+
12
+
13
+ Process.set_kill_with_children
14
+
15
+ require 'Yk/__hook__'
16
+
17
+
18
+ class ResultObj
19
+ def error?
20
+ @isError
21
+ end
22
+ def error
23
+ @isError ? @obj : nil
24
+ end
25
+ def result
26
+ !@isError ? @obj : nil
27
+ end
28
+ def initialize (obj, isError = false)
29
+ @obj = obj
30
+ @isError = isError
31
+ end
32
+ end
33
+
34
+
35
+ class RemoteProcedure
36
+ attr_reader :obj, :path, :name
37
+ def initialize (obj, path, name, *args, &bl)
38
+ @obj = obj
39
+ @path = path
40
+ @name = name
41
+ @args = args
42
+ bl && (@has_block = true)
43
+ end
44
+ def has_block?
45
+ @has_block
46
+ end
47
+ def remote?
48
+ @path != nil
49
+ end
50
+ def call (manager)
51
+ result = nil
52
+ if @path != nil && @path.strip != ""
53
+ newPathArr = @path.split /:/
54
+ if Etc.getpwuid(Process.euid).name != newPathArr[0]
55
+ remoteManager = RemoteManager.connect(nil, newPathArr[0], *manager.stdPipes)
56
+ end
57
+ end
58
+ if remoteManager
59
+ if !@has_block
60
+ remoteManager.callRemote @obj, newPathArr[1..-1], *@args
61
+ else
62
+ remoteManager.callRemote @obj, newPathArr[1..-1], *@args do |*args|
63
+ yield *args
64
+ end
65
+ end
66
+ else
67
+ begin
68
+ if !@has_block
69
+ res = (@obj || manager).method(@name).call *@args
70
+ else
71
+ res = (@obj || manager).method(@name).call *@args do |*args|
72
+ yield *args
73
+ end
74
+ end
75
+ ResultObj.new(res, false)
76
+ rescue Exception, SignalException => e
77
+ ResultObj.new(e, true)
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+
84
+ class BlockCaller
85
+ def initialize (*args)
86
+ @args = args
87
+ end
88
+ def execute (&bl)
89
+ bl.call(*@args)
90
+ end
91
+ end
92
+
93
+
94
+ class RemoteManager
95
+ def inspect
96
+ [@utilityPipe, @requester, @requestee, @cleaner].inspect
97
+ end
98
+ class RemoteObj
99
+ def initialize (obj, remoteManager, path)
100
+ @obj = obj
101
+ @remoteManager = remoteManager
102
+ @path = path
103
+ end
104
+ def method_missing (name, *args, &bl)
105
+ @remoteManager.callRemote @obj, @path, name, *args, &bl
106
+ end
107
+ end
108
+ @@newMutex = Mutex.new
109
+ @@managers = []
110
+ def initialize (remoteHost, mode, *pidOrPipes)
111
+ @@newMutex.synchronize do
112
+ @mutex = Mutex.new
113
+ @mutexId = Mutex.new
114
+ @cMutex = Mutex.new
115
+ @channels = Hash.new
116
+ @threads = []
117
+ @fps = []
118
+ @closeProcs = []
119
+ @idLast = -1
120
+ @started = false
121
+ case mode
122
+ when :client
123
+ startClient(remoteHost, *pidOrPipes)
124
+ when :server
125
+ startServer(*pidOrPipes)
126
+ else
127
+ startSecondServer(remoteHost, mode, *pidOrPipes)
128
+ end
129
+ at_exit do
130
+ close
131
+ end
132
+ @@managers.push self
133
+ end
134
+ end
135
+ def join
136
+ @threads.each do |e|
137
+ e.join
138
+ end
139
+ @closed = true
140
+ end
141
+ def send (id, buff)
142
+ header = [id, buff.size].pack("i*")
143
+ @mutex.synchronize do
144
+ @ioAfterEncode.write header
145
+ @ioAfterEncode.write buff
146
+ @ioAfterEncode.flush
147
+ end
148
+ end
149
+ def checkId
150
+ @mode == :client ? offset = 35576 * 2 : offset = 35576
151
+ id = nil
152
+ @mutexId.synchronize do
153
+ if @idLast >= 35576
154
+ raise ArguemntError.new("two big id (#{id ? id : @@idLast + 1}) specified.")
155
+ end
156
+ id = (@idLast += 1) + offset
157
+ end
158
+ id
159
+ end
160
+ def setEncoder (io)
161
+ @ioAfterEncode = io
162
+ end
163
+ def setDecoder (io)
164
+ @decoderIO = io
165
+ @readThread = Thread.new do
166
+ begin
167
+ cid = nil
168
+ buff = ""
169
+ while true
170
+ begin
171
+ if (tmp = io.read(8)) == nil
172
+ break
173
+ end
174
+ cid, sz = tmp.unpack("i*")
175
+ io.read(sz, buff)
176
+ rescue EOFError
177
+ break
178
+ end
179
+ if @channels[cid]
180
+ @channels[cid].write buff
181
+ end
182
+ end
183
+ rescue EOFError
184
+ rescue IOError => e
185
+ raise if e.to_s !~ /stream closed/
186
+ end
187
+ end
188
+ end
189
+ def closeDecoder
190
+ @decoderIO.close
191
+ end
192
+ def ioproxy (*args)
193
+ if args.size == 2
194
+ idOrIo, mode = args
195
+ else
196
+ idOrIo, mode = args[0]
197
+ end
198
+ if !(ipxr = @channels[idOrIo])
199
+ ipxr = @channels[idOrIo] = IOProxy.new(self, idOrIo, mode)
200
+ if idOrIo.is_a? IO
201
+ @channels[ipxr.id] = ipxr
202
+ else # idOrIo.is_a? Integer
203
+ @channels[ipxr.io] = ipxr
204
+ end
205
+ end
206
+ ipxr
207
+ end
208
+
209
+ def sendClose (id, oprt)
210
+ @cMutex.synchronize do
211
+ @cleaner.write_obj [id, oprt]
212
+ end
213
+ end
214
+
215
+ def remove (id, io)
216
+ @channels.delete id
217
+ @channels.delete(io)
218
+ end
219
+
220
+ class AlreadyConnected < Exception
221
+ def initialize (obj, msg)
222
+ super msg
223
+ @obj = obj
224
+ end
225
+ end
226
+
227
+ @@canonRemoteNames = Hash.new
228
+ def @@canonRemoteNames.insert (k, v)
229
+ if k && !@@canonRemoteNames.key?(k)
230
+ @@canonRemoteNames[k] = v
231
+ else
232
+ raise AlreadyConnected.new(@@canonRemoteNames[k], "#{v} is already used")
233
+ end
234
+ end
235
+
236
+ def addThread (t)
237
+ @threads.push t
238
+ end
239
+
240
+ def startClient (remoteHost, *stdPipes)
241
+ _in, _out, _err = stdPipes
242
+ @mode = :client
243
+ @stdPipes = stdPipes
244
+ magic = rand(100000000).to_s
245
+ f0, f1, f2 = [$0, "--spipe-magic=#{magic}", "--spipe-base=#{@@base}", "--spipe-remote=#{@@local}"].popen3_at(remoteHost)
246
+ echoOff = nil
247
+ orgMode = nil
248
+ controlStarted = false
249
+ tb = nil
250
+ begin
251
+ if _in.tty?
252
+ orgMode = _in.stty_mode
253
+ if orgMode != (echoOff = orgMode & ~Termios::ECHO)
254
+ _in.stty_mode = echoOff
255
+ end
256
+ end
257
+ ta = _in.transfer_to(f0)
258
+ tb = f2.transfer_to(_err)
259
+ f1.transfer_to(_out, magic) do
260
+ ta.terminate
261
+ ta.join
262
+ f0.flush
263
+ f0.tty? && f0.set_raw
264
+ f0.write_obj magic
265
+ f0.flush
266
+ controlStarted = true
267
+ tb.terminate
268
+ end
269
+ tb.join
270
+ ensure
271
+ if echoOff
272
+ _in.stty_mode = orgMode
273
+ end
274
+ end
275
+ if !controlStarted
276
+ raise Exception.new("failed to connect to #{remoteHost}")
277
+ end
278
+ setEncoder(f0)
279
+ f1.tty? && f1.set_raw
280
+ addThread setDecoder(f1)
281
+ @utilityPipe = ioproxy(0, "r+")
282
+ @requester = ioproxy(1, "r+")
283
+ @requestee = ioproxy(2, "r+")
284
+ @cleaner = ioproxy(3, "r+")
285
+ @canonRemoteName = @utilityPipe.read_obj
286
+ begin
287
+ @@canonRemoteNames.insert @canonRemoteName, self
288
+ rescue AlreadyConnected => e
289
+ @utilityPipe.write_obj nil
290
+ raise
291
+ end
292
+ @utilityPipe.write_obj @@local
293
+ addThread answerLoop
294
+ addThread startCleaner
295
+ callRemote(nil, nil, :setStdPipes, _in, _out, _err)
296
+ end
297
+
298
+ def setStdPipes (_in, _out, _err)
299
+ if @isFirstServer
300
+ STDIN.reopen _in
301
+ STDOUT.reopen _out
302
+ recoverErrBuff _err
303
+ end
304
+ @stdPipes = [_in, _out, _err]
305
+ end
306
+
307
+ class IOLog < Array
308
+ def initialize
309
+ super
310
+ @r, @w = IO.pipe
311
+ @r.nonblock = true
312
+ @w.nonblock = true
313
+ @thread = Thread.new do
314
+ cmd = ["/usr/bin/multilog", "t", "#{ENV['HOME']}/.spipe/log/#{$0.basename}".check_dir]
315
+ cmd.condSQuote.open "pw" do |fw|
316
+ begin
317
+ while true
318
+ push tmp = @r.readpartial(1024)
319
+ fw.write tmp
320
+ fw.flush
321
+ end
322
+ rescue EOFError => e
323
+ end
324
+ end
325
+ end
326
+ end
327
+ def io
328
+ @w
329
+ end
330
+ def terminate
331
+ @thread.terminate
332
+ end
333
+ end
334
+
335
+ def setErrLog
336
+ @errBuff = IOLog.new
337
+ STDERR.reopen @errBuff.io
338
+ end
339
+
340
+ def recoverErrBuff (newIO)
341
+ #@errBuff.terminate
342
+ #newIO.write *@errBuff
343
+ #STDERR.reopen newIO
344
+ end
345
+
346
+ def startServer (magic, _in = STDIN.dup, _out = STDOUT.dup, remote = @@remote, isFirstServer = true)
347
+ @mode = :server
348
+ @isFirstServer = isFirstServer
349
+ _in.nonblock = true
350
+ _out.nonblock = true
351
+ setErrLog
352
+ _out.write magic
353
+ _out.flush
354
+ _out.tty? && _out.set_raw
355
+ _in.tty? && _in.set_raw
356
+ if _in.read_obj != magic
357
+ raise Exception.new("magic string not detected")
358
+ end
359
+ addThread setDecoder(_in)
360
+ setEncoder(_out)
361
+ @utilityPipe = ioproxy(0, "r+")
362
+ @requestee = ioproxy(1, "r+")
363
+ @requester = ioproxy(2, "r+")
364
+ @cleaner = ioproxy(3, "r+")
365
+ begin
366
+ @@canonRemoteNames.insert remote, self
367
+ rescue AlreadyConnected => e
368
+ @utilityPipe.write_obj nil
369
+ close
370
+ raise
371
+ end
372
+ @utilityPipe.write_obj @@local
373
+ if !@utilityPipe.read_obj
374
+ @@canonRemoteNames.delete remote
375
+ close
376
+ raise AlreadyConnected.new(nil, "peer saids already connected")
377
+ end
378
+ addThread answerLoop
379
+ addThread startCleaner
380
+ end
381
+
382
+ def on_close (&bl)
383
+ @closeProcs.push bl
384
+ end
385
+
386
+ def startSecondServer (remote, cid, pid, magic)
387
+ inpipe = self.class.infoDir / "inpipe.#{cid}"
388
+ outpipe = self.class.infoDir / "outpipe.#{cid}"
389
+ delpipe = self.class.infoDir / "delpipe.#{cid}"
390
+ @fps.push _in = inpipe.open("nr")
391
+ @fps.push _out = outpipe.open("nw")
392
+ @fps.push _del = delpipe.open("nw")
393
+ on_close do
394
+ if (tmp = ProcList.pid(pid)) && tmp.prog == $0 && delpipe.exist?
395
+ _del.write_obj nil
396
+ end
397
+ end
398
+ begin
399
+ startServer(magic, _in, _out, remote, false)
400
+ rescue
401
+ _del.write_obj nil
402
+ raise
403
+ end
404
+ end
405
+
406
+ def close (byRemote = false)
407
+ if !@closed
408
+ @@newMutex.synchronize do
409
+ @closed = true
410
+ @closeProcs.each do |e|
411
+ e.call
412
+ end
413
+ @channels.values.uniq.each do |e|
414
+ if e.mode == :proxy
415
+ e.close
416
+ end
417
+ end
418
+ @utilityPipe.close
419
+ @requester.close
420
+ @requestee.close
421
+ byRemote or @cleaner.write_obj "close_all"
422
+ @cleaner.close
423
+ closeDecoder
424
+ @fps.each do |fp|
425
+ fp.closed? || fp.close
426
+ end
427
+ @threads.each do |t|
428
+ t.join if t != Thread.current
429
+ end
430
+ end
431
+ end
432
+ end
433
+
434
+ def startCleaner
435
+ Thread.new do
436
+ begin
437
+ @cleaner.each_obj do |obj|
438
+ if obj == "close_all"
439
+ close(true)
440
+ else
441
+ @channels[obj[0]].closeBySent(obj[1])
442
+ end
443
+ end
444
+ rescue EOFError
445
+ rescue IOError => e
446
+ raise if e.to_s !~ /stream closed/
447
+ end
448
+ end
449
+ end
450
+
451
+ def callRemote (obj, path, funcLabel, *args, &bl)
452
+ @requester.write_obj RemoteProcedure.new(obj, path, funcLabel, *args, &bl)
453
+ ret = nil
454
+ begin
455
+ while answer = @requester.read_obj
456
+ if answer.is_a? BlockCaller
457
+ if bl
458
+ @requester.write_obj answer.execute(&bl)
459
+ else
460
+ @requester.write_obj nil
461
+ end
462
+ elsif answer.is_a? ResultObj
463
+ if path == nil
464
+ if answer.error?
465
+ $! = answer.error
466
+ raise
467
+ else
468
+ ret = answer.result
469
+ end
470
+ break
471
+ else
472
+ ret = answer.result
473
+ break
474
+ end
475
+ else
476
+ raise Exception.new("unknown error")
477
+ end
478
+ end
479
+ rescue EOFError
480
+ end
481
+ ret
482
+ end
483
+
484
+ def answerLoop
485
+ Thread.new do
486
+ begin
487
+ while true
488
+ procedure = @requestee.read_obj
489
+ result = nil
490
+ if procedure.has_block?
491
+ result = procedure.call self do |*args|
492
+ @requestee.write_obj BlockCaller.new(*args)
493
+ @requestee.read_obj
494
+ end
495
+ else
496
+ result = procedure.call self
497
+ end
498
+ @requestee.write_obj result
499
+ end
500
+ rescue EOFError
501
+ rescue IOError => e
502
+ raise if e.to_s !~ /stream closed/
503
+ end
504
+ end
505
+ end
506
+ @@remoteHosts = Hash.new
507
+ def self.connect (tag, remoteHost, *pipes)
508
+ (pipes.size .. 2).each do |i|
509
+ pipes.push [STDIN, STDOUT, STDERR][i]
510
+ end
511
+ arr = remoteHost.split(/:/)
512
+ remoteManager = nil
513
+ begin
514
+ remoteManager = @@remoteHosts[arr[0]] ||= new(arr[0], :client, *pipes)
515
+ rescue AlreadyConnected => e
516
+ remoteManager = e.remoteManager
517
+ end
518
+ if tag
519
+ RemoteObj.__defun__ tag do |obj|
520
+ RemoteObj.new(obj, remoteManager, arr[1..-1].join)
521
+ end
522
+ Object.class_eval %{
523
+ def #{tag}
524
+ RemoteObj.#{tag} self
525
+ end
526
+ }
527
+ end
528
+ remoteManager
529
+ end
530
+ def self.base
531
+ @@base
532
+ end
533
+ HOME = Etc.getpwuid(Process.euid).dir
534
+ def self.infoDir
535
+ HOME / ".spipe" / $0.basename + "--" + @@base
536
+ end
537
+ def self.checkRemoteEntry
538
+ lock = infoDir / "lock--#{@@remote}"
539
+ end
540
+ def self.startSecondTransferAgent (magic)
541
+ cid = nil
542
+ (infoDir / "cpipe.lock").lock_ex do
543
+ rem_cpipe = infoDir / "cpipe.rem"
544
+ cid_cpipe = infoDir / "cpipe.cid"
545
+ rem_cpipe.open "nw" do |f|
546
+ f.write_obj [@@remote, $$.to_i, magic]
547
+ f.flush
548
+ end
549
+ cid_cpipe.open "nr" do |f|
550
+ cid = f.read_obj
551
+ end
552
+ end
553
+ wpipe = infoDir / "inpipe.#{cid}"
554
+ rpipe = infoDir / "outpipe.#{cid}"
555
+ dpipe = infoDir / "delpipe.#{cid}"
556
+ cleanFiles = Proc.new do
557
+ wpipe.rm_f
558
+ rpipe.rm_f
559
+ dpipe.rm_f
560
+ end
561
+ at_exit do
562
+ cleanFiles.call
563
+ end
564
+ wpipe.fifo? || wpipe.mkfifo
565
+ rpipe.fifo? || rpipe.mkfifo
566
+ dpipe.fifo? || dpipe.mkfifo
567
+ t0 = Thread.new do
568
+ dpipe.read
569
+ cleanFiles.call
570
+ exit 0
571
+ end
572
+ STDIN.nonblock = true
573
+ t = Thread.new do
574
+ buff = ""
575
+ wpipe.open "nw" do |fw|
576
+ while true
577
+ STDIN.readpartial 1024, buff
578
+ fw.write buff
579
+ fw.flush
580
+ end
581
+ end
582
+ end
583
+ buff2
584
+ STDOUT.nonblock = true
585
+ rpipe.open "n" do |fr|
586
+ while true
587
+ fr.readpartial 1024, buff2
588
+ STDOUT.write buff2
589
+ STDOUT.flush
590
+ end
591
+ end
592
+ t.join
593
+ end
594
+
595
+ def self.start
596
+ (infoDir / "lock").try_lock_ex
597
+ end
598
+
599
+ @@cid = 0
600
+ def self.startSecondManager
601
+ rem_cpipe = infoDir / "cpipe.rem"
602
+ rem_cpipe.fifo? || rem_cpipe.mkfifo
603
+ cid_cpipe = infoDir / "cpipe.cid"
604
+ cid_cpipe.fifo? || cid_cpipe.mkfifo
605
+ t = Thread.new do
606
+ rem_cpipe.open "n" do |fr|
607
+ fr.each_obj do |rem, agentPid, magic|
608
+ @@cid += 1
609
+ cid_cpipe.open "n" do |fw|
610
+ fw.write_obj @@cid
611
+ end
612
+ new(rem, @@cid, agentPid, magic)
613
+ end
614
+ end
615
+ end
616
+ end
617
+ end
618
+
619
+
620
+ class IO
621
+ def _dump (limit)
622
+ proxy = IOProxy.remoteManagerToDump.ioproxy(self)
623
+ str = Marshal.dump([proxy.id, proxy.fmode], limit)
624
+ str
625
+ end
626
+ def self._load (stream)
627
+ id, fmode = Marshal.load(stream)
628
+ proxy = IOProxy.remoteManagerToLoad.ioproxy(id, fmode.reverse)
629
+ proxy.io
630
+ end
631
+ end
632
+
633
+
634
+ class IOProxy
635
+ attr_reader :id, :fmode, :toRemote, :mode
636
+ def io
637
+ @io || @toRemote
638
+ end
639
+ def check_remove
640
+ if @mode != :life
641
+ @toRemote.closed? || @toRemote.close
642
+ end
643
+ @remoteManager.remove(@id, @idf)
644
+ end
645
+ def write (buff)
646
+ checkWriteThread
647
+ @wMutex.synchronize do
648
+ @residue += buff
649
+ if @residue.size > 0
650
+ @wCv.signal
651
+ end
652
+ end
653
+ end
654
+ def checkWriteThread
655
+ if !@wThread
656
+ @wMutex = Mutex.new
657
+ @wCv = ConditionVariable.new
658
+ Thread.new do
659
+ @wThread = Thread.current
660
+ @wMutex.synchronize do
661
+ while true
662
+ while @residue.size == 0
663
+ @wCv.wait(@wMutex)
664
+ end
665
+ wsz = 0
666
+ begin
667
+ wsz = @toRemote.write_nonblock @residue
668
+ rescue Errno::EAGAIN => e
669
+ Thread.pass
670
+ end
671
+ @residue.slice!(0...wsz)
672
+ end
673
+ end
674
+ end
675
+ end
676
+ end
677
+ def startEncoder
678
+ @thread = Thread.new do
679
+ begin
680
+ buff = ""
681
+ while true
682
+ @toRemote.readpartial(1024, buff)
683
+ @remoteManager.send @id, buff
684
+ end
685
+ rescue EOFError
686
+ rescue Errno::EIO
687
+ retry
688
+ rescue IOError => e
689
+ raise if e.to_s !~ /stream closed/
690
+ end
691
+ end
692
+ end
693
+ public
694
+ def initialize (remoteManager, idOrIO, fmode = nil)
695
+ @remoteManager = remoteManager
696
+ @mutex = Mutex.new
697
+ @residue = ""
698
+ @closeSent = Hash.new
699
+ if idOrIO.is_a? Integer
700
+ @id = idOrIO
701
+ @mode = @id > 35575 ? :proxy : :system
702
+ @io, @toRemote = IO.pipe(fmode)
703
+ @io.nonblock = true
704
+ @toRemote.nonblock = true
705
+ @fmode = fmode.to_fmode
706
+ if @mode == :system
707
+ @io.__hook__ :write_obj do |org|
708
+ IOProxy.__context_var__ :remoteManagerToDump, @remoteManager do
709
+ org.call
710
+ end
711
+ end
712
+ @io.__hook__ :read_obj do |org|
713
+ IOProxy.__context_var__ :remoteManagerToLoad, @remoteManager do
714
+ org.call
715
+ end
716
+ end
717
+ end
718
+ else
719
+ @mode = :life
720
+ @id = @remoteManager.checkId
721
+ @idf = idOrIO
722
+ @toRemote = idOrIO
723
+ @toRemote.nonblock = true
724
+ @toRemote.__defun__ :proxy, self
725
+ @fmode = @toRemote.fmode.reverse
726
+ end
727
+ if @mode != :system
728
+ [:close, :close_write, :close_read].each do |label|
729
+ oprt = IO::CloseOperation.new(label)
730
+ io.__hook__ label, oprt do |org, op|
731
+ !@closeSent[label] && @remoteManager.sendClose(@id, op)
732
+ org.call
733
+ @mode == :proxy && @toRemote.method(op.reverse.to_label).call
734
+ check_remove
735
+ end
736
+ end
737
+ end
738
+ if @toRemote.readable?
739
+ startEncoder
740
+ end
741
+ end
742
+ def write_obj (obj)
743
+ io.write_obj obj
744
+ end
745
+ def read_obj
746
+ io.read_obj
747
+ end
748
+ def each_obj (&bl)
749
+ io.each_obj &bl
750
+ end
751
+ def close
752
+ @mutex.synchronize do
753
+ io.closed? || io.close
754
+ end
755
+ end
756
+ def closeBySent (oprt)
757
+ label = oprt.to_label
758
+ @mutex.synchronize do
759
+ if !@closeSent[label]
760
+ @closeSent[label] = true
761
+ io.method(label).call
762
+ end
763
+ end
764
+ end
765
+ end
766
+
767
+
768
+ class RemoteManager
769
+ @@local = ENV['USER'] + "@" + `hostname`.chomp
770
+ @@base = nil
771
+ ARGV.each_index do |i|
772
+ while i < ARGV.size && ARGV[i] =~ /^\-\-spipe\-base\=(.*)$/
773
+ @@base = $1
774
+ ARGV.slice!(i)
775
+ end
776
+ end
777
+ @@remote = nil
778
+ ARGV.each_index do |i|
779
+ while i < ARGV.size && ARGV[i] =~ /^\-\-spipe\-remote\=(.*)$/
780
+ @@remote = $1
781
+ ARGV.slice!(i)
782
+ end
783
+ end
784
+ magic = nil
785
+ ARGV.each_index do |i|
786
+ while i < ARGV.size && ARGV[i] =~ /^\-\-spipe\-magic\=(.*)$/
787
+ magic = $1
788
+ ARGV.slice!(i)
789
+ end
790
+ end
791
+ if !@@base
792
+ @@base = ENV['USER'] + "@" + `hostname`.chomp
793
+ infoDir.mkdir_p
794
+ if @@base == "localhost.localdomain"
795
+ raise Exception.new("cannot use #{@@base}; please set a unique name to the host")
796
+ end
797
+ if !tmp = start
798
+ raise Exception.new("second instance is not allowed")
799
+ else
800
+ t = startSecondManager
801
+ at_exit do
802
+ t.terminate
803
+ end
804
+ end
805
+ else
806
+ infoDir.mkdir_p
807
+ if !start
808
+ startSecondTransferAgent magic
809
+ exit 0
810
+ else
811
+ t = startSecondManager
812
+ at_exit do
813
+ t.terminate
814
+ end
815
+ m = new(@@remote, :server, magic)
816
+ m.join
817
+ @@managers.each do |mg|
818
+ mg.close
819
+ end
820
+ exit 0
821
+ end
822
+ end
823
+ end
824
+
825
+
826
+ #def main
827
+ # fw, fr, fe = IOProxy.createPipes "mailip -g"
828
+ # fw.write "hello!"
829
+ # println fr.read # "good bye!"
830
+ #end
831
+
832
+ # IOProxy.callRemote :system, "mailip -g" do |fw, fr, fe|
833
+ #
834
+ # end
835
+
836
+
837
+ # fw = remote2["/var/tmp/file"].open "w"
838
+ # remote1["/var/tmp/file"].open "r" do |fr|
839
+ # fr.each_line do |ln|
840
+ # fw.write ln
841
+ # end
842
+ # end
843
+