speednode 0.8.2 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5d2a802e8fd3c7f25ef9c9dd0bef1807ec87d860da0a140f8a494868bcc2241
4
- data.tar.gz: 4ecc3ad8b012f0f76cf583789b9f78daec2a3606b3b5d94d163c1471d2a45341
3
+ metadata.gz: 3cb17f3391d9416c0a92291be8beaa42b25d8df70528e400d28a41984e3693bf
4
+ data.tar.gz: 463169b3ceb3d42703cbee80aa56c7edf2e1196a0114f8607eed173d0d6af583
5
5
  SHA512:
6
- metadata.gz: 616c54a7dafd5c2ddd67f0479e8fa241303d97cb9b3ac560858378996e46ccc4d976d18b175ba64768b32a9d3b519cf87d61962757fe49361c44aff71f8f7812
7
- data.tar.gz: a42e8fa9e0d825ebb7e2c0df0492286db295ce52b1d1dbfb5b459c1a1d6b79f33d4e5b255453da081408fe80a61ec4fc1876d1091eb116609d9af58ec0328f65
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
@@ -154,6 +158,7 @@ module Speednode
154
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])
158
163
  Process.detach(@pid)
159
164
 
@@ -184,8 +189,7 @@ module Speednode
184
189
 
185
190
  @started = true
186
191
 
187
- exit_proc = self.class.finalize(@socket, @socket_dir, @socket_path, @pid)
188
-
192
+ exit_proc = self.class.finalize(@socket, @socket_dir, @socket_path, @pid, @spawner_pid)
189
193
  Kernel.at_exit { exit_proc.call }
190
194
  end
191
195
 
@@ -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.2'
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.2
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-27 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.