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 +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
|