virtual_module 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd5f0e87cb8b078374f942887d00b5d32e3f2245
4
- data.tar.gz: f350813eb2781d0158ac0d1a931c8a9bd0643ccf
3
+ metadata.gz: ac2dd86960d57e8ca74b66f23d706aa38413ebb6
4
+ data.tar.gz: 870312de88c44be64424e91b4cb507554454c273
5
5
  SHA512:
6
- metadata.gz: a05517f26f04375b0241986354bd9008960f1d57dc3146580165b17d608a4d4e47056605993b40d94f856d07729c7a4e9547fc1fce9a21214c578fa53fa6fe69
7
- data.tar.gz: 7bdf2a597339e02a8fc40a919b79edbddd4de11aabe7a997979e07cb4e280f69632649b82ef1cd5009869a7cd252009683dbafb264a027d7abb01604bf8f86a5
6
+ metadata.gz: 05988bd3c35c324b49600615c9fff85c917d007b604c6799382b460a04241bdf25be0356e649183a54b4c68d8a05d7757cda184cbc70db335a83bbac258a8072
7
+ data.tar.gz: a3c47595572bea85f6f818f55da750d96bb31133e79e7c239aca69adbb2f7ab24f88dec121803e80495253b4aa68e309303057ec5cb6445312008a417478466e
@@ -10,14 +10,24 @@ module VirtualModule
10
10
  require 'virtual_module/version'
11
11
 
12
12
  class << self
13
- def new(methods, **args)
14
- option = {:lang=>:julia, :pkgs=>[], :ipc=>:file}.merge(args)
15
- vm_builder = Builder.new(option[:lang], option[:pkgs], option[:ipc])
16
- vm_builder.add(methods)
13
+ def new(**args)
14
+ format_args = ->(key){
15
+ if args.keys.include?(key)
16
+ args[:lang] = key
17
+ args[:pkgs] = args[key]
18
+ args[:transpiler] ||= nil if key == :python
19
+ end
20
+ }
21
+ [:python, :julia].map{|e| format_args.call(e)}
22
+ option = {:lang=>:julia, :methods=>"", :transpiler=>->(s){Julializer.ruby2julia(s)}, :pkgs=>[], :ipc=>:file}.merge(args)
23
+ vm_builder = Builder.new(option)
24
+ vm_builder.add(option[:methods])
17
25
  vm_builder.build
18
26
  end
19
27
  end
20
28
 
29
+ class RuntimeException < Exception; end
30
+
21
31
  module SexpParser
22
32
  def extract_defs(s)
23
33
  if s.instance_of?(Array) && s[0].instance_of?(Symbol) then
@@ -47,9 +57,20 @@ module VirtualModule
47
57
  class Builder
48
58
  include SexpParser
49
59
 
50
- def initialize(lang=:julia, pkgs=[], ipc=:file)
51
- @provider = instance_eval("#{lang.capitalize}SourceProvider").new(pkgs)
52
- @ipc = instance_eval("#{ipc.to_s.capitalize}IpcInterface").new(@provider)
60
+ ProxyObjectTransmitter = Struct.new(:vmbuilder, :receiver) do
61
+ def convert_to(target_oid)
62
+ (target_oid == vmbuilder.object_id) ?
63
+ receiver :
64
+ ((receiver[0..5] == "\xC1VMOBJ") ? vmbuilder.serialize(receiver[6..-1]) : receiver)
65
+ end
66
+ def get_index(target_oid)
67
+ (target_oid == vmbuilder.object_id && receiver[0..5] == "\xC1VMOBJ") ? receiver[6..-1] : nil
68
+ end
69
+ end
70
+
71
+ def initialize(option)
72
+ @provider = instance_eval("#{option[:lang].capitalize}SourceProvider").new(self, option[:pkgs], option[:transpiler])
73
+ @ipc = instance_eval("#{option[:ipc].to_s.capitalize}IpcInterface").new(@provider)
53
74
  end
54
75
 
55
76
  def add(methods="")
@@ -59,45 +80,35 @@ module VirtualModule
59
80
  end
60
81
 
61
82
  def build
62
- vm_builder = self
63
- ipc = @ipc
64
- @vm = Module.new{
65
- @vm_builder = vm_builder
66
- @ipc = ipc
67
- def self.virtual_module_eval(*args)
68
- @vm_builder.send(:virtual_module_eval, *args)
69
- end
70
- def self.method_missing(key, *args, &block)
71
- @vm_builder.send(:call, key, *args)
72
- end
73
- def self.___get_serialized___
74
- @ipc.serialized
75
- end
76
- }
77
- extract_defs(Ripper.sexp(@provider.source.join(";"))).split(",").each{|e|
78
- @vm.class_eval {
79
- define_method e.to_sym, Proc.new { |*args|
80
- vm_builder.call(e.to_sym, *args)
81
- }
82
- }
83
- }
83
+ @vm = new_vm(nil)
84
84
  @vm
85
85
  end
86
86
 
87
- def call(name, *args)
87
+ def call(receiver, name, *args)
88
+ if args.last.class==Hash
89
+ kwargs = args.pop
90
+ else
91
+ kwargs = {}
92
+ end
88
93
  begin
89
- @ipc.call(name, *args)
90
- rescue StandardError => e
91
- @ipc.serialized = e.message
92
- @vm
94
+ @ipc.call(receiver, name, *args, **kwargs)
95
+ rescue => e
96
+ new_vm(e.message)
97
+ rescue RuntimeException => e
98
+ raise e.message
93
99
  end
94
100
  end
95
101
 
96
- def virtual_module_eval(script, auto_binding=true)
102
+ def serialize(object_lookup_id)
103
+ @ipc.serialize(object_lookup_id)
104
+ end
105
+
106
+ def virtual_module_eval(receiver, script, auto_binding=true)
97
107
  vars, type_info, params = inspect_local_vars(binding.of_caller(2), script)
98
108
  @provider.compile(vars, type_info, params, script, auto_binding)
99
109
  @ipc.reset @provider
100
- evaluated = self.call(:___main, params, type_info)
110
+ evaluated = self.call(receiver, :vm_builtin_eval_func, [params, type_info])
111
+
101
112
  if auto_binding
102
113
  binding.of_caller(2).eval(evaluated[1].map{|k,v| "#{k}=#{v};" if !v.nil? }.join)
103
114
  end
@@ -109,8 +120,50 @@ module VirtualModule
109
120
  alias_method :virtual_eval, :virtual_module_eval
110
121
 
111
122
  private
123
+ def new_vm(receiver)
124
+ vm_builder, provider, transmitter = [self, @provider, ProxyObjectTransmitter.new(self, receiver)]
125
+ vm = Module.new{
126
+ @vm_builder, @provider, @transmitter, @receiver = [vm_builder, provider, transmitter, receiver]
127
+ def self.virtual_module_eval(*args)
128
+ @vm_builder.send(:virtual_module_eval, @receiver, *args)
129
+ end
130
+ def self.method_missing(key, *args, &block)
131
+ @vm_builder.send(:call, @receiver, key, *args)
132
+ end
133
+ def self.___proxy_object_transmitter
134
+ @transmitter
135
+ end
136
+ def self.to_s
137
+ @vm_builder.send(:call, nil, @provider.to_s, self)
138
+ end
139
+ def self.to_a
140
+ @vm_builder.send(:call, nil, @provider.to_a, self)
141
+ end
142
+ def self.vclass
143
+ @vm_builder.send(:call, nil, @provider.to_s,
144
+ @vm_builder.send(:call, nil, @provider.vclass, self)
145
+ )
146
+ end
147
+ def self.vmethods
148
+ @vm_builder.send(:call, nil, @provider.vmethods, self)
149
+ end
150
+ }
151
+ includables = (
152
+ (defs = extract_defs(Ripper.sexp(@provider.source.join(";")))).nil? ? [] : defs.split(",") +
153
+ provider.pkgs.map{|e| e.class==Hash ? e.values : e}.flatten
154
+ )
155
+ includables.each{|e|
156
+ vm.class_eval {
157
+ define_method e.to_sym, Proc.new { |*args|
158
+ vm_builder.call(receiver, e.to_sym, *args)
159
+ }
160
+ }
161
+ } if !includables.nil?
162
+ vm
163
+ end
164
+
112
165
  def inspect_local_vars(context, script)
113
- vars = extract_args(Ripper.sexp(script)).split(",").uniq.map{|e| e.to_sym} & context.eval("local_variables")
166
+ vars = (args = extract_args(Ripper.sexp(script))).nil? ? [] : args.split(",").uniq.map{|e| e.to_sym} & context.eval("local_variables")
114
167
 
115
168
  type_info = {}
116
169
  type_info[:params] = context.eval("Hash[ *#{vars}.collect { |e| [ e, eval(e.to_s).class.to_s ] }.flatten ]").select{|k,v| ["FloatArray", "IntArray"].include?(v)}
@@ -127,34 +180,249 @@ EOS
127
180
 
128
181
  class BaseSourceProvider
129
182
  attr_accessor :source
130
- def initialize(pkgs)
131
- @source = load_packages(pkgs)
183
+ attr_accessor :pkgs
184
+ KwargsConverter = Struct.new(:initializer, :setter, :varargs)
185
+
186
+ def initialize(builder, pkgs, transpiler=nil)
187
+ @builder = builder
188
+ @pkgs = pkgs
189
+ @transpiler = transpiler.nil? ? ->(s){s} : transpiler
190
+ @source = []
132
191
  @compiled_lib = ""
133
192
  end
134
193
 
135
- def load_packages(pkgs)
194
+ def load_packages
136
195
  [] #to be overrieded
137
196
  end
197
+
198
+ def lang
199
+ self.class.name.match(/\:\:(.*)SourceProvider/)[1].downcase.to_sym
200
+ end
201
+
202
+ def vclass
203
+ raise Exception.new("An equivalent method for #{__method__} seems not supported in #{lang}.")
204
+ end
205
+ alias_method :vmethods, :vclass
206
+ alias_method :to_s, :vclass
207
+ alias_method :to_a, :vclass
208
+
209
+ private
210
+ def prepare_params(input_queue_path, gen_driver, conv_kwargs, name, *args, **kwargs)
211
+ script, params = ["", []]
212
+ if args.count == 1 && args[0].class == Symbol
213
+ # do nothing - this will be called as "#name()"
214
+ else
215
+ type = ->(arg){
216
+ arg.class == Module ? "serialized" : "msgpack"
217
+ }
218
+ args.each_with_index do |arg, i|
219
+ File.write(
220
+ "#{input_queue_path}.#{i}.#{type.call(arg)}",
221
+ arg.class == Module ?
222
+ arg.___proxy_object_transmitter.convert_to(@builder.object_id):
223
+ MessagePack.pack(arg)
224
+ )
225
+ params << "params_#{i}"
226
+ script += gen_driver.call(arg, input_queue_path, i, type.call(arg), params.last)
227
+ end
228
+ if kwargs.count>0
229
+ script += "kwargs=#{conv_kwargs.initializer};"
230
+ kwargs.each_with_index do |(k,v), i|
231
+ File.write(
232
+ "#{input_queue_path}.#{params.count+i}.#{type.call(v)}",
233
+ v.class == Module ?
234
+ v.___proxy_object_transmitter.convert_to(@builder.object_id):
235
+ MessagePack.pack(v)
236
+ )
237
+ script += gen_driver.call(v, input_queue_path, params.count+i, type.call(v), conv_kwargs.setter.call(k))
238
+ end
239
+ params << conv_kwargs.varargs
240
+ end
241
+ end
242
+ [script, name==:[] ? "[#{params.join(',')}]" : "(#{params.join(',')})"]
243
+ end
244
+
245
+ end
246
+
247
+ class PythonSourceProvider < BaseSourceProvider
248
+ EXT = "py"
249
+
250
+ def load_packages
251
+ @pkgs.map{|e|
252
+ if e.class==Hash
253
+ e.map{|k,v| "from #{k} import #{ v.class==Array ? v.join(",") : v}"}
254
+ else
255
+ "import #{e}"
256
+ end
257
+ }.flatten
258
+ end
259
+
260
+ def to_a
261
+ :list
262
+ end
263
+
264
+ def to_s
265
+ :str
266
+ end
267
+
268
+ def vclass
269
+ :type
270
+ end
271
+
272
+ def vmethods
273
+ :dir
274
+ end
275
+
276
+ def main_loop(input_queue_path, output_queue_path, lib_script=nil)
277
+ <<EOS
278
+ # coding: utf-8
279
+ import sys
280
+ sys.path.append('#{File.dirname(input_queue_path)}')
281
+ from #{lib_script} import *
282
+ import dill
283
+ import msgpack
284
+
285
+ object_lookup_table = {}
286
+ while True :
287
+ try:
288
+ f = open('#{input_queue_path}', 'r')
289
+ source = f.read()
290
+ f.close()
291
+ if source[0]=='\\n':
292
+ f = open('#{output_queue_path}', 'w')
293
+ f.write(dill.dumps(object_lookup_table[int(source[1:len(source)])]))
294
+ f.close()
295
+ else:
296
+ exec(source)
297
+ f = open('#{output_queue_path}', 'w')
298
+ try:
299
+ f.write(msgpack.packb(___result))
300
+ except:
301
+ object_lookup_table[id(___result)] = ___result
302
+ f.write('\\xc1VMOBJ'+str(id(___result)))
303
+ f.close()
304
+ except KeyboardInterrupt:
305
+ print(object_lookup_table.keys())
306
+ exit(0);
307
+ except Exception as e:
308
+ f = open('#{output_queue_path}', 'w')
309
+ f.write('\\xc1VMERR'+str(type(e))+','+str(e.message))
310
+ f.close()
311
+ EOS
312
+ end
313
+
314
+ def lib_script(ipc=nil)
315
+ if ipc!=:rpc
316
+ @compiled_lib
317
+ else
318
+ # :rpc mode is to be implemented
319
+ @compiled_lib
320
+ end
321
+ end
322
+
323
+ def compile(vars=nil, type_info=nil, params=nil, script=nil, auto_binding=nil)
324
+ @compiled_lib = (load_packages + @source).join("\n")
325
+ if !vars.nil? && !type_info.nil? && !params.nil? && !script.nil? && !auto_binding.nil?
326
+ preprocess = vars.map{|e| e.to_s + '=params[0]["'+e.to_s+'"]'}
327
+ postprocess = auto_binding ? vars.map{|e| 'params[0]["'+e.to_s+'"]='+e.to_s } : []
328
+ @compiled_lib += <<EOS
329
+ def vm_builtin_eval_func(params):
330
+ #{(preprocess.join(";") + ";") if preprocess.count>0} #{script};
331
+ #{(postprocess.join(";") + ";") if postprocess.count>0} return (None,#{auto_binding ? "params[0]" : "-1" });
332
+
333
+ EOS
334
+ end
335
+ end
336
+
337
+ def generate_message(input_queue_path, receiver, name, *args, **kwargs)
338
+ script, params = ["", ""]
339
+ if args.count + kwargs.count > 0
340
+ gen_driver = ->(arg, input_queue_path, i, type, param_name){
341
+ val = arg.class == Module ?
342
+ (
343
+ (table_index = arg.___proxy_object_transmitter.get_index(@builder.object_id)).nil? ?
344
+ "dill.loads(f.read())" :
345
+ "object_lookup_table[#{table_index}]"
346
+ ) :
347
+ "msgpack.unpackb(f.read())"
348
+ "f=open('#{input_queue_path}.#{i}.#{type}', 'r'); #{param_name}=#{val}; f.close();"
349
+ }
350
+ conv_kwargs = KwargsConverter.new("{}", ->(k){"kwargs['#{k}']"}, "**kwargs")
351
+ script, params = prepare_params(input_queue_path, gen_driver, conv_kwargs, name, *args, **kwargs)
352
+ end
353
+ callee = "#{name}"
354
+ if !receiver.nil?
355
+ if receiver[0..5]=="\xC1VMOBJ"
356
+ script += "receiver=object_lookup_table[#{receiver[6..-1]}];"
357
+ else
358
+ File.write("#{input_queue_path}_serialized", receiver)
359
+ script += "f=open('#{input_queue_path}_serialized', 'r'); receiver=dill.load(f); f.close();"
360
+ end
361
+ if name==:[]
362
+ callee = "receiver"
363
+ else
364
+ callee = "receiver.#{name}"
365
+ end
366
+ end
367
+ script += "___result = #{callee}#{params};"
368
+ end
138
369
  end
139
370
 
140
371
  class JuliaSourceProvider < BaseSourceProvider
141
- def load_packages(pkgs)
142
- pkgs.map{|e| "import #{e}"}
372
+ EXT = "jl"
373
+
374
+ def load_packages
375
+ @pkgs.map{|e| "import #{e}"}
376
+ end
377
+
378
+ def to_a
379
+ :tuple
143
380
  end
144
381
 
145
- def main_loop(input_queue_path, output_queue_path)
382
+ def to_s
383
+ :string
384
+ end
385
+
386
+ def vclass
387
+ :summary
388
+ end
389
+
390
+ def main_loop(input_queue_path, output_queue_path, lib_script=nil)
146
391
  <<EOS
147
392
  using MsgPack
393
+ object_lookup_table = Dict()
148
394
  while true
149
- source = open( "#{input_queue_path}", "r" ) do fp
150
- readall(fp)
151
- end
152
- result = eval(parse(source))
153
- open( "#{output_queue_path}", "w" ) do fp
154
- try
155
- write(fp,pack(result))
156
- catch
157
- serialize(fp,result)
395
+ try
396
+ source = open( "#{input_queue_path}", "r" ) do fp
397
+ readall(fp)
398
+ end
399
+ if source[1]=='\n'
400
+ open( "#{output_queue_path}", "w" ) do fp
401
+ serialize(fp, object_lookup_table[parse(Int,source[2:length(source)])])
402
+ end
403
+ else
404
+ result = eval(parse(source))
405
+ open( "#{output_queue_path}", "w" ) do fp
406
+ try
407
+ write(fp,pack(result))
408
+ catch
409
+ object_lookup_table[object_id(result)] = result
410
+ write(fp, 0xc1)
411
+ write(fp, "VMOBJ")
412
+ write(fp, string(object_id(result)))
413
+ end
414
+ end
415
+ end
416
+ catch err
417
+ print(typeof(err))
418
+ if !isa(err, InterruptException)
419
+ open( "#{output_queue_path}", "w" ) do fp
420
+ write(fp, 0xc1)
421
+ write(fp, "VMERR")
422
+ write(fp, string(err))
423
+ end
424
+ else
425
+ exit
158
426
  end
159
427
  end
160
428
  end
@@ -176,10 +444,9 @@ EOS
176
444
  end
177
445
 
178
446
  def compile(vars=nil, type_info=nil, params=nil, script=nil, auto_binding=nil)
179
- @compiled_lib = File.read(
180
- File.dirname(__FILE__)+"/virtual_module/bridge.jl") + ";" +
181
- Julializer.ruby2julia(@source.join(";\n")
182
- )
447
+ @compiled_lib =
448
+ File.read(File.dirname(__FILE__)+"/virtual_module/bridge.jl") + ";" +
449
+ load_packages.join(";\n") + @transpiler.call(@source.join(";\n"))
183
450
  if !vars.nil? && !type_info.nil? && !params.nil? && !script.nil? && !auto_binding.nil?
184
451
  @compiled_lib += <<EOS
185
452
  function ___convert_type(name, typename, params)
@@ -194,39 +461,60 @@ EOS
194
461
  end
195
462
  end
196
463
 
197
- function ___main(params, type_info)
198
- #{vars.map{|e| e.to_s + '=___convert_type("'+e.to_s+'","'+(type_info[:params][e]||"")+'", params)'}.join(";")}
464
+ function vm_builtin_eval_func(params)
465
+ #{vars.map{|e| e.to_s + '=___convert_type("'+e.to_s+'","'+(type_info[:params][e]||"")+'", params[1])'}.join(";")}
199
466
  ##{vars.map{|e| 'println("'+e.to_s+'=", typeof('+e.to_s+'))' }.join(";")}
200
- ___evaluated = (#{Julializer.ruby2julia(script)})
467
+ ___evaluated = (#{@transpiler.call(script)})
201
468
 
202
- #{vars.map{|e| 'params["'+e.to_s+'"]='+e.to_s }.join(";") if auto_binding}
469
+ #{vars.map{|e| 'params[1]["'+e.to_s+'"]='+e.to_s }.join(";") if auto_binding}
203
470
 
204
- (___evaluated,#{auto_binding ? "params" : "-1" })
471
+ (___evaluated,#{auto_binding ? "params[1]" : "-1" })
205
472
  end
206
473
  EOS
207
474
  end
208
475
  end
209
476
 
210
- def generate_message(input_queue_path, name, *args)
211
- script = ""
212
- params = []
213
- args.each_with_index do |arg, i|
214
- type = arg.class == Module ? "serialized" : "msgpack"
215
- File.write("#{input_queue_path}.#{i}.#{type}", arg.class == Module ? arg.___get_serialized___ : MessagePack.pack(arg))
216
- params << "params_#{i}"
217
- val = arg.class == Module ? "deserialize(fp)" : "unpack(readall(fp))"
218
- script += "#{params.last} =open( \"#{input_queue_path}.#{i}.#{type}\", \"r\" ) do fp; #{val}; end;"
477
+ def generate_message(input_queue_path, receiver, name, *args, **kwargs)
478
+ script, params = ["", ""]
479
+ if args.count + kwargs.count > 0
480
+ gen_driver = ->(arg, input_queue_path, i, type, param_name){
481
+ val = case arg.class.to_s
482
+ when "Module" then (
483
+ (table_index = arg.___proxy_object_transmitter.get_index(@builder.object_id)).nil? ?
484
+ "deserialize(fp)" :
485
+ "object_lookup_table[#{table_index}]"
486
+ )
487
+ when "Symbol" then "convert(Symbol, unpack(readall(fp)))"
488
+ else "unpack(readall(fp))"
489
+ end
490
+ script += "#{param_name} =open( \"#{input_queue_path}.#{i}.#{type}\", \"r\" ) do fp; #{val}; end;"
491
+ }
492
+ conv_kwargs = KwargsConverter.new("Dict{Symbol,Any}()", ->(k){"kwargs[:#{k}]"}, ";kwargs...")
493
+ script, params = prepare_params(input_queue_path, gen_driver, conv_kwargs, name, *args, **kwargs)
219
494
  end
220
- script += "#{name}(#{params.join(',')});"
495
+ callee = "#{name}"
496
+ if !receiver.nil?
497
+ if receiver[0..5]=="\xC1VMOBJ"
498
+ script += "receiver=object_lookup_table[#{receiver[6..-1]}];"
499
+ else
500
+ File.write("#{input_queue_path}_serialized", receiver)
501
+ script += "receiver =open( \"#{input_queue_path}_serialized\", \"r\" ) do fp; deserialize(fp); end;"
502
+ end
503
+ if name==:[]
504
+ callee = "receiver"
505
+ else
506
+ callee = "receiver.#{name}"
507
+ end
508
+ end
509
+ script += "#{callee}#{params};"
221
510
  end
222
511
 
223
512
  end
224
513
 
225
514
  class BaseIpcInterface
226
- LIB_SCRIPT = "vm-lib"
515
+ LIB_SCRIPT = "vmlib"
227
516
 
228
517
  attr_accessor :work_dir
229
- attr_accessor :serialized
230
518
 
231
519
  def initialize(provider)
232
520
  @provider = provider
@@ -241,39 +529,48 @@ EOS
241
529
  end
242
530
 
243
531
  class FileIpcInterface < BaseIpcInterface
244
- INPUT = "vm-input"
245
- OUTPUT = "vm-output"
246
- MAIN_LOOP = "vm-main"
532
+ INPUT = "vminput"
533
+ OUTPUT = "vmoutput"
534
+ MAIN_LOOP = "vmmain"
247
535
 
248
536
  def initialize(provider)
249
537
  super
250
538
  File.mkfifo("#{@work_dir}/#{INPUT}")
251
539
  File.mkfifo("#{@work_dir}/#{OUTPUT}")
252
540
  at_exit do
253
- Process.kill(:INT, @pid) if !@pid.nil?
541
+ Process.kill(:KILL, @pid) if !@pid.nil?
254
542
  FileUtils.remove_entry @work_dir if File.directory?(@work_dir)
255
543
  end
256
544
  end
257
545
 
258
- def call(name, *args)
546
+ def call(receiver, name, *args, **kwargs)
259
547
  #require 'byebug'
260
548
  #byebug
261
- if Helper.is_installed?(:julia)
262
- enqueue @provider.generate_message("#{@work_dir}/#{INPUT}", name, *args)
549
+ if Helper.is_installed?(@provider.lang)
550
+ enqueue @provider.generate_message("#{@work_dir}/#{INPUT}", receiver, name, *args, **kwargs)
263
551
  elsif Helper.is_installed?(:docker)
264
- enqueue @provider.generate_message("/opt/#{INPUT}", name, *args)
552
+ enqueue @provider.generate_message("/opt/#{INPUT}", receiver, name, *args, **kwargs)
265
553
  else
266
- raise Exception.new("Either julia or docker command is required to run virtual_module")
554
+ raise Exception.new("Either #{@provider.lang} or docker command is required to run virtual_module")
267
555
  end
268
- #byebug
269
556
  response = dequeue
270
- begin
271
- MessagePack.unpack(response)
272
- rescue
273
- raise StandardError.new(response)
557
+ case response[0..5]
558
+ when "\xC1VMERR" then raise RuntimeException, "wrong wrong!: " + response[6..-1]
559
+ when "\xC1VMOBJ" then raise StandardError.new(response)
560
+ else
561
+ begin
562
+ MessagePack.unpack(response)
563
+ rescue
564
+ raise StandardError.new(response)
565
+ end
274
566
  end
275
567
  end
276
568
 
569
+ def serialize(object_lookup_id)
570
+ enqueue "\n#{object_lookup_id}"
571
+ dequeue
572
+ end
573
+
277
574
  def reset(source)
278
575
  super
279
576
  restart_server_process
@@ -281,17 +578,33 @@ EOS
281
578
 
282
579
  private
283
580
  def restart_server_process
284
- Process.kill(:KILL, @pid) if !@pid.nil?
285
- File.write("#{@work_dir}/#{LIB_SCRIPT}", @provider.lib_script)
286
- File.write("#{@work_dir}/#{MAIN_LOOP}", @provider.main_loop("#{@work_dir}/#{INPUT}", "#{@work_dir}/#{OUTPUT}"))
287
- if Helper.is_installed?(:julia)
288
- command = "julia --depwarn=no -L #{@work_dir}/#{LIB_SCRIPT} #{@work_dir}/#{MAIN_LOOP}"
289
- elsif Helper.is_installed?(:docker)
290
- command = "docker run -v #{@work_dir}/:/opt/ remore/virtual_module julia --depwarn=no -L /opt/#{LIB_SCRIPT} /opt/#{MAIN_LOOP}"
581
+ if !@pid.nil?
582
+ begin
583
+ Process.getpgid(@pid)
584
+ Process.kill(:KILL, @pid)
585
+ rescue Errno::ESRCH
586
+ end
587
+ @pid=nil
588
+ end
589
+ File.write("#{@work_dir}/#{LIB_SCRIPT}.#{@provider.class::EXT}", @provider.lib_script)
590
+ File.write("#{@work_dir}/#{MAIN_LOOP}.#{@provider.class::EXT}", @provider.main_loop("#{@work_dir}/#{INPUT}", "#{@work_dir}/#{OUTPUT}", LIB_SCRIPT))
591
+ case @provider.lang
592
+ when :julia
593
+ if Helper.is_installed?(:julia)
594
+ command = "julia --depwarn=no -L #{@work_dir}/#{LIB_SCRIPT}.#{@provider.class::EXT} #{@work_dir}/#{MAIN_LOOP}.#{@provider.class::EXT}"
595
+ elsif Helper.is_installed?(:docker)
596
+ command = "docker run -v #{@work_dir}/:/opt/ remore/virtual_module julia --depwarn=no -L /opt/#{LIB_SCRIPT}.#{@provider.class::EXT} /opt/#{MAIN_LOOP}.#{@provider.class::EXT}"
597
+ else
598
+ raise Exception.new("Either julia or docker command is required to run virtual_module")
599
+ end
600
+ when :python
601
+ # -B : Prevent us from creating *.pyc cache - this will be problematic when we call #virtual_module_eval repeatedly.
602
+ command = "python -B #{@work_dir}/#{MAIN_LOOP}.#{@provider.class::EXT}"
291
603
  else
292
- raise Exception.new("Either julia or docker command is required to run virtual_module")
604
+ raise Exception.new("Unsupported language was specified")
293
605
  end
294
606
  @pid = Process.spawn(command, :err => :out,:out => "/dev/null") # , :pgroup => Process.pid)
607
+ #@pid = Process.spawn(command) # , :pgroup => Process.pid)
295
608
  Process.detach @pid
296
609
  end
297
610
 
@@ -313,14 +626,14 @@ EOS
313
626
  @timeout = 10
314
627
  end
315
628
 
316
- def call(name, *args)
629
+ def call(name, *args, **kwargs)
317
630
  restart_server_process
318
631
  while `echo exit | telnet #{@server} #{@port} 2>&1`.chomp[-5,5]!="host." do
319
632
  sleep(0.05)
320
633
  end
321
634
  @client = MessagePack::RPC::Client.new(@server, @port) if @client.nil?
322
635
  @client.timeout = @timeout
323
- args.count>0 ? @client.call(name, *args) : @client.call(name)
636
+ args.count>0 || kwargs.count>0 ? @client.call(name, *args, **kwargs) : @client.call(name)
324
637
  end
325
638
 
326
639
  private
@@ -330,7 +643,7 @@ EOS
330
643
  @client = nil
331
644
  at_exit do
332
645
  @client.close if !@client.nil?
333
- Process.kill(:INT, @pid) if !@pid.nil?
646
+ Process.kill(:KILL, @pid) if !@pid.nil?
334
647
  FileUtils.remove_entry @work_dir if File.directory?(@work_dir)
335
648
  end
336
649
  end
@@ -339,8 +652,8 @@ EOS
339
652
  Process.kill(:KILL, @pid) if !@pid.nil?
340
653
  `lsof -wni tcp:#{@port} | cut -f 4 -d ' ' | sed -ne '2,$p' | xargs kill -9`
341
654
  init_connection
342
- File.write("#{@work_dir}/#{LIB_SCRIPT}", @provider.lib_script(:rpc))
343
- @pid = Process.spawn("julia --depwarn=no #{@work_dir}/#{LIB_SCRIPT} #{@port}", :err => :out,:out => "/dev/null") #, :pgroup=>Process.pid)
655
+ File.write("#{@work_dir}/#{LIB_SCRIPT}.#{@provider.class::EXT}", @provider.lib_script(:rpc))
656
+ @pid = Process.spawn("julia --depwarn=no #{@work_dir}/#{LIB_SCRIPT}.#{@provider.class::EXT} #{@port}", :err => :out,:out => "/dev/null") #, :pgroup=>Process.pid)
344
657
  Process.detach @pid
345
658
  end
346
659
  end
@@ -1,3 +1,3 @@
1
1
  module VirtualModule
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: virtual_module
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kei Sawada(@remore)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-19 00:00:00.000000000 Z
11
+ date: 2016-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack