speednode 0.8.1 → 0.9.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
  SHA256:
3
- metadata.gz: ab3e330c3cd4bf4518c54e6666ff13ee722b553e4de7d8be2602b984811da9fc
4
- data.tar.gz: '08218aa8e443770808a35de088c869bfc0d227493beba5f60b98ddcdfe35b51a'
3
+ metadata.gz: 3cb17f3391d9416c0a92291be8beaa42b25d8df70528e400d28a41984e3693bf
4
+ data.tar.gz: 463169b3ceb3d42703cbee80aa56c7edf2e1196a0114f8607eed173d0d6af583
5
5
  SHA512:
6
- metadata.gz: 3f41ebd4a9b509dc81f815c7dff64ff3ce8ae15a57fa085038ce5cdb139ab37f0f0b26cded89f52450e4e39a0f69afd98238a7ed02d20db50e7d395872617f67
7
- data.tar.gz: cb7d8667d95403426e7964e4e2be7d1608a3d2ad43fe1b36a694f125bd9595dfe3ba5b73d983d57215fdc637b2a141d8536f642435082005cbbdc5487af1b2e1
6
+ metadata.gz: fc644dbb0581167a2d03fe19b157cdd82fc2da2af2de29e80b4676e21097c2437e9da5acdb7bd6bdf0d6c52391bea5ad04b5a392e3717c2fb72cf0bc8004f1d5
7
+ data.tar.gz: 5e391001e4d7b42accf5c4b29ed424637fce9193871feb65a2c145ebc2ac082a94711031e70bf0221d9e70bc77cf40602f916f3571eb7a8d7624624deea52b06
data/README.md CHANGED
@@ -48,7 +48,7 @@ ExecJS.permissive_eval('1+1')
48
48
  ```
49
49
 
50
50
  #### Stopping Contexts
51
- Contexts can be stopped programmatically. If all contexts of a VM are stopped, the VM itself will be shut down with Node exiting, freeing memory and resources.
51
+ Contexts should be stopped programmatically when no longer needed.
52
52
  ```ruby
53
53
  context = ExecJS.compile('Test = "test"') # will start a node process
54
54
  ExecJS::Runtimes::Speednode.stop_context(context) # will kill the node process
@@ -80,7 +80,7 @@ context.await("foo('test')") # => 'test'
80
80
 
81
81
  ### Attaching ruby methods to Permissive Contexts
82
82
 
83
- Ruby methods can be attached to Permissive Contexts using Context#attach:
83
+ Ruby methods can be attached to permissive contexts using Context#attach:
84
84
  ```ruby
85
85
  context = ExecJS.permissive_compile(SOURCE)
86
86
  context.attach('foo') { |v| v }
@@ -9,8 +9,8 @@ try {
9
9
  crypto_var = require('crypto');
10
10
  } catch (err) {}
11
11
  const crypto = crypto_var;
12
- let contexts = {};
13
- let scripts = {};
12
+ let contexts = Object.create(null);
13
+ let scripts = Object.create(null);
14
14
  let process_exit = false;
15
15
 
16
16
  /*** circular-json, originally taken from https://raw.githubusercontent.com/WebReflection/circular-json/
@@ -41,7 +41,7 @@ let process_exit = false;
41
41
 
42
42
  */
43
43
 
44
- const CircularJSON = {};
44
+ const CircularJSON = Object.create(null);
45
45
  CircularJSON.specialChar = '~';
46
46
  CircularJSON.safeSpecialChar = '\\x' + ('0' + CircularJSON.specialChar.charCodeAt(0).toString(16)).slice(-2);
47
47
  CircularJSON.escapedSafeSpecialChar = '\\' + CircularJSON.safeSpecialChar;
@@ -240,6 +240,8 @@ function getContext(uuid) {
240
240
 
241
241
  function getContextOptions(uuid) {
242
242
  let options = { filename: "(execjs)", displayErrors: true };
243
+ if (!contexts[uuid])
244
+ throw new Error(`Context ${uuid} not found`);
243
245
  if (contexts[uuid].options.timeout)
244
246
  options.timeout = contexts[uuid].options.timeout;
245
247
  return options;
@@ -1,12 +1,6 @@
1
1
  module Speednode
2
2
  class Runtime < ExecJS::Runtime
3
3
  class Context < ::ExecJS::Runtime::Context
4
- def self.finalize(runtime, uuid)
5
- proc do
6
- runtime.unregister_context(uuid)
7
- end
8
- end
9
-
10
4
  def initialize(runtime, source = "", options = {})
11
5
  @runtime = runtime
12
6
  @uuid = SecureRandom.uuid
@@ -16,7 +10,7 @@ module Speednode
16
10
  @debug = false unless ENV['NODE_OPTIONS']&.include?('--inspect')
17
11
  @vm = @runtime.vm
18
12
  @timeout = options[:timeout] ? options[:timeout]/1000 : 600
19
-
13
+
20
14
  filename = options.delete(:filename)
21
15
  source = File.read(filename) if filename
22
16
 
@@ -26,8 +20,6 @@ module Speednode
26
20
  source = source.force_encoding('UTF-8')
27
21
  end
28
22
 
29
- ObjectSpace.define_finalizer(self, self.class.finalize(@runtime, @uuid))
30
-
31
23
  if @debug && @permissive
32
24
  raw_created(source, options)
33
25
  elsif @permissive
@@ -105,6 +97,10 @@ module Speednode
105
97
  raw_exec("(function(){#{source}})()")
106
98
  end
107
99
 
100
+ def available?
101
+ @runtime.context_registered?(@uuid)
102
+ end
103
+
108
104
  def stop
109
105
  @runtime.unregister_context(@uuid)
110
106
  end
@@ -40,14 +40,17 @@ end
40
40
  module Speednode
41
41
  class Runtime < ExecJS::Runtime
42
42
  class VM
43
- def self.finalize(socket, socket_dir, socket_path, pid)
43
+ def self.finalize(socket, socket_dir, socket_path, pid, spawner_pid)
44
44
  proc do
45
- ::Speednode::Runtime.responders[socket_path].kill if ::Speednode::Runtime.responders[socket_path]
46
- exit_node(socket, socket_dir, socket_path, pid)
45
+ if spawner_pid == Process.pid
46
+ ::Speednode::Runtime.responders[socket_path].kill if ::Speednode::Runtime.responders[socket_path]
47
+ exit_node(socket, socket_dir, socket_path, pid, spawner_pid)
48
+ end
47
49
  end
48
50
  end
49
51
 
50
- def self.exit_node(socket, socket_dir, socket_path, pid)
52
+ def self.exit_node(socket, socket_dir, socket_path, pid, spawner_pid)
53
+ return if spawner_pid != Process.pid
51
54
  VMCommand.new(socket, "exit", 0).execute rescue nil
52
55
  socket.close
53
56
  File.unlink(socket_path) if File.exist?(socket_path)
@@ -135,8 +138,9 @@ module Speednode
135
138
 
136
139
  def stop
137
140
  return unless @started
141
+ return if @spawner_pid != Process.pid
138
142
  @mutex.synchronize do
139
- self.class.exit_node(@socket, @socket_dir, @socket_path, @pid)
143
+ self.class.exit_node(@socket, @socket_dir, @socket_path, @pid, @spawner_pid)
140
144
  @socket_path = nil
141
145
  @started = false
142
146
  @socket = nil
@@ -151,10 +155,12 @@ module Speednode
151
155
  @socket_dir = nil
152
156
  @socket_path = SecureRandom.uuid
153
157
  else
154
- @socket_dir = Dir.mktmpdir("iso-speednode-")
158
+ @socket_dir = Dir.mktmpdir("speednode-")
155
159
  @socket_path = File.join(@socket_dir, "socket")
156
160
  end
161
+ @spawner_pid = Process.pid
157
162
  @pid = Process.spawn({"SOCKET_PATH" => @socket_path}, @options[:binary], '--expose-gc', @options[:source_maps], @options[:runner_path])
163
+ Process.detach(@pid)
158
164
 
159
165
  retries = 500
160
166
 
@@ -183,7 +189,8 @@ module Speednode
183
189
 
184
190
  @started = true
185
191
 
186
- Kernel.at_exit { self.class.finalize(@socket, @socket_dir, @socket_path, @pid).call }
192
+ exit_proc = self.class.finalize(@socket, @socket_dir, @socket_path, @pid, @spawner_pid)
193
+ Kernel.at_exit { exit_proc.call }
187
194
  end
188
195
 
189
196
  def create_responder(context)
@@ -24,7 +24,11 @@ module Speednode
24
24
  @popen_options = {}
25
25
  @popen_options[:external_encoding] = @encoding if @encoding
26
26
  @popen_options[:internal_encoding] = ::Encoding.default_internal || 'UTF-8'
27
- @contexts = {}
27
+ @contexts = {}
28
+ end
29
+
30
+ def context_registered?(uuid)
31
+ @contexts.key?(uuid)
28
32
  end
29
33
 
30
34
  def register_context(uuid, context)
@@ -33,8 +37,7 @@ module Speednode
33
37
 
34
38
  def unregister_context(uuid)
35
39
  context = @contexts.delete(uuid)
36
- if context && @vm
37
- ObjectSpace.undefine_finalizer(context)
40
+ if context
38
41
  @vm.delete_context(uuid) rescue nil # if delete_context fails, the vm exited before probably
39
42
  end
40
43
  @vm.stop if @contexts.size == 0 && @vm.started?
@@ -1,3 +1,3 @@
1
1
  module Speednode
2
- VERSION = '0.8.1'
2
+ VERSION = '0.9.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: speednode
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Biedermann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-16 00:00:00.000000000 Z
11
+ date: 2024-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: execjs
@@ -78,28 +78,28 @@ dependencies:
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: 5.20.0
81
+ version: 5.23.0
82
82
  type: :development
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: 5.20.0
88
+ version: 5.23.0
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: rake
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - "~>"
93
+ - - ">="
94
94
  - !ruby/object:Gem::Version
95
- version: 13.1.0
95
+ version: '0'
96
96
  type: :development
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
- - - "~>"
100
+ - - ">="
101
101
  - !ruby/object:Gem::Version
102
- version: 13.1.0
102
+ version: '0'
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: uglifier
105
105
  requirement: !ruby/object:Gem::Requirement
@@ -114,8 +114,8 @@ dependencies:
114
114
  - - ">="
115
115
  - !ruby/object:Gem::Version
116
116
  version: '0'
117
- description: A fast ExecJS runtime based on nodejs. As fast as mini_racer, but without
118
- the need to compile the js engine, because it uses the system provided nodejs.
117
+ description: A fast ExecJS, almost as fast as mini_racer, but without the need to
118
+ compile the js engine, because it uses the system provided nodejs.
119
119
  email: jan@kursator.de
120
120
  executables: []
121
121
  extensions: []
@@ -156,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
158
  requirements: []
159
- rubygems_version: 3.5.3
159
+ rubygems_version: 3.5.9
160
160
  signing_key:
161
161
  specification_version: 4
162
162
  summary: A fast ExecJS runtime based on nodejs.