jscall 1.0.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +225 -29
- data/examples/pdf-js.rb +56 -0
- data/lib/jscall/browser.mjs +36 -11
- data/lib/jscall/browser.rb +29 -7
- data/lib/jscall/main.mjs +218 -62
- data/lib/jscall/synch.mjs +185 -0
- data/lib/jscall/version.rb +1 -1
- data/lib/jscall.rb +246 -75
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dad6ca4017b93ba7f1675b3d1e3727a143d5e413f86d9f000966f7eae9306d06
|
4
|
+
data.tar.gz: e50ef13d47441f195194e4a36886b506266f87339f9d7bbf7f5b9d79dc500814
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16a7885d6e0e5ef993a9f8ea43a6dc2bcfe78624f20cd10517642c00f59525b1edab1a91ab99367f962d3f63ba5a5c6705bf7cad915673613fb9ee805358baeb
|
7
|
+
data.tar.gz: 1f7d95224652882839fd9bce1d4fd539021980018ecc1cca73aed56e598a2c034b8800cdfb88cc6ffd4b09f6488867e33335e8180f7e5e81aa29663ebdc6a5d4
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Jscall
|
2
2
|
|
3
|
+
[![Ruby](https://github.com/csg-tokyo/jscall/actions/workflows/ruby.yml/badge.svg)](https://github.com/csg-tokyo/jscall/actions/workflows/ruby.yml)
|
4
|
+
|
3
5
|
Jscall allows executing a program in JavaScript on node.js or a web browser.
|
4
6
|
By default, node.js is used for the execution.
|
5
7
|
To choose a web browser, call `Jscall.config`.
|
@@ -16,13 +18,17 @@ Jscall.exec '1 + 1'
|
|
16
18
|
```
|
17
19
|
|
18
20
|
This returns `2`. The argument passed to `Jscall.exec` can be
|
19
|
-
|
21
|
+
multiple lines. It is executed as source code written in JavaScript.
|
20
22
|
|
21
23
|
`Jscall.exec` returns a resulting value. Numbers, character strings (and symbols), boolean values, and `nil` (and `null`)
|
22
|
-
are copied when passing between Ruby and JavaScript. An array is
|
24
|
+
are copied when passing between Ruby and JavaScript. An array is shallow-copied.
|
23
25
|
Other objects are not copied. When they are passed, a remote reference is created at the destination.
|
26
|
+
When a `Map` object is returned from JavaScript to Ruby, it is also
|
27
|
+
shallow-copied but into a `Hash` object in Ruby.
|
24
28
|
|
25
|
-
A remote reference is a
|
29
|
+
A remote reference is a local reference to a proxy object.
|
30
|
+
A method call on a remote reference invokes a method on the corresponding
|
31
|
+
object on the remote site. For example,
|
26
32
|
|
27
33
|
```
|
28
34
|
js_obj = Jscall.exec '({ foo: (x) => x + 1, bar: 7 })'
|
@@ -35,11 +41,30 @@ js_obj.baz # 9
|
|
35
41
|
The `foo` method is executed in JavaScript.
|
36
42
|
Since `bar` is not a function, its value is returned to Ruby as it is.
|
37
43
|
|
38
|
-
Setting
|
44
|
+
Setting an object property to a given value is also
|
39
45
|
allowed. The expression `js_obj.baz = 9` above sets
|
40
46
|
the object property `baz` to 9.
|
41
47
|
|
42
|
-
|
48
|
+
An argument to a JavaScript method is copied from Ruby to
|
49
|
+
JavaScript unless it is an object. When an argument is a Ruby object,
|
50
|
+
a proxy object is created in JavaScript. The rule is the same as the
|
51
|
+
rule for returning a value from JavaScript to Ruby. A primitive
|
52
|
+
value is copied but an object is not. An array is shallow-copied.
|
53
|
+
|
54
|
+
A `Hash` object in Ruby is also shallow-copied into JavaScript but a normal
|
55
|
+
object is created in JavaScript. Recall that a JavaScript object is
|
56
|
+
regarded as an associative array, or a hash table as in Ruby.
|
57
|
+
For example, in Ruby,
|
58
|
+
|
59
|
+
```
|
60
|
+
obj = { a: 2, b: 3 }
|
61
|
+
```
|
62
|
+
|
63
|
+
when this ruby object is passed to JavaScript as an argument,
|
64
|
+
a normal object `{ a: 2, b: 3 }` is created as its copy in JavaScript
|
65
|
+
and passed to a JavaScript method.
|
66
|
+
|
67
|
+
To call a JavaScript function from Ruby, call a method on `Jscall`.
|
43
68
|
For example,
|
44
69
|
|
45
70
|
```
|
@@ -54,9 +79,22 @@ Jscall.foo(7) # 8
|
|
54
79
|
`Jscall.foo(7)` invokes the JavaScript function with the name following `Jscall.`
|
55
80
|
with the given argument. In this case,
|
56
81
|
the `foo` function is executed with the argument `7`.
|
82
|
+
Arguments and a return value are passed to/from a function
|
83
|
+
as they are passed to/from a method.
|
84
|
+
|
85
|
+
`Jscall` can be used for obtaining a remote reference to access a global variable
|
86
|
+
in JavaScript. For example,
|
87
|
+
|
88
|
+
```
|
89
|
+
Jscall.console.log('Hello')
|
90
|
+
```
|
91
|
+
|
92
|
+
This prints `Hello` on a JavaScript console. `Jscall.console` returns a remote
|
93
|
+
reference to the value of `console` in JavaScript. Then, `.log('Hello')`
|
94
|
+
calls the `log` method on `console` in JavaScript.
|
57
95
|
|
58
96
|
When a Ruby object is passed to a JavaScript function/method,
|
59
|
-
|
97
|
+
you can call a method on the passed Ruby object.
|
60
98
|
|
61
99
|
```
|
62
100
|
Jscall.exec <<CODE
|
@@ -72,7 +110,7 @@ created in Ruby.
|
|
72
110
|
Note that you must `await` every call to Ruby object since it is
|
73
111
|
asynchronous call.
|
74
112
|
|
75
|
-
In JavaScript, `Ruby.exec` is
|
113
|
+
In JavaScript, `Ruby.exec` is available to run a program in Ruby.
|
76
114
|
For example,
|
77
115
|
|
78
116
|
```
|
@@ -84,10 +122,19 @@ CODE
|
|
84
122
|
Jscall.foo()
|
85
123
|
```
|
86
124
|
|
87
|
-
`Jscall.foo()` returns the result of evaluating
|
88
|
-
in Ruby.
|
125
|
+
`Jscall.foo()` returns the result of evaluating given Ruby code
|
126
|
+
`RUBY_VERSION` in Ruby.
|
89
127
|
Don't forget to `await` a call to `Ruby.exec`.
|
90
128
|
|
129
|
+
### Remote references
|
130
|
+
|
131
|
+
A remote reference is implemented by a local reference to a proxy
|
132
|
+
object representing the remote object that the remote reference refers to.
|
133
|
+
When a proxy object is passed as an argument or a return value
|
134
|
+
from Ruby to JavaScript (or vice versa), the corresponding JavaScript
|
135
|
+
(or Ruby) object is passed to the destination. In other words,
|
136
|
+
a remote reference passed is converted back to a local reference.
|
137
|
+
|
91
138
|
Remote references will be automatically reclaimed when they are no
|
92
139
|
longer used. To reclaim them immediately, call:
|
93
140
|
|
@@ -95,6 +142,25 @@ longer used. To reclaim them immediately, call:
|
|
95
142
|
Jscall.scavenge_references
|
96
143
|
```
|
97
144
|
|
145
|
+
As mentioned above, a remote reference is a local reference
|
146
|
+
to a proxy object. In Ruby,
|
147
|
+
even a proxy object provides a number of methods inherited from `Object` class,
|
148
|
+
such as `clone`, `to_s`, and `inspect`. A call to such a method is not
|
149
|
+
delegated to the corresponding JavaScript object. To invoke such a method
|
150
|
+
on a JavaScript object, call `send` on its proxy object.
|
151
|
+
For example,
|
152
|
+
|
153
|
+
```
|
154
|
+
js_obj = Jscall.exec '({ to_s: (x, y) => x + y })'
|
155
|
+
puts js_obj.to_s(3, 4) # error
|
156
|
+
puts js_obj.send('to_s', 3, 4) # 7
|
157
|
+
```
|
158
|
+
|
159
|
+
The `send` method invokes the JavaScript method with the name specified
|
160
|
+
by the first argument. The remaining arguments passed to `send` are passed
|
161
|
+
to that JavaScript method.
|
162
|
+
|
163
|
+
|
98
164
|
## DOM manipulation
|
99
165
|
|
100
166
|
When JavaScript code is run on a browser, some utility methods
|
@@ -109,7 +175,16 @@ links `mystyle.css` in the current directory.
|
|
109
175
|
- `Jscall.dom.print(msg)`
|
110
176
|
|
111
177
|
This adds a `p` element to the DOM tree.
|
178
|
+
Its inner text is the character string passed as `msg`.
|
112
179
|
|
180
|
+
- `Jscall.dom.append_to_body(html_source)`
|
181
|
+
|
182
|
+
This inserts the given `html_source` at the end of the `body` element.
|
183
|
+
It is a shorthand for
|
184
|
+
|
185
|
+
```
|
186
|
+
Jscall.document.body.insertAdjacentHTML('beforeend', html_source)
|
187
|
+
```
|
113
188
|
|
114
189
|
## Variable scope
|
115
190
|
|
@@ -142,16 +217,33 @@ for loading a CommonJS module. For example,
|
|
142
217
|
Jscall.exec "mime = require('./mime.js')"
|
143
218
|
```
|
144
219
|
|
145
|
-
The file `./mime.js` is loaded and the module is bound to a global variable `mime
|
220
|
+
The file `./mime.js` is loaded and the module is bound to a global variable `mime` in JavaScript.
|
146
221
|
|
147
|
-
You
|
222
|
+
You can directly call `require` on `Jscall` in Ruby.
|
223
|
+
|
224
|
+
```
|
225
|
+
parser = Jscall.require("@babel/parser")
|
226
|
+
ast = parser.parse('const i = 3')
|
227
|
+
Jscall.console.log(ast)
|
228
|
+
```
|
229
|
+
|
230
|
+
`require` will search `./node_modules/` for `@babel/parser`.
|
231
|
+
This is equivalent to the following JavaScript code.
|
232
|
+
|
233
|
+
```
|
234
|
+
parser = require("@babel/parser")
|
235
|
+
ast = parser.parse('const i = 3')
|
236
|
+
console.log(ast)
|
237
|
+
```
|
238
|
+
|
239
|
+
Dynamic importing is also available. Call `Jscall.dyn_import` in Ruby.
|
148
240
|
|
149
241
|
```
|
150
242
|
fs = Jscall.dyn_import('fs')
|
151
243
|
```
|
152
244
|
|
153
245
|
This executes dynamic importing in JavaScript.
|
154
|
-
For node.js, the file name of the imported module should be a full path name. For a web browser, the root directory is
|
246
|
+
For node.js, the file name of the imported module should be a full path name. For a web browser, the root directory is the current working directory. So `Jscall.dyn_import('/mine.mjs')` loads the file `./mine.mjs`.
|
155
247
|
|
156
248
|
`Jscall.dyn_import` takes the second argument. If it is given,
|
157
249
|
a global variable in JavaScript is bound to the loaded module.
|
@@ -166,49 +258,147 @@ This is quite equivalent to the following JavaScript code:
|
|
166
258
|
fs_module = await load('fs')
|
167
259
|
```
|
168
260
|
|
261
|
+
## Promise
|
262
|
+
|
263
|
+
If a program attempts to pass a `Promise` object from JavaScript to Ruby,
|
264
|
+
it waits until the promise is fulfilled. Then Jscall passes
|
265
|
+
the value of that promise from JavaScript to Ruby instead of that
|
266
|
+
promise itself (or a remote reference to that promise). When that promise
|
267
|
+
is rejected, an error object is passed to Ruby
|
268
|
+
so that the error will be raised in Ruby.
|
269
|
+
This design reflects the fact that an `async` function in JavaScript
|
270
|
+
also returns a `Promise` object but this object must not be returned
|
271
|
+
to Ruby as is when that `async` function is called from Ruby.
|
272
|
+
Jscall cannot determine whether a promise should be passed as is to Ruby
|
273
|
+
or its value must be passed to Ruby after the promise is fulfilled.
|
274
|
+
|
275
|
+
When enforcing Jscall to pass a `Promise` object from JavaScript to Ruby,
|
276
|
+
`.async` must be inserted between a receiver and a method name.
|
277
|
+
|
278
|
+
```
|
279
|
+
Jscall.exec(<<CODE)
|
280
|
+
function make_promise() {
|
281
|
+
return { a: Promise.resolve(7) }
|
282
|
+
}
|
283
|
+
CODE
|
284
|
+
|
285
|
+
obj = Jscall.make_promise
|
286
|
+
result = obj.a # 7
|
287
|
+
prom = obj.async.a # promise
|
288
|
+
prom.then(->(r) { puts r }) # 7
|
289
|
+
```
|
290
|
+
|
291
|
+
## Synchronous calls
|
292
|
+
|
293
|
+
You might want to avoid writing `await` when you call a method on a Ruby
|
294
|
+
object or you execute Ruby code by `Ruby.exec` from JavaScript.
|
295
|
+
For example, that call is included in library code and you might not
|
296
|
+
be able to modify the library code so that `await` will be inserted.
|
297
|
+
|
298
|
+
Jscall supports synchronous calls from JavaScript to Ruby only when
|
299
|
+
the underlying JavaScript engine is node.js on Linux.
|
300
|
+
In the mode of synchronous calls, you do not have to `await` a method call
|
301
|
+
on a Ruby object or a call to `Ruby.exec`.
|
302
|
+
It blocks until the return value comes back from Ruby.
|
303
|
+
While it blocks, all calls from Ruby to JavaScript are
|
304
|
+
synchronously processed.
|
305
|
+
|
306
|
+
To change to the mode of synchronous calls,
|
307
|
+
call `Jscall.config`:
|
308
|
+
|
309
|
+
```
|
310
|
+
Jscall.config(sync: true)
|
311
|
+
```
|
169
312
|
|
170
313
|
## Configuration
|
171
314
|
|
172
|
-
|
315
|
+
Jscall supports several configuration options.
|
316
|
+
Call `Jscall.config` with necessary options.
|
317
|
+
|
318
|
+
### module_names:
|
319
|
+
|
320
|
+
To import JavaScript modules when node.js or a web browser starts,
|
173
321
|
|
174
322
|
```
|
175
|
-
Jscall.config(module_names: [["Foo", "./foo.mjs"], ["Bar", "./bar.mjs"]]
|
323
|
+
Jscall.config(module_names: [["Foo", "./js", "/lib/foo.mjs"], ["Bar", "./js", "/lib/bar.mjs"]])
|
176
324
|
```
|
177
325
|
|
178
|
-
This specifies that `./foo.mjs` and `./bar.mjs` are
|
326
|
+
This specifies that `./js/lib/foo.mjs` and `./js/lib/bar.mjs` are imported
|
327
|
+
at the beginning.
|
179
328
|
This is equivalent to the following import declarations:
|
180
329
|
|
181
330
|
```
|
182
|
-
import * as "Foo" from "./foo.mjs"
|
183
|
-
import * as "Bar" from "./bar.mjs"
|
331
|
+
import * as "Foo" from "./js/lib/foo.mjs"
|
332
|
+
import * as "Bar" from "./js/lib/bar.mjs"
|
184
333
|
```
|
185
334
|
|
186
|
-
|
335
|
+
Note that each array element given to `module_names:` is
|
187
336
|
|
188
|
-
|
337
|
+
```
|
338
|
+
[<module_name> <root> <path>]
|
339
|
+
```
|
189
340
|
|
190
|
-
|
341
|
+
`<path>` must start with `/`. It is used as a part of the URL when a browser
|
342
|
+
accesses a module.
|
343
|
+
When importing a module for node.js, `<root>` and `<path>` are concatenated
|
344
|
+
to form a full path name.
|
345
|
+
|
346
|
+
`<path>` must not start with `/jscall` or `/cmd`. They are reserved for
|
347
|
+
internal use.
|
348
|
+
|
349
|
+
### options:
|
350
|
+
|
351
|
+
To specify a command line argument passed to node.js,
|
191
352
|
|
192
353
|
```
|
193
|
-
Jscall
|
354
|
+
Jscall.config(options: '--use-strict')
|
194
355
|
```
|
195
356
|
|
196
|
-
|
357
|
+
This call specifies that
|
358
|
+
`--use-strict` is passed as a command line argument.
|
359
|
+
|
360
|
+
### browser: and port:
|
197
361
|
|
198
362
|
When running JavaScript code on a web browser,
|
199
363
|
|
200
364
|
```
|
201
|
-
Jscall.config(browser: true,
|
365
|
+
Jscall.config(browser: true, port: 10082)
|
202
366
|
```
|
203
367
|
|
204
|
-
`
|
368
|
+
Passing `true` for `browser:` switches the execution engine to a web browser.
|
369
|
+
The default engine is node.js.
|
370
|
+
To switch the engine back to node.js, pass `false` for `browser:`.
|
371
|
+
Call `Jscall.close` to detach the current execution engine.
|
372
|
+
A new engine with a new configuration will be created.
|
373
|
+
|
374
|
+
`port:` specifies the port number of an http server. It is optional.
|
205
375
|
The example above specifies that Ruby receives http requests
|
206
376
|
sent to http://localhost:10082 from JavaScript on a web browser.
|
207
377
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
378
|
+
|
379
|
+
### Misc.
|
380
|
+
|
381
|
+
To change to the mode of synchronous calls,
|
382
|
+
|
383
|
+
```
|
384
|
+
Jscall.config(sync: true)
|
385
|
+
```
|
386
|
+
|
387
|
+
To set all the configurations to the default ones,
|
388
|
+
|
389
|
+
```
|
390
|
+
Jscall.config()
|
391
|
+
```
|
392
|
+
|
393
|
+
### Other configurations
|
394
|
+
|
395
|
+
To change the name of the node command,
|
396
|
+
|
397
|
+
```
|
398
|
+
Jscall::PipeToJs.node_command = "node.exe"
|
399
|
+
```
|
400
|
+
|
401
|
+
The default command name is `"node"`.
|
212
402
|
|
213
403
|
To change the command for launching a web browser,
|
214
404
|
|
@@ -224,6 +414,12 @@ Jscall launches a web browser by the command like the following:
|
|
224
414
|
open http://localhost:10082/jscall/jscall.html
|
225
415
|
```
|
226
416
|
|
417
|
+
Jscall generates a verbose error message if its debug level is more than 0.
|
418
|
+
|
419
|
+
```
|
420
|
+
Jscall.debug = 1
|
421
|
+
```
|
422
|
+
|
227
423
|
## Installation
|
228
424
|
|
229
425
|
Add this line to your application's Gemfile:
|
@@ -254,7 +450,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/csg-to
|
|
254
450
|
|
255
451
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
256
452
|
|
257
|
-
##
|
453
|
+
## Acknowledgment
|
258
454
|
|
259
455
|
The icon image for jscall was created by partly using the Ruby logo, which was obtained
|
260
456
|
from https://www.ruby-lang.org/en/about/logo/ under CC BY-SA 2.5.
|
data/examples/pdf-js.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Display a pdf file by using pdf.js
|
2
|
+
|
3
|
+
require 'jscall'
|
4
|
+
|
5
|
+
# Run a JavaScript program on a browser
|
6
|
+
Jscall.config browser: true
|
7
|
+
|
8
|
+
# Write HTML code on a blank web page.
|
9
|
+
Jscall.dom.append_to_body(<<CODE)
|
10
|
+
<h1>PDF.js 'Hello, world!' example</h1>
|
11
|
+
<canvas id="the-canvas"></canvas>
|
12
|
+
CODE
|
13
|
+
|
14
|
+
# import pdf.js
|
15
|
+
pdfjs = Jscall.dyn_import('https://mozilla.github.io/pdf.js/build/pdf.js')
|
16
|
+
|
17
|
+
# A pdf file
|
18
|
+
url = "https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf"
|
19
|
+
|
20
|
+
pdf = Jscall.exec 'window["pdfjs-dist/build/pdf"]'
|
21
|
+
|
22
|
+
pdf.GlobalWorkerOptions.workerSrc = "https://mozilla.github.io/pdf.js/build/pdf.worker.js"
|
23
|
+
|
24
|
+
loadingTask = pdf.getDocument(url)
|
25
|
+
loadingTask.async.promise.then(-> (pdf) {
|
26
|
+
puts "PDF loaded"
|
27
|
+
|
28
|
+
# Fetch the first page
|
29
|
+
pageNumber = 1;
|
30
|
+
pdf.async.getPage(pageNumber).then(-> (page) {
|
31
|
+
puts "Page loaded"
|
32
|
+
|
33
|
+
scale = 1.5;
|
34
|
+
viewport = page.getViewport({ scale: scale })
|
35
|
+
|
36
|
+
canvas = Jscall.document.getElementById("the-canvas")
|
37
|
+
context = canvas.getContext("2d")
|
38
|
+
canvas.height = viewport.height
|
39
|
+
canvas.width = viewport.width
|
40
|
+
|
41
|
+
# Render the pdf page
|
42
|
+
renderContext = {
|
43
|
+
canvasContext: context,
|
44
|
+
viewport: viewport,
|
45
|
+
}
|
46
|
+
renderTask = page.render(renderContext)
|
47
|
+
renderTask.async.promise.then(-> (r) {
|
48
|
+
# Print a message when the rendering succeeds.
|
49
|
+
puts "Page rendered #{r}"
|
50
|
+
})
|
51
|
+
})
|
52
|
+
},
|
53
|
+
-> (reason) {
|
54
|
+
# an error occurs.
|
55
|
+
puts reason
|
56
|
+
})
|
data/lib/jscall/browser.mjs
CHANGED
@@ -2,24 +2,27 @@
|
|
2
2
|
|
3
3
|
export class HttpStream {
|
4
4
|
constructor() {
|
5
|
-
this.
|
5
|
+
this.recv_buffer = []
|
6
6
|
this.send_callback = null
|
7
|
+
this.fetching = null
|
8
|
+
this.call_queue = []
|
9
|
+
this.puts('start')
|
7
10
|
}
|
8
11
|
|
9
12
|
[Symbol.asyncIterator]() {
|
10
13
|
const http_stream = this
|
11
14
|
return {
|
12
15
|
next() {
|
13
|
-
let
|
14
|
-
if (
|
16
|
+
let next_data = http_stream.recv_buffer.shift()
|
17
|
+
if (next_data === undefined)
|
15
18
|
return new Promise((resolve, reject) => {
|
16
19
|
if (http_stream.send_callback === null)
|
17
20
|
http_stream.send_callback = resolve
|
18
21
|
else
|
19
22
|
throw new Error('(fatal) send_callback is not null!')
|
20
|
-
})
|
23
|
+
})
|
21
24
|
else
|
22
|
-
return
|
25
|
+
return next_data
|
23
26
|
}
|
24
27
|
}
|
25
28
|
}
|
@@ -40,12 +43,30 @@ export class HttpStream {
|
|
40
43
|
}
|
41
44
|
|
42
45
|
puts(msg) {
|
43
|
-
this.
|
44
|
-
|
45
|
-
|
46
|
-
this.
|
47
|
-
|
48
|
-
|
46
|
+
if (this.fetching === null)
|
47
|
+
this.fetching = this.puts0(msg)
|
48
|
+
else
|
49
|
+
this.call_queue.push(msg)
|
50
|
+
}
|
51
|
+
|
52
|
+
puts0(msg) {
|
53
|
+
return this.do_fetch(msg)
|
54
|
+
.then((data) => {
|
55
|
+
if (this.send_callback === null)
|
56
|
+
this.recv_buffer.push(data)
|
57
|
+
else {
|
58
|
+
const callback = this.send_callback
|
59
|
+
this.send_callback = null
|
60
|
+
callback(data)
|
61
|
+
}
|
62
|
+
|
63
|
+
if (this.call_queue.length > 0) {
|
64
|
+
const msg2 = this.call_queue.shift()
|
65
|
+
this.fetching = this.puts0(msg2)
|
66
|
+
}
|
67
|
+
else
|
68
|
+
this.fetching = null
|
69
|
+
})
|
49
70
|
}
|
50
71
|
|
51
72
|
setEncoding(encoding) {}
|
@@ -64,4 +85,8 @@ export const Jscall = new class {
|
|
64
85
|
link.href = file_name
|
65
86
|
document.head.append(link)
|
66
87
|
}
|
88
|
+
|
89
|
+
append_to_body(html_source) {
|
90
|
+
document.body.insertAdjacentHTML('beforeend', html_source)
|
91
|
+
}
|
67
92
|
}
|
data/lib/jscall/browser.rb
CHANGED
@@ -8,6 +8,7 @@ module Jscall
|
|
8
8
|
WEBrick::HTTPUtils::DefaultMimeTypes['mjs'] ||= "application/javascript"
|
9
9
|
|
10
10
|
class Dom
|
11
|
+
# see Jscall class in browser.mjs
|
11
12
|
def method_missing(name, *args)
|
12
13
|
Jscall.__getpipe__.funcall(nil, "Jscall.#{name}", args)
|
13
14
|
end
|
@@ -23,13 +24,27 @@ module Jscall
|
|
23
24
|
end
|
24
25
|
|
25
26
|
class PipeToBrowser < PipeToJs
|
26
|
-
def startJS(module_names,
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
def startJS(module_names, config)
|
28
|
+
urls = {}
|
29
|
+
module_names.each_index do |i|
|
30
|
+
mod = module_names[i]
|
31
|
+
urls[mod[2]] = mod
|
32
|
+
end
|
33
|
+
port = config[:port] || 10081
|
34
|
+
@pipe = FetchServer.new(port, urls)
|
30
35
|
@pipe.open
|
31
36
|
end
|
32
37
|
|
38
|
+
def setup(config)
|
39
|
+
if config[:browser]
|
40
|
+
module_names = config[:module_names] || []
|
41
|
+
module_names.each_index do |i|
|
42
|
+
mod = module_names[i]
|
43
|
+
Jscall.dyn_import(mod[2], mod[0])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
33
48
|
def close
|
34
49
|
@pipe.shutdown
|
35
50
|
sleep(0.5)
|
@@ -58,7 +73,8 @@ module Jscall
|
|
58
73
|
@@run_cmd = name
|
59
74
|
end
|
60
75
|
|
61
|
-
def initialize(port)
|
76
|
+
def initialize(port, urls)
|
77
|
+
@url_map = urls
|
62
78
|
@send_buffer = Thread::Queue.new
|
63
79
|
@receive_buffer = Thread::Queue.new
|
64
80
|
@server_running = false
|
@@ -96,10 +112,16 @@ module Jscall
|
|
96
112
|
end
|
97
113
|
|
98
114
|
def read_file(req, res)
|
99
|
-
|
115
|
+
path = req.path
|
116
|
+
if path.start_with?('/jscall/')
|
100
117
|
root = "#{__dir__}/../"
|
101
118
|
else
|
102
|
-
|
119
|
+
value = @url_map[path]
|
120
|
+
if value.nil?
|
121
|
+
root = @server.config[:DocumentRoot]
|
122
|
+
else
|
123
|
+
root = value[1]
|
124
|
+
end
|
103
125
|
end
|
104
126
|
WEBrick::HTTPServlet::FileHandler.new(@server, root).service(req, res)
|
105
127
|
end
|