Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
deno
提交
d359789c
D
deno
项目概览
张重言
/
deno
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
deno
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
d359789c
编写于
4月 16, 2020
作者:
B
Bartek Iwańczuk
提交者:
GitHub
4月 16, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: support Deno namespace in Worker API (#4784)
上级
1cd1f7de
变更
13
隐藏空白更改
内联
并排
Showing
13 changed file
with
190 addition
and
21 deletion
+190
-21
cli/compilers/compiler_worker.rs
cli/compilers/compiler_worker.rs
+1
-1
cli/js/compiler.ts
cli/js/compiler.ts
+2
-2
cli/js/lib.deno.shared_globals.d.ts
cli/js/lib.deno.shared_globals.d.ts
+40
-0
cli/js/lib.deno.worker.d.ts
cli/js/lib.deno.worker.d.ts
+2
-0
cli/js/ops/worker_host.ts
cli/js/ops/worker_host.ts
+2
-0
cli/js/runtime_worker.ts
cli/js/runtime_worker.ts
+29
-3
cli/js/web/workers.ts
cli/js/web/workers.ts
+4
-0
cli/ops/worker_host.rs
cli/ops/worker_host.rs
+32
-11
cli/tests/subdir/deno_worker.ts
cli/tests/subdir/deno_worker.ts
+7
-0
cli/tests/subdir/non_deno_worker.js
cli/tests/subdir/non_deno_worker.js
+7
-0
cli/tests/workers_test.out
cli/tests/workers_test.out
+3
-2
cli/tests/workers_test.ts
cli/tests/workers_test.ts
+33
-0
cli/web_worker.rs
cli/web_worker.rs
+28
-2
未找到文件。
cli/compilers/compiler_worker.rs
浏览文件 @
d359789c
...
...
@@ -30,7 +30,7 @@ pub struct CompilerWorker(WebWorker);
impl
CompilerWorker
{
pub
fn
new
(
name
:
String
,
startup_data
:
StartupData
,
state
:
State
)
->
Self
{
let
state_
=
state
.clone
();
let
mut
worker
=
WebWorker
::
new
(
name
,
startup_data
,
state_
);
let
mut
worker
=
WebWorker
::
new
(
name
,
startup_data
,
state_
,
false
);
{
let
isolate
=
&
mut
worker
.isolate
;
ops
::
compiler
::
init
(
isolate
,
&
state
);
...
...
cli/js/compiler.ts
浏览文件 @
d359789c
...
...
@@ -391,12 +391,12 @@ async function wasmCompilerOnMessage({
}
function
bootstrapTsCompilerRuntime
():
void
{
bootstrapWorkerRuntime
(
"
TS
"
);
bootstrapWorkerRuntime
(
"
TS
"
,
false
);
globalThis
.
onmessage
=
tsCompilerOnMessage
;
}
function
bootstrapWasmCompilerRuntime
():
void
{
bootstrapWorkerRuntime
(
"
WASM
"
);
bootstrapWorkerRuntime
(
"
WASM
"
,
false
);
globalThis
.
onmessage
=
wasmCompilerOnMessage
;
}
...
...
cli/js/lib.deno.shared_globals.d.ts
浏览文件 @
d359789c
...
...
@@ -1080,6 +1080,46 @@ declare class Worker extends EventTarget {
options
?:
{
type
?:
"
classic
"
|
"
module
"
;
name
?:
string
;
/** UNSTABLE: New API. Expect many changes; most likely this
* field will be made into an object for more granular
* configuration of worker thread (permissions, import map, etc.).
*
* Set to `true` to make `Deno` namespace and all of its methods
* available to worker thread.
*
* Currently worker inherits permissions from main thread (permissions
* given using `--allow-*` flags).
* Configurable permissions are on the roadmap to be implemented.
*
* Example:
* // mod.ts
* const worker = new Worker("./deno_worker.ts", { type: "module", deno: true });
* worker.postMessage({ cmd: "readFile", fileName: "./log.txt" });
*
* // deno_worker.ts
*
*
* self.onmessage = async function (e) {
* const { cmd, fileName } = e.data;
* if (cmd !== "readFile") {
* throw new Error("Invalid command");
* }
* const buf = await Deno.readFile(fileName);
* const fileContents = new TextDecoder().decode(buf);
* console.log(fileContents);
* }
*
* // log.txt
* hello world
* hello world 2
*
* // run program
* $ deno run --allow-read mod.ts
* hello world
* hello world2
*
*/
deno
?:
boolean
;
}
);
postMessage
(
message
:
any
,
transfer
:
ArrayBuffer
[]):
void
;
...
...
cli/js/lib.deno.worker.d.ts
浏览文件 @
d359789c
...
...
@@ -3,6 +3,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any */
/// <reference no-default-lib="true" />
/// <reference lib="deno.ns" />
/// <reference lib="deno.shared_globals" />
/// <reference lib="esnext" />
...
...
@@ -15,6 +16,7 @@ declare interface DedicatedWorkerGlobalScope {
name
:
typeof
__workerMain
.
name
;
close
:
typeof
__workerMain
.
close
;
postMessage
:
typeof
__workerMain
.
postMessage
;
Deno
:
typeof
Deno
;
}
declare
const
self
:
DedicatedWorkerGlobalScope
&
typeof
globalThis
;
...
...
cli/js/ops/worker_host.ts
浏览文件 @
d359789c
...
...
@@ -6,6 +6,7 @@ export function createWorker(
specifier
:
string
,
hasSourceCode
:
boolean
,
sourceCode
:
string
,
useDenoNamespace
:
boolean
,
name
?:
string
):
{
id
:
number
}
{
return
sendSync
(
"
op_create_worker
"
,
{
...
...
@@ -13,6 +14,7 @@ export function createWorker(
hasSourceCode
,
sourceCode
,
name
,
useDenoNamespace
,
});
}
...
...
cli/js/runtime_worker.ts
浏览文件 @
d359789c
...
...
@@ -17,12 +17,23 @@ import {
eventTargetProperties
,
setEventTargetData
,
}
from
"
./globals.ts
"
;
import
*
as
Deno
from
"
./deno.ts
"
;
import
*
as
webWorkerOps
from
"
./ops/web_worker.ts
"
;
import
{
LocationImpl
}
from
"
./web/location.ts
"
;
import
{
log
,
assert
,
immutableDefine
}
from
"
./util.ts
"
;
import
{
MessageEvent
,
ErrorEvent
}
from
"
./web/workers.ts
"
;
import
{
TextEncoder
}
from
"
./web/text_encoding.ts
"
;
import
*
as
runtime
from
"
./runtime.ts
"
;
import
{
internalObject
}
from
"
./internals.ts
"
;
import
{
symbols
}
from
"
./symbols.ts
"
;
import
{
setSignals
}
from
"
./signals.ts
"
;
// FIXME(bartlomieju): duplicated in `runtime_main.ts`
// TODO: factor out `Deno` global assignment to separate function
// Add internal object to Deno object.
// This is not exposed as part of the Deno types.
// @ts-ignore
Deno
[
symbols
.
internal
]
=
internalObject
;
const
encoder
=
new
TextEncoder
();
...
...
@@ -109,6 +120,7 @@ export const workerRuntimeGlobalProperties = {
export
function
bootstrapWorkerRuntime
(
name
:
string
,
useDenoNamespace
:
boolean
,
internalName
?:
string
):
void
{
if
(
hasBootstrapped
)
{
...
...
@@ -128,7 +140,21 @@ export function bootstrapWorkerRuntime(
immutableDefine
(
globalThis
,
"
location
"
,
location
);
Object
.
freeze
(
globalThis
.
location
);
// globalThis.Deno is not available in worker scope
delete
globalThis
.
Deno
;
assert
(
globalThis
.
Deno
===
undefined
);
if
(
useDenoNamespace
)
{
Object
.
defineProperties
(
Deno
,
{
pid
:
readOnly
(
s
.
pid
),
noColor
:
readOnly
(
s
.
noColor
),
args
:
readOnly
(
Object
.
freeze
(
s
.
args
)),
});
// Setup `Deno` global - we're actually overriding already
// existing global `Deno` with `Deno` namespace from "./deno.ts".
immutableDefine
(
globalThis
,
"
Deno
"
,
Deno
);
Object
.
freeze
(
globalThis
.
Deno
);
Object
.
freeze
(
globalThis
.
Deno
.
core
);
Object
.
freeze
(
globalThis
.
Deno
.
core
.
sharedQueue
);
setSignals
();
}
else
{
delete
globalThis
.
Deno
;
assert
(
globalThis
.
Deno
===
undefined
);
}
}
cli/js/web/workers.ts
浏览文件 @
d359789c
...
...
@@ -105,6 +105,7 @@ export interface Worker {
export
interface
WorkerOptions
{
type
?:
"
classic
"
|
"
module
"
;
name
?:
string
;
deno
?:
boolean
;
}
export
class
WorkerImpl
extends
EventTarget
implements
Worker
{
...
...
@@ -146,10 +147,13 @@ export class WorkerImpl extends EventTarget implements Worker {
}
*/
const
useDenoNamespace
=
options
?
!!
options
.
deno
:
false
;
const
{
id
}
=
createWorker
(
specifier
,
hasSourceCode
,
sourceCode
,
useDenoNamespace
,
options
?.
name
);
this
.
#
id
=
id
;
...
...
cli/ops/worker_host.rs
浏览文件 @
d359789c
...
...
@@ -3,6 +3,7 @@ use super::dispatch_json::{Deserialize, JsonOp, Value};
use
crate
::
fmt_errors
::
JSError
;
use
crate
::
global_state
::
GlobalState
;
use
crate
::
op_error
::
OpError
;
use
crate
::
ops
::
io
::
get_stdio
;
use
crate
::
permissions
::
DenoPermissions
;
use
crate
::
startup_data
;
use
crate
::
state
::
State
;
...
...
@@ -37,17 +38,31 @@ fn create_web_worker(
global_state
:
GlobalState
,
permissions
:
DenoPermissions
,
specifier
:
ModuleSpecifier
,
has_deno_namespace
:
bool
,
)
->
Result
<
WebWorker
,
ErrBox
>
{
let
state
=
State
::
new_for_worker
(
global_state
,
Some
(
permissions
),
specifier
)
?
;
let
mut
worker
=
WebWorker
::
new
(
name
.to_string
(),
startup_data
::
deno_isolate_init
(),
state
);
if
has_deno_namespace
{
let
mut
s
=
state
.borrow_mut
();
let
(
stdin
,
stdout
,
stderr
)
=
get_stdio
();
s
.resource_table
.add
(
"stdin"
,
Box
::
new
(
stdin
));
s
.resource_table
.add
(
"stdout"
,
Box
::
new
(
stdout
));
s
.resource_table
.add
(
"stderr"
,
Box
::
new
(
stderr
));
}
let
mut
worker
=
WebWorker
::
new
(
name
.clone
(),
startup_data
::
deno_isolate_init
(),
state
,
has_deno_namespace
,
);
// Instead of using name for log we use `worker-${id}` because
// WebWorkers can have empty string as name.
let
script
=
format!
(
"bootstrapWorkerRuntime(
\"
{}
\"
,
\"
worker-{}
\"
)"
,
name
,
worker_id
"bootstrapWorkerRuntime(
\"
{}
\"
,
{},
\"
worker-{}
\"
)"
,
name
,
worker
.has_deno_namespace
,
worker
_id
);
worker
.execute
(
&
script
)
?
;
...
...
@@ -61,8 +76,8 @@ fn run_worker_thread(
global_state
:
GlobalState
,
permissions
:
DenoPermissions
,
specifier
:
ModuleSpecifier
,
has_
source_cod
e
:
bool
,
source_code
:
String
,
has_
deno_namespac
e
:
bool
,
maybe_source_code
:
Option
<
String
>
,
)
->
Result
<
(
JoinHandle
<
()
>
,
WebWorkerHandle
),
ErrBox
>
{
let
(
handle_sender
,
handle_receiver
)
=
std
::
sync
::
mpsc
::
sync_channel
::
<
Result
<
WebWorkerHandle
,
ErrBox
>>
(
1
);
...
...
@@ -80,6 +95,7 @@ fn run_worker_thread(
global_state
,
permissions
,
specifier
.clone
(),
has_deno_namespace
,
);
if
let
Err
(
err
)
=
result
{
...
...
@@ -108,7 +124,7 @@ fn run_worker_thread(
// TODO: run with using select with terminate
// Execute provided source code immediately
let
result
=
if
has
_source_code
{
let
result
=
if
let
Some
(
source_code
)
=
maybe
_source_code
{
worker
.execute
(
&
source_code
)
}
else
{
// TODO(bartlomieju): add "type": "classic", ie. ability to load
...
...
@@ -146,6 +162,7 @@ struct CreateWorkerArgs {
specifier
:
String
,
has_source_code
:
bool
,
source_code
:
String
,
use_deno_namespace
:
bool
,
}
/// Create worker as the host
...
...
@@ -157,9 +174,13 @@ fn op_create_worker(
let
args
:
CreateWorkerArgs
=
serde_json
::
from_value
(
args
)
?
;
let
specifier
=
args
.specifier
.clone
();
let
has_source_code
=
args
.has_source_code
;
let
source_code
=
args
.source_code
.clone
();
let
maybe_source_code
=
if
args
.has_source_code
{
Some
(
args
.source_code
.clone
())
}
else
{
None
};
let
args_name
=
args
.name
;
let
use_deno_namespace
=
args
.use_deno_namespace
;
let
parent_state
=
state
.clone
();
let
mut
state
=
state
.borrow_mut
();
let
global_state
=
state
.global_state
.clone
();
...
...
@@ -179,8 +200,8 @@ fn op_create_worker(
global_state
,
permissions
,
module_specifier
,
has_source_cod
e
,
source_code
,
use_deno_namespac
e
,
maybe_
source_code
,
)
.map_err
(|
e
|
OpError
::
other
(
e
.to_string
()))
?
;
// At this point all interactions with worker happen using thread
...
...
cli/tests/subdir/deno_worker.ts
0 → 100644
浏览文件 @
d359789c
onmessage
=
function
(
e
):
void
{
if
(
typeof
self
.
Deno
===
"
undefined
"
)
{
throw
new
Error
(
"
Deno namespace not available in worker
"
);
}
postMessage
(
e
.
data
);
};
cli/tests/subdir/non_deno_worker.js
0 → 100644
浏览文件 @
d359789c
onmessage
=
function
(
e
)
{
if
(
typeof
self
.
Deno
!==
"
undefined
"
)
{
throw
new
Error
(
"
Deno namespace unexpectedly available in worker
"
);
}
postMessage
(
e
.
data
);
};
cli/tests/workers_test.out
浏览文件 @
d359789c
running
8
tests
running
9
tests
test worker terminate ... ok [WILDCARD]
test worker nested ... ok [WILDCARD]
test worker throws when executing ... ok [WILDCARD]
...
...
@@ -7,5 +7,6 @@ test worker terminate busy loop ... ok [WILDCARD]
test worker race condition ... ok [WILDCARD]
test worker is event listener ... ok [WILDCARD]
test worker scope is event listener ... ok [WILDCARD]
test worker with Deno namespace ... ok [WILDCARD]
test result: ok.
8
passed; 0 failed; 0 ignored; 0 measured; 0 filtered out [WILDCARD]
test result: ok.
9
passed; 0 failed; 0 ignored; 0 measured; 0 filtered out [WILDCARD]
cli/tests/workers_test.ts
浏览文件 @
d359789c
...
...
@@ -257,3 +257,36 @@ Deno.test({
worker
.
terminate
();
},
});
Deno
.
test
({
name
:
"
worker with Deno namespace
"
,
fn
:
async
function
():
Promise
<
void
>
{
const
promise
=
createResolvable
();
const
promise2
=
createResolvable
();
const
regularWorker
=
new
Worker
(
"
../tests/subdir/non_deno_worker.js
"
,
{
type
:
"
module
"
,
});
const
denoWorker
=
new
Worker
(
"
../tests/subdir/deno_worker.ts
"
,
{
type
:
"
module
"
,
deno
:
true
,
});
regularWorker
.
onmessage
=
(
e
):
void
=>
{
assertEquals
(
e
.
data
,
"
Hello World
"
);
regularWorker
.
terminate
();
promise
.
resolve
();
};
denoWorker
.
onmessage
=
(
e
):
void
=>
{
assertEquals
(
e
.
data
,
"
Hello World
"
);
denoWorker
.
terminate
();
promise2
.
resolve
();
};
regularWorker
.
postMessage
(
"
Hello World
"
);
await
promise
;
denoWorker
.
postMessage
(
"
Hello World
"
);
await
promise2
;
},
});
cli/web_worker.rs
浏览文件 @
d359789c
...
...
@@ -77,10 +77,16 @@ pub struct WebWorker {
event_loop_idle
:
bool
,
terminate_rx
:
mpsc
::
Receiver
<
()
>
,
handle
:
WebWorkerHandle
,
pub
has_deno_namespace
:
bool
,
}
impl
WebWorker
{
pub
fn
new
(
name
:
String
,
startup_data
:
StartupData
,
state
:
State
)
->
Self
{
pub
fn
new
(
name
:
String
,
startup_data
:
StartupData
,
state
:
State
,
has_deno_namespace
:
bool
,
)
->
Self
{
let
state_
=
state
.clone
();
let
mut
worker
=
Worker
::
new
(
name
,
startup_data
,
state_
);
...
...
@@ -105,6 +111,7 @@ impl WebWorker {
event_loop_idle
:
false
,
terminate_rx
,
handle
,
has_deno_namespace
,
};
let
handle
=
web_worker
.thread_safe_handle
();
...
...
@@ -124,6 +131,22 @@ impl WebWorker {
ops
::
errors
::
init
(
isolate
,
&
state
);
ops
::
timers
::
init
(
isolate
,
&
state
);
ops
::
fetch
::
init
(
isolate
,
&
state
);
if
has_deno_namespace
{
let
op_registry
=
isolate
.op_registry
.clone
();
ops
::
runtime_compiler
::
init
(
isolate
,
&
state
);
ops
::
fs
::
init
(
isolate
,
&
state
);
ops
::
fs_events
::
init
(
isolate
,
&
state
);
ops
::
plugins
::
init
(
isolate
,
&
state
,
op_registry
);
ops
::
net
::
init
(
isolate
,
&
state
);
ops
::
tls
::
init
(
isolate
,
&
state
);
ops
::
os
::
init
(
isolate
,
&
state
);
ops
::
permissions
::
init
(
isolate
,
&
state
);
ops
::
process
::
init
(
isolate
,
&
state
);
ops
::
random
::
init
(
isolate
,
&
state
);
ops
::
signal
::
init
(
isolate
,
&
state
);
ops
::
tty
::
init
(
isolate
,
&
state
);
}
}
web_worker
...
...
@@ -238,8 +261,11 @@ mod tests {
"TEST"
.to_string
(),
startup_data
::
deno_isolate_init
(),
state
,
false
,
);
worker
.execute
(
"bootstrapWorkerRuntime(
\"
TEST
\"
)"
)
.unwrap
();
worker
.execute
(
"bootstrapWorkerRuntime(
\"
TEST
\"
, false)"
)
.unwrap
();
worker
}
#[test]
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录