virtual_module 0.2.1 → 0.3.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 +4 -4
- data/lib/virtual_module.rb +413 -100
- data/lib/virtual_module/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac2dd86960d57e8ca74b66f23d706aa38413ebb6
|
4
|
+
data.tar.gz: 870312de88c44be64424e91b4cb507554454c273
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05988bd3c35c324b49600615c9fff85c917d007b604c6799382b460a04241bdf25be0356e649183a54b4c68d8a05d7757cda184cbc70db335a83bbac258a8072
|
7
|
+
data.tar.gz: a3c47595572bea85f6f818f55da750d96bb31133e79e7c239aca69adbb2f7ab24f88dec121803e80495253b4aa68e309303057ec5cb6445312008a417478466e
|
data/lib/virtual_module.rb
CHANGED
@@ -10,14 +10,24 @@ module VirtualModule
|
|
10
10
|
require 'virtual_module/version'
|
11
11
|
|
12
12
|
class << self
|
13
|
-
def new(
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
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
|
91
|
-
|
92
|
-
|
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
|
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(:
|
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
|
-
|
131
|
-
|
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
|
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
|
-
|
142
|
-
|
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
|
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
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
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 =
|
180
|
-
File.dirname(__FILE__)+"/virtual_module/bridge.jl") + ";" +
|
181
|
-
|
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
|
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 = (#{
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
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
|
-
|
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 = "
|
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 = "
|
245
|
-
OUTPUT = "
|
246
|
-
MAIN_LOOP = "
|
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(:
|
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?(
|
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
|
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
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
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
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
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("
|
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(:
|
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
|
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.
|
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-
|
11
|
+
date: 2016-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|