nodo 1.6.5 → 1.8.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/README.md +17 -0
- data/lib/nodo/core.rb +50 -46
- data/lib/nodo/dependency.rb +28 -5
- data/lib/nodo/{nodo.js → nodo.cjs} +16 -12
- data/lib/nodo/version.rb +1 -1
- metadata +7 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7c1002efcf0b7ba146dde5e10af7ddcdfdfeb450824dfaf5cce56c115630303
|
4
|
+
data.tar.gz: 3dc41a17980258b0ef634bb6a05319cc98501495ebb7a4688007cd0546f32fb3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 877eac53f4eb526c8fc8ef7cc7b10437232a9b50effffd894dda29c36129b33c7a2c9e9edb47964ad2b566ce98c25f38d2866ce0cd0fc52062efbe0084105f31
|
7
|
+
data.tar.gz: 5aaf9f8097c8a3b7335e1a67b23dc388a194b2dfe395b8b8e0faeca324b194615d1b946fd3a6bf117b0c0d2567c71cae622b00611d772e95f8f35e1e1f519f4a
|
data/README.md
CHANGED
@@ -99,6 +99,23 @@ bar = Bar.new
|
|
99
99
|
bar.v4 => "b305f5c4-db9a-4504-b0c3-4e097a5ec8b9"
|
100
100
|
```
|
101
101
|
|
102
|
+
`import` is also supported for loading ESM packages:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class Bar < Nodo::Core
|
106
|
+
import :uuid
|
107
|
+
|
108
|
+
function :v4, <<~JS
|
109
|
+
() => {
|
110
|
+
return uuid.v4();
|
111
|
+
}
|
112
|
+
JS
|
113
|
+
end
|
114
|
+
|
115
|
+
bar = Bar.new
|
116
|
+
bar.v4 => "b305f5c4-db9a-4504-b0c3-4e097a5ec8b9"
|
117
|
+
```
|
118
|
+
|
102
119
|
### Aliasing requires
|
103
120
|
|
104
121
|
If the library name cannot be used as name of the constant, the `const` name
|
data/lib/nodo/core.rb
CHANGED
@@ -9,48 +9,48 @@ module Nodo
|
|
9
9
|
ARRAY_CLASS_ATTRIBUTES = %i[dependencies constants scripts].freeze
|
10
10
|
HASH_CLASS_ATTRIBUTES = %i[functions].freeze
|
11
11
|
CLASS_ATTRIBUTES = (ARRAY_CLASS_ATTRIBUTES + HASH_CLASS_ATTRIBUTES).freeze
|
12
|
-
|
12
|
+
|
13
13
|
@@node_pid = nil
|
14
14
|
@@tmpdir = nil
|
15
15
|
@@mutex = Mutex.new
|
16
16
|
@@exiting = nil
|
17
|
-
|
17
|
+
|
18
18
|
class << self
|
19
19
|
extend Forwardable
|
20
|
-
|
20
|
+
|
21
21
|
attr_accessor :class_defined
|
22
|
-
|
22
|
+
|
23
23
|
def inherited(subclass)
|
24
24
|
CLASS_ATTRIBUTES.each do |attr|
|
25
25
|
subclass.send "#{attr}=", send(attr).dup
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def instance
|
30
30
|
@instance ||= new
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def class_defined?
|
34
34
|
!!class_defined
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def clsid
|
38
38
|
name || "Class:0x#{object_id.to_s(0x10)}"
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
CLASS_ATTRIBUTES.each do |attr|
|
42
42
|
define_method "#{attr}=" do |value|
|
43
43
|
instance_variable_set :"@#{attr}", value
|
44
44
|
end
|
45
45
|
protected "#{attr}="
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
ARRAY_CLASS_ATTRIBUTES.each do |attr|
|
49
49
|
define_method "#{attr}" do
|
50
50
|
instance_variable_get(:"@#{attr}") || instance_variable_set(:"@#{attr}", [])
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
HASH_CLASS_ATTRIBUTES.each do |attr|
|
55
55
|
define_method "#{attr}" do
|
56
56
|
instance_variable_get(:"@#{attr}") || instance_variable_set(:"@#{attr}", {})
|
@@ -60,15 +60,15 @@ module Nodo
|
|
60
60
|
def generate_core_code
|
61
61
|
<<~JS
|
62
62
|
global.nodo = require(#{nodo_js});
|
63
|
-
|
63
|
+
|
64
64
|
const socket = process.argv[1];
|
65
65
|
if (!socket) {
|
66
66
|
process.stderr.write('Socket path is required\\n');
|
67
67
|
process.exit(1);
|
68
68
|
}
|
69
|
-
|
69
|
+
|
70
70
|
process.title = `nodo-core ${socket}`;
|
71
|
-
|
71
|
+
|
72
72
|
const shutdown = () => {
|
73
73
|
nodo.core.close(() => { process.exit(0) });
|
74
74
|
};
|
@@ -82,7 +82,7 @@ module Nodo
|
|
82
82
|
|
83
83
|
def generate_class_code
|
84
84
|
<<~JS
|
85
|
-
(() => {
|
85
|
+
(async () => {
|
86
86
|
const __nodo_klass__ = { nodo: global.nodo };
|
87
87
|
#{dependencies.map(&:to_js).join}
|
88
88
|
#{constants.map(&:to_js).join}
|
@@ -92,23 +92,27 @@ module Nodo
|
|
92
92
|
})()
|
93
93
|
JS
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
protected
|
97
|
-
|
97
|
+
|
98
98
|
def finalize_context(context_id)
|
99
99
|
proc do
|
100
|
-
if not @@exiting and core =
|
100
|
+
if not @@exiting and core = @instance
|
101
|
+
puts "finalize_context #{context_id}"
|
101
102
|
core.send(:call_js_method, GC_METHOD, context_id)
|
102
103
|
end
|
103
104
|
end
|
104
105
|
end
|
105
|
-
|
106
|
+
|
106
107
|
private
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
108
|
+
|
109
|
+
{ require: :cjs, import: :esm }.each do |method, type|
|
110
|
+
define_method method do |*mods|
|
111
|
+
deps = mods.last.is_a?(Hash) ? mods.pop : {}
|
112
|
+
mods = mods.map { |m| [m, m] }.to_h
|
113
|
+
self.dependencies = dependencies + mods.merge(deps).map { |name, package| Dependency.new(name, package, type: type) }
|
114
|
+
end
|
115
|
+
private method
|
112
116
|
end
|
113
117
|
|
114
118
|
def function(name, _code = nil, timeout: Nodo.timeout, code: nil, &block)
|
@@ -118,7 +122,7 @@ module Nodo
|
|
118
122
|
self.functions = functions.merge(name => Function.new(name, _code || code, source_location, timeout, &block))
|
119
123
|
define_method(name) { |*args| call_js_method(name, args) }
|
120
124
|
end
|
121
|
-
|
125
|
+
|
122
126
|
def class_function(*methods)
|
123
127
|
singleton_class.def_delegators(:instance, *methods)
|
124
128
|
end
|
@@ -126,20 +130,20 @@ module Nodo
|
|
126
130
|
def const(name, value)
|
127
131
|
self.constants = constants + [Constant.new(name, value)]
|
128
132
|
end
|
129
|
-
|
133
|
+
|
130
134
|
def script(code = nil, &block)
|
131
135
|
self.scripts = scripts + [Script.new(code, &block)]
|
132
136
|
end
|
133
|
-
|
137
|
+
|
134
138
|
def nodo_js
|
135
|
-
Pathname.new(__FILE__).dirname.join('nodo.
|
139
|
+
Pathname.new(__FILE__).dirname.join('nodo.cjs').to_s.to_json
|
136
140
|
end
|
137
|
-
|
141
|
+
|
138
142
|
def reserved_method_name?(name)
|
139
143
|
Nodo::Core.method_defined?(name, false) || Nodo::Core.private_method_defined?(name, false) || name.to_s == DEFINE_METHOD
|
140
144
|
end
|
141
145
|
end
|
142
|
-
|
146
|
+
|
143
147
|
def initialize
|
144
148
|
raise ClassError, :new if self.class == Nodo::Core
|
145
149
|
@@mutex.synchronize do
|
@@ -148,18 +152,18 @@ module Nodo
|
|
148
152
|
ensure_class_is_defined
|
149
153
|
end
|
150
154
|
end
|
151
|
-
|
155
|
+
|
152
156
|
def evaluate(code)
|
153
157
|
ensure_context_is_defined
|
154
158
|
call_js_method(EVALUATE_METHOD, code)
|
155
159
|
end
|
156
|
-
|
160
|
+
|
157
161
|
private
|
158
|
-
|
162
|
+
|
159
163
|
def node_pid
|
160
164
|
@@node_pid
|
161
165
|
end
|
162
|
-
|
166
|
+
|
163
167
|
def tmpdir
|
164
168
|
@@tmpdir
|
165
169
|
end
|
@@ -167,33 +171,33 @@ module Nodo
|
|
167
171
|
def socket_path
|
168
172
|
tmpdir && tmpdir.join(SOCKET_NAME)
|
169
173
|
end
|
170
|
-
|
174
|
+
|
171
175
|
def clsid
|
172
176
|
self.class.clsid
|
173
177
|
end
|
174
|
-
|
178
|
+
|
175
179
|
def context_defined?
|
176
180
|
@context_defined
|
177
181
|
end
|
178
|
-
|
182
|
+
|
179
183
|
def log_exception(e)
|
180
184
|
return unless logger = Nodo.logger
|
181
185
|
message = "\n#{e.class} (#{e.message})"
|
182
186
|
message << ":\n\n#{e.backtrace.join("\n")}" if e.backtrace
|
183
187
|
logger.error message
|
184
188
|
end
|
185
|
-
|
189
|
+
|
186
190
|
def ensure_process_is_spawned
|
187
191
|
return if node_pid
|
188
192
|
spawn_process
|
189
193
|
end
|
190
|
-
|
194
|
+
|
191
195
|
def ensure_class_is_defined
|
192
196
|
return if self.class.class_defined?
|
193
197
|
call_js_method(DEFINE_METHOD, self.class.generate_class_code)
|
194
198
|
self.class.class_defined = true
|
195
199
|
end
|
196
|
-
|
200
|
+
|
197
201
|
def ensure_context_is_defined
|
198
202
|
return if context_defined?
|
199
203
|
@@mutex.synchronize do
|
@@ -202,7 +206,7 @@ module Nodo
|
|
202
206
|
@context_defined = true
|
203
207
|
end
|
204
208
|
end
|
205
|
-
|
209
|
+
|
206
210
|
def spawn_process
|
207
211
|
@@tmpdir = Pathname.new(Dir.mktmpdir('nodo'))
|
208
212
|
env = Nodo.env.merge('NODE_PATH' => Nodo.modules_root.to_s)
|
@@ -215,7 +219,7 @@ module Nodo
|
|
215
219
|
FileUtils.remove_entry(tmpdir) if File.directory?(tmpdir)
|
216
220
|
end
|
217
221
|
end
|
218
|
-
|
222
|
+
|
219
223
|
def wait_for_socket
|
220
224
|
start = Time.now
|
221
225
|
socket = nil
|
@@ -237,7 +241,7 @@ module Nodo
|
|
237
241
|
raise NameError, "undefined function `#{method}' for #{self.class}" unless function || INTERNAL_METHODS.include?(method)
|
238
242
|
context_id = case method
|
239
243
|
when DEFINE_METHOD then 0
|
240
|
-
when GC_METHOD then args
|
244
|
+
when GC_METHOD then args
|
241
245
|
else
|
242
246
|
object_id
|
243
247
|
end
|
@@ -257,7 +261,7 @@ module Nodo
|
|
257
261
|
# TODO: restart or something? If this happens the process is completely broken
|
258
262
|
raise Error, 'Node process failed'
|
259
263
|
end
|
260
|
-
|
264
|
+
|
261
265
|
def handle_error(response, function)
|
262
266
|
if response.body
|
263
267
|
result = parse_response(response)
|
@@ -270,12 +274,12 @@ module Nodo
|
|
270
274
|
log_exception(error)
|
271
275
|
raise error
|
272
276
|
end
|
273
|
-
|
277
|
+
|
274
278
|
def parse_response(response)
|
275
279
|
data = response.body.force_encoding('UTF-8')
|
276
280
|
JSON.parse(data) unless data == ''
|
277
281
|
end
|
278
|
-
|
282
|
+
|
279
283
|
def with_tempfile(name)
|
280
284
|
ext = File.extname(name)
|
281
285
|
result = nil
|
@@ -284,6 +288,6 @@ module Nodo
|
|
284
288
|
end
|
285
289
|
result
|
286
290
|
end
|
287
|
-
|
291
|
+
|
288
292
|
end
|
289
293
|
end
|
data/lib/nodo/dependency.rb
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
module Nodo
|
2
2
|
class Dependency
|
3
|
-
attr_reader :name, :package
|
4
|
-
|
5
|
-
def initialize(name, package)
|
6
|
-
@name, @package = name, package
|
3
|
+
attr_reader :name, :package, :type
|
4
|
+
|
5
|
+
def initialize(name, package, type:)
|
6
|
+
@name, @package, @type = name, package, type
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def to_js
|
10
|
+
case type
|
11
|
+
when :cjs then to_cjs
|
12
|
+
when :esm then to_esm
|
13
|
+
else raise "Unknown dependency type: #{type}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def to_cjs
|
10
20
|
<<~JS
|
11
21
|
const #{name} = __nodo_klass__.#{name} = (() => {
|
12
22
|
try {
|
@@ -18,5 +28,18 @@ module Nodo
|
|
18
28
|
})();
|
19
29
|
JS
|
20
30
|
end
|
31
|
+
|
32
|
+
def to_esm
|
33
|
+
<<~JS
|
34
|
+
const #{name} = __nodo_klass__.#{name} = await (async () => {
|
35
|
+
try {
|
36
|
+
return await nodo.import(#{package.to_json});
|
37
|
+
} catch(e) {
|
38
|
+
e.nodo_dependency = #{package.to_json};
|
39
|
+
throw e;
|
40
|
+
}
|
41
|
+
})();
|
42
|
+
JS
|
43
|
+
end
|
21
44
|
end
|
22
45
|
end
|
@@ -13,7 +13,7 @@ module.exports = (function() {
|
|
13
13
|
let server, closing;
|
14
14
|
const classes = {};
|
15
15
|
const contexts = {};
|
16
|
-
|
16
|
+
|
17
17
|
function render_error(e) {
|
18
18
|
let errInfo = {};
|
19
19
|
if (e instanceof Error) {
|
@@ -31,7 +31,7 @@ module.exports = (function() {
|
|
31
31
|
debug(`Error ${code} ${rendered}`);
|
32
32
|
res.end(rendered, 'utf8');
|
33
33
|
}
|
34
|
-
|
34
|
+
|
35
35
|
function respond_with_data(res, data, start) {
|
36
36
|
let timing;
|
37
37
|
res.statusCode = 200;
|
@@ -58,18 +58,18 @@ module.exports = (function() {
|
|
58
58
|
debug('Starting up...');
|
59
59
|
server = http.createServer((req, res) => {
|
60
60
|
const start = performance.now();
|
61
|
-
|
61
|
+
|
62
62
|
res.setHeader('Content-Type', 'application/json');
|
63
63
|
debug(`${req.method} ${req.url}`);
|
64
64
|
|
65
65
|
if (req.method !== 'POST' || !req.url.startsWith('/')) {
|
66
66
|
return respond_with_error(res, 405, 'Method Not Allowed');
|
67
67
|
}
|
68
|
-
|
68
|
+
|
69
69
|
const url = req.url.substring(1);
|
70
70
|
const [class_name, object_id, method] = url.split('/');
|
71
71
|
let klass, context;
|
72
|
-
|
72
|
+
|
73
73
|
if (classes.hasOwnProperty(class_name)) {
|
74
74
|
klass = classes[class_name];
|
75
75
|
if (EVALUATE_METHOD == method) {
|
@@ -83,9 +83,9 @@ module.exports = (function() {
|
|
83
83
|
} else if (DEFINE_METHOD != method) {
|
84
84
|
return respond_with_error(res, 404, `Class ${class_name} not defined`);
|
85
85
|
}
|
86
|
-
|
86
|
+
|
87
87
|
let body = '';
|
88
|
-
|
88
|
+
|
89
89
|
req.on('data', (data) => { body += data; });
|
90
90
|
|
91
91
|
req.on('end', () => {
|
@@ -99,8 +99,12 @@ module.exports = (function() {
|
|
99
99
|
|
100
100
|
try {
|
101
101
|
if (DEFINE_METHOD == method) {
|
102
|
-
|
103
|
-
|
102
|
+
Promise.resolve(vm.runInThisContext(input, class_name)).then((result) => {
|
103
|
+
classes[class_name] = result;
|
104
|
+
respond_with_data(res, class_name, start);
|
105
|
+
}).catch((error) => {
|
106
|
+
respond_with_error(res, 500, error);
|
107
|
+
})
|
104
108
|
} else if (EVALUATE_METHOD == method) {
|
105
109
|
Promise.resolve(vm.runInNewContext(input, context)).then((result) => {
|
106
110
|
respond_with_data(res, result, start);
|
@@ -120,7 +124,7 @@ module.exports = (function() {
|
|
120
124
|
} catch(error) {
|
121
125
|
return respond_with_error(res, 500, error);
|
122
126
|
}
|
123
|
-
|
127
|
+
|
124
128
|
});
|
125
129
|
});
|
126
130
|
|
@@ -129,7 +133,7 @@ module.exports = (function() {
|
|
129
133
|
debug(`server ready, listening on ${socket} (max connections: ${server.maxConnections})`);
|
130
134
|
});
|
131
135
|
},
|
132
|
-
|
136
|
+
|
133
137
|
close: (finalizer) => {
|
134
138
|
debug("Shutting down");
|
135
139
|
if (!closing) {
|
@@ -138,6 +142,6 @@ module.exports = (function() {
|
|
138
142
|
}
|
139
143
|
}
|
140
144
|
};
|
141
|
-
|
145
|
+
|
142
146
|
return { core: core, debug: debug, import: import_module };
|
143
147
|
})();
|
data/lib/nodo/version.rb
CHANGED
metadata
CHANGED
@@ -1,66 +1,23 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nodo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthias Grosser
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-02-05 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
13
|
+
name: logger
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
16
|
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
18
|
version: '0'
|
19
|
-
|
19
|
+
type: :runtime
|
20
20
|
prerelease: false
|
21
|
-
type: :development
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
29
|
-
requirements:
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '0'
|
33
|
-
name: rake
|
34
|
-
prerelease: false
|
35
|
-
type: :development
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - ">="
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '0'
|
47
|
-
name: byebug
|
48
|
-
prerelease: false
|
49
|
-
type: :development
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - ">="
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '0'
|
61
|
-
name: minitest
|
62
|
-
prerelease: false
|
63
|
-
type: :development
|
64
21
|
version_requirements: !ruby/object:Gem::Requirement
|
65
22
|
requirements:
|
66
23
|
- - ">="
|
@@ -82,7 +39,7 @@ files:
|
|
82
39
|
- lib/nodo/dependency.rb
|
83
40
|
- lib/nodo/errors.rb
|
84
41
|
- lib/nodo/function.rb
|
85
|
-
- lib/nodo/nodo.
|
42
|
+
- lib/nodo/nodo.cjs
|
86
43
|
- lib/nodo/railtie.rb
|
87
44
|
- lib/nodo/script.rb
|
88
45
|
- lib/nodo/version.rb
|
@@ -90,7 +47,6 @@ homepage: https://github.com/mtgrosser/nodo
|
|
90
47
|
licenses:
|
91
48
|
- MIT
|
92
49
|
metadata: {}
|
93
|
-
post_install_message:
|
94
50
|
rdoc_options: []
|
95
51
|
require_paths:
|
96
52
|
- lib
|
@@ -98,15 +54,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
54
|
requirements:
|
99
55
|
- - ">="
|
100
56
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
57
|
+
version: 3.0.0
|
102
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
59
|
requirements:
|
104
60
|
- - ">="
|
105
61
|
- !ruby/object:Gem::Version
|
106
62
|
version: '0'
|
107
63
|
requirements: []
|
108
|
-
rubygems_version: 3.
|
109
|
-
signing_key:
|
64
|
+
rubygems_version: 3.6.2
|
110
65
|
specification_version: 4
|
111
66
|
summary: Call Node.js from Ruby
|
112
67
|
test_files: []
|