execjs-pcruntime 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/.github/workflows/check.yml +23 -0
- data/.github/workflows/test.yml +7 -2
- data/Gemfile +1 -1
- data/README.md +2 -2
- data/execjs-pcruntime.gemspec +1 -1
- data/lib/execjs/pcruntime/context_process_runtime.rb +85 -14
- data/lib/execjs/pcruntime/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6f5cbb865a9d767748d30d1d4066d5739d93e218ba643a54872d49a139ed4dd
|
4
|
+
data.tar.gz: f8b27ca7a6faee4525e79f0252e2054afbe6d1698e85ddaeaf9602e62d4c392d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 315555b3b6d1b661abd6c4c37b95899d94abfa84e0b525e2211d77d7ade941a55aa4ee8f17d0ef314f71ae79e7fc3eea6c329b63ffb01aca459128b464d4652a
|
7
|
+
data.tar.gz: 4bdc7ecfb0cbf781fee0c27fcefc6a218c1dbd3916ba71e3e3c97729a7c676e633e5d1451cf20e44a26f2e65694de94cfc7e24757a3d3ba4af4b47ed4f19e969
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: Check
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ main ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
rubocop:
|
11
|
+
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v3
|
16
|
+
- name: Set up Ruby
|
17
|
+
uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: '3.3'
|
20
|
+
- name: Install dependencies
|
21
|
+
run: bundle install
|
22
|
+
- name: Run RuboCop
|
23
|
+
run: bundle exec rubocop
|
data/.github/workflows/test.yml
CHANGED
@@ -13,7 +13,8 @@ jobs:
|
|
13
13
|
|
14
14
|
strategy:
|
15
15
|
matrix:
|
16
|
-
ruby-version: ['3.
|
16
|
+
ruby-version: ['3.3', '3.2', '3.1']
|
17
|
+
node-version: ['16', '18', '20', '22']
|
17
18
|
|
18
19
|
steps:
|
19
20
|
- uses: actions/checkout@v3
|
@@ -21,7 +22,11 @@ jobs:
|
|
21
22
|
uses: ruby/setup-ruby@v1
|
22
23
|
with:
|
23
24
|
ruby-version: ${{ matrix.ruby-version }}
|
25
|
+
- name: Set up Node.js ${{ matrix.node-version }}
|
26
|
+
uses: actions/setup-node@v4
|
27
|
+
with:
|
28
|
+
node-version: ${{ matrix.node-version }}
|
24
29
|
- name: Install dependencies
|
25
30
|
run: bundle install
|
26
31
|
- name: Run tests
|
27
|
-
run: bundle exec rake
|
32
|
+
run: bundle exec rake
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -60,7 +60,7 @@ bundle exec rake
|
|
60
60
|
|
61
61
|
## Contributing
|
62
62
|
|
63
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
63
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/heyinc/execjs-pcruntime. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
64
64
|
|
65
65
|
## License
|
66
66
|
|
@@ -68,4 +68,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
68
68
|
|
69
69
|
## Code of Conduct
|
70
70
|
|
71
|
-
Everyone interacting in the Execjs::Pcruntime project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
71
|
+
Everyone interacting in the Execjs::Pcruntime project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/heyinc/execjs-pcruntime/blob/master/CODE_OF_CONDUCT.md).
|
data/execjs-pcruntime.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.name = 'execjs-pcruntime'
|
9
9
|
spec.version = Execjs::PCRuntime::VERSION
|
10
10
|
spec.authors = ['White-Green']
|
11
|
-
spec.required_ruby_version = '>=3.
|
11
|
+
spec.required_ruby_version = '>=3.1.0'
|
12
12
|
spec.summary = 'Fast ExecJS Runtime using Process as a Context.'
|
13
13
|
spec.homepage = 'https://rubygems.org/gems/execjs-pcruntime'
|
14
14
|
spec.license = 'MIT'
|
@@ -20,10 +20,7 @@ module ExecJS
|
|
20
20
|
super
|
21
21
|
|
22
22
|
# @type [JSRuntimeHandle]
|
23
|
-
@runtime = runtime.create_runtime_handle
|
24
|
-
|
25
|
-
# load initial source to Context
|
26
|
-
@runtime.evaluate(source.encode('UTF-8'))
|
23
|
+
@runtime = runtime.create_runtime_handle source.encode('UTF-8')
|
27
24
|
end
|
28
25
|
|
29
26
|
# implementation of ExecJS::Runtime::Context#eval
|
@@ -52,17 +49,19 @@ module ExecJS
|
|
52
49
|
|
53
50
|
# Handle of JavaScript Runtime
|
54
51
|
# launch Runtime by .new and finished on finalizer
|
52
|
+
# rubocop:disable Metrics/ClassLength
|
55
53
|
class JSRuntimeHandle
|
56
54
|
# @param [Array<String>] binary Launch command for the node(or similar JavaScript Runtime) binary,
|
57
55
|
# such as ['node'], ['deno', 'run'].
|
58
56
|
# @param [String] initial_source_path Path of .js Runtime loads at startup.
|
59
|
-
def initialize(binary, initial_source_path)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
57
|
+
def initialize(binary, initial_source_path, compile_source, semaphore)
|
58
|
+
@semaphore = semaphore
|
59
|
+
@binary = binary
|
60
|
+
@initial_source_path = initial_source_path
|
61
|
+
@compile_source = compile_source
|
62
|
+
@recreate_process_lock = Mutex.new
|
63
|
+
@runtime_pid, @socket_path = initialize_process
|
64
|
+
evaluate(@compile_source)
|
66
65
|
ObjectSpace.define_finalizer(self, self.class.finalizer(@runtime_pid))
|
67
66
|
end
|
68
67
|
|
@@ -70,7 +69,35 @@ module ExecJS
|
|
70
69
|
# @param [String] source JavaScript source code
|
71
70
|
# @return [object]
|
72
71
|
def evaluate(source)
|
73
|
-
|
72
|
+
socket_path = @socket_path
|
73
|
+
post_request(socket_path, '/eval', 'text/javascript', source)
|
74
|
+
rescue RuntimeError, ProgramError => e
|
75
|
+
raise e
|
76
|
+
rescue StandardError => e
|
77
|
+
warn e.full_message
|
78
|
+
retry if socket_path != @socket_path
|
79
|
+
@recreate_process_lock.synchronize do
|
80
|
+
@runtime_pid, @socket_path = recreate_process if socket_path == @socket_path
|
81
|
+
end
|
82
|
+
retry
|
83
|
+
end
|
84
|
+
|
85
|
+
# kill JavaScript runtime process and re-create
|
86
|
+
# @return [[Integer, String]] [runtime_pid, socket_path]
|
87
|
+
def recreate_process
|
88
|
+
runtime_pid = @runtime_pid
|
89
|
+
begin
|
90
|
+
err = self.class.kill_process(runtime_pid)
|
91
|
+
warn err.full_message unless err.nil?
|
92
|
+
runtime_pid, socket_path = initialize_process
|
93
|
+
post_request(socket_path, '/eval', 'text/javascript', @compile_source)
|
94
|
+
rescue RuntimeError, ProgramError => e
|
95
|
+
raise e
|
96
|
+
rescue StandardError => e
|
97
|
+
warn e.full_message
|
98
|
+
retry
|
99
|
+
end
|
100
|
+
[runtime_pid, socket_path]
|
74
101
|
end
|
75
102
|
|
76
103
|
# Create a procedure to kill the Process that has specified pid.
|
@@ -96,6 +123,20 @@ module ExecJS
|
|
96
123
|
|
97
124
|
private
|
98
125
|
|
126
|
+
# create temporary filename for UNIX Domain Socket and spawn JavaScript runtime process
|
127
|
+
# @return [[Integer, String]] [runtime_pid, socket_path]
|
128
|
+
def initialize_process
|
129
|
+
runtime_pid = 0
|
130
|
+
socket_path = ''
|
131
|
+
Dir::Tmpname.create 'execjs_pcruntime' do |path|
|
132
|
+
# Dir::Tmpname.create rescues Errno::EEXIST and retry block
|
133
|
+
# So, raise it if failed to create Process.
|
134
|
+
runtime_pid = create_process(path, *@binary, @initial_source_path) || raise(Errno::EEXIST)
|
135
|
+
socket_path = path
|
136
|
+
end
|
137
|
+
[runtime_pid, socket_path]
|
138
|
+
end
|
139
|
+
|
99
140
|
# Attempt to execute the block several times, spacing out the attempts over a certain period.
|
100
141
|
# @param [Integer] times maximum number of attempts
|
101
142
|
# @yieldreturn [Boolean] true iff succeed execute
|
@@ -148,6 +189,7 @@ module ExecJS
|
|
148
189
|
# so suppressing lint errors.
|
149
190
|
# rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
150
191
|
def post_request(socket_path, path, content_type = nil, body = nil)
|
192
|
+
@semaphore.acquire
|
151
193
|
socket = create_socket socket_path
|
152
194
|
|
153
195
|
# timeout occurred during the test
|
@@ -155,6 +197,7 @@ module ExecJS
|
|
155
197
|
socket.write_timeout *= 100
|
156
198
|
|
157
199
|
request = Net::HTTP::Post.new(path)
|
200
|
+
request['Host'] = 'localhost'
|
158
201
|
request['Connection'] = 'close'
|
159
202
|
unless content_type.nil?
|
160
203
|
request['Content-Type'] = content_type
|
@@ -187,10 +230,15 @@ module ExecJS
|
|
187
230
|
error.set_backtrace(stack)
|
188
231
|
raise error
|
189
232
|
end
|
233
|
+
ensure
|
234
|
+
@semaphore.release
|
190
235
|
end
|
236
|
+
|
191
237
|
# rubocop:enable Metrics/MethodLength,Metrics/AbcSize
|
192
238
|
end
|
193
239
|
|
240
|
+
# rubocop:enable Metrics/ClassLength
|
241
|
+
|
194
242
|
attr_reader :name
|
195
243
|
|
196
244
|
# @param [String] name name of Runtime
|
@@ -203,6 +251,8 @@ module ExecJS
|
|
203
251
|
@runner_path = runner_path
|
204
252
|
@binary = nil
|
205
253
|
@deprecated = deprecated
|
254
|
+
# limit number of threads 128 to avoid Errno::ECONNREFUSED
|
255
|
+
@semaphore = Semaphore.new 128
|
206
256
|
end
|
207
257
|
|
208
258
|
# implementation of ExecJS::Runtime#available?
|
@@ -217,8 +267,8 @@ module ExecJS
|
|
217
267
|
|
218
268
|
# Launch JavaScript Runtime and return its handle.
|
219
269
|
# @return [JSRuntimeHandle]
|
220
|
-
def create_runtime_handle
|
221
|
-
JSRuntimeHandle.new(binary, @runner_path)
|
270
|
+
def create_runtime_handle(compile_source)
|
271
|
+
JSRuntimeHandle.new(binary, @runner_path, compile_source, @semaphore)
|
222
272
|
end
|
223
273
|
|
224
274
|
private
|
@@ -256,5 +306,26 @@ module ExecJS
|
|
256
306
|
nil
|
257
307
|
end
|
258
308
|
end
|
309
|
+
|
310
|
+
# Semaphore
|
311
|
+
# implemented with Thread::Queue
|
312
|
+
# since faster than Concurrent::Semaphore and Mutex+ConditionVariable
|
313
|
+
class Semaphore
|
314
|
+
# @param [Integer] limit
|
315
|
+
def initialize(limit)
|
316
|
+
@queue = Thread::Queue.new
|
317
|
+
limit.times { @queue.push nil }
|
318
|
+
end
|
319
|
+
|
320
|
+
# acquires 1 of permits from this semaphore, blocking until be available.
|
321
|
+
def acquire
|
322
|
+
@queue.pop
|
323
|
+
end
|
324
|
+
|
325
|
+
# releases 1 of permits
|
326
|
+
def release
|
327
|
+
@queue.push nil
|
328
|
+
end
|
329
|
+
end
|
259
330
|
end
|
260
331
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: execjs-pcruntime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- White-Green
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -30,6 +30,7 @@ executables: []
|
|
30
30
|
extensions: []
|
31
31
|
extra_rdoc_files: []
|
32
32
|
files:
|
33
|
+
- ".github/workflows/check.yml"
|
33
34
|
- ".github/workflows/test.yml"
|
34
35
|
- ".gitignore"
|
35
36
|
- ".rubocop.yml"
|
@@ -69,14 +70,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
69
70
|
requirements:
|
70
71
|
- - ">="
|
71
72
|
- !ruby/object:Gem::Version
|
72
|
-
version: 3.
|
73
|
+
version: 3.1.0
|
73
74
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
75
|
requirements:
|
75
76
|
- - ">="
|
76
77
|
- !ruby/object:Gem::Version
|
77
78
|
version: '0'
|
78
79
|
requirements: []
|
79
|
-
rubygems_version: 3.
|
80
|
+
rubygems_version: 3.5.16
|
80
81
|
signing_key:
|
81
82
|
specification_version: 4
|
82
83
|
summary: Fast ExecJS Runtime using Process as a Context.
|