mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
refactor(cli): decouple ops from ProgramState and Flags (#8659)
This commit does major refactor of "Worker" and "WebWorker", in order to decouple them from "ProgramState" and "Flags". The main points of interest are "create_main_worker()" and "create_web_worker_callback()" functions which are responsible for creating "Worker" and "WebWorker" in CLI context. As a result it is now possible to factor out common "runtime" functionality into a separate crate.
This commit is contained in:
parent
9414dee9e5
commit
65e72b68ac
19 changed files with 465 additions and 281 deletions
|
@ -228,7 +228,7 @@ lazy_static! {
|
|||
crate::version::deno(),
|
||||
env!("PROFILE"),
|
||||
env!("TARGET"),
|
||||
crate::version::v8(),
|
||||
deno_core::v8_version(),
|
||||
crate::version::TYPESCRIPT
|
||||
);
|
||||
}
|
||||
|
|
|
@ -203,7 +203,7 @@ async fn server(
|
|||
warp::reply::json(&json!({
|
||||
"Browser": format!("Deno/{}", crate::version::deno()),
|
||||
"Protocol-Version": "1.3",
|
||||
"V8-Version": crate::version::v8(),
|
||||
"V8-Version": deno_core::v8_version(),
|
||||
}))
|
||||
});
|
||||
|
||||
|
|
154
cli/main.rs
154
cli/main.rs
|
@ -55,15 +55,22 @@ use crate::file_fetcher::FileFetcher;
|
|||
use crate::file_watcher::ModuleResolutionResult;
|
||||
use crate::flags::DenoSubcommand;
|
||||
use crate::flags::Flags;
|
||||
use crate::fmt_errors::PrettyJsError;
|
||||
use crate::import_map::ImportMap;
|
||||
use crate::media_type::MediaType;
|
||||
use crate::module_loader::CliModuleLoader;
|
||||
use crate::ops::worker_host::CreateWebWorkerCb;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::program_state::exit_unstable;
|
||||
use crate::program_state::ProgramState;
|
||||
use crate::source_maps::apply_source_map;
|
||||
use crate::specifier_handler::FetchHandler;
|
||||
use crate::standalone::create_standalone_binary;
|
||||
use crate::tools::installer::infer_name_from_url;
|
||||
use crate::web_worker::WebWorker;
|
||||
use crate::web_worker::WebWorkerOptions;
|
||||
use crate::worker::MainWorker;
|
||||
use crate::worker::WorkerOptions;
|
||||
use deno_core::error::generic_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::future::FutureExt;
|
||||
|
@ -86,6 +93,134 @@ use std::pin::Pin;
|
|||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn create_web_worker_callback(
|
||||
program_state: Arc<ProgramState>,
|
||||
) -> Arc<CreateWebWorkerCb> {
|
||||
Arc::new(move |args| {
|
||||
let global_state_ = program_state.clone();
|
||||
let js_error_create_fn = Rc::new(move |core_js_error| {
|
||||
let source_mapped_error =
|
||||
apply_source_map(&core_js_error, global_state_.clone());
|
||||
PrettyJsError::create(source_mapped_error)
|
||||
});
|
||||
|
||||
let attach_inspector = program_state.maybe_inspector_server.is_some()
|
||||
|| program_state.flags.coverage;
|
||||
let maybe_inspector_server = program_state.maybe_inspector_server.clone();
|
||||
|
||||
let module_loader = CliModuleLoader::new_for_worker(program_state.clone());
|
||||
let create_web_worker_cb =
|
||||
create_web_worker_callback(program_state.clone());
|
||||
|
||||
let options = WebWorkerOptions {
|
||||
args: program_state.flags.argv.clone(),
|
||||
apply_source_maps: true,
|
||||
debug_flag: program_state
|
||||
.flags
|
||||
.log_level
|
||||
.map_or(false, |l| l == log::Level::Debug),
|
||||
unstable: program_state.flags.unstable,
|
||||
ca_filepath: program_state.flags.ca_file.clone(),
|
||||
seed: program_state.flags.seed,
|
||||
module_loader,
|
||||
create_web_worker_cb,
|
||||
js_error_create_fn: Some(js_error_create_fn),
|
||||
use_deno_namespace: args.use_deno_namespace,
|
||||
attach_inspector,
|
||||
maybe_inspector_server,
|
||||
};
|
||||
|
||||
let mut worker = WebWorker::from_options(
|
||||
args.name,
|
||||
args.permissions,
|
||||
args.main_module,
|
||||
args.worker_id,
|
||||
&options,
|
||||
);
|
||||
|
||||
// This block registers additional ops and state that
|
||||
// are only available in the CLI
|
||||
{
|
||||
let js_runtime = &mut worker.js_runtime;
|
||||
js_runtime
|
||||
.op_state()
|
||||
.borrow_mut()
|
||||
.put::<Arc<ProgramState>>(program_state.clone());
|
||||
// Applies source maps - works in conjuction with `js_error_create_fn`
|
||||
// above
|
||||
ops::errors::init(js_runtime);
|
||||
if args.use_deno_namespace {
|
||||
ops::runtime_compiler::init(js_runtime);
|
||||
}
|
||||
}
|
||||
worker.bootstrap(&options);
|
||||
|
||||
worker
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_main_worker(
|
||||
program_state: &Arc<ProgramState>,
|
||||
main_module: ModuleSpecifier,
|
||||
permissions: Permissions,
|
||||
) -> MainWorker {
|
||||
let module_loader = CliModuleLoader::new(program_state.clone());
|
||||
|
||||
let global_state_ = program_state.clone();
|
||||
|
||||
let js_error_create_fn = Rc::new(move |core_js_error| {
|
||||
let source_mapped_error =
|
||||
apply_source_map(&core_js_error, global_state_.clone());
|
||||
PrettyJsError::create(source_mapped_error)
|
||||
});
|
||||
|
||||
let attach_inspector = program_state.maybe_inspector_server.is_some()
|
||||
|| program_state.flags.repl
|
||||
|| program_state.flags.coverage;
|
||||
let maybe_inspector_server = program_state.maybe_inspector_server.clone();
|
||||
let should_break_on_first_statement =
|
||||
program_state.flags.inspect_brk.is_some();
|
||||
|
||||
let create_web_worker_cb = create_web_worker_callback(program_state.clone());
|
||||
|
||||
let options = WorkerOptions {
|
||||
apply_source_maps: true,
|
||||
args: program_state.flags.argv.clone(),
|
||||
debug_flag: program_state
|
||||
.flags
|
||||
.log_level
|
||||
.map_or(false, |l| l == log::Level::Debug),
|
||||
unstable: program_state.flags.unstable,
|
||||
ca_filepath: program_state.flags.ca_file.clone(),
|
||||
seed: program_state.flags.seed,
|
||||
js_error_create_fn: Some(js_error_create_fn),
|
||||
create_web_worker_cb,
|
||||
attach_inspector,
|
||||
maybe_inspector_server,
|
||||
should_break_on_first_statement,
|
||||
module_loader,
|
||||
};
|
||||
|
||||
let mut worker = MainWorker::from_options(main_module, permissions, &options);
|
||||
|
||||
// This block registers additional ops and state that
|
||||
// are only available in the CLI
|
||||
{
|
||||
let js_runtime = &mut worker.js_runtime;
|
||||
js_runtime
|
||||
.op_state()
|
||||
.borrow_mut()
|
||||
.put::<Arc<ProgramState>>(program_state.clone());
|
||||
// Applies source maps - works in conjuction with `js_error_create_fn`
|
||||
// above
|
||||
ops::errors::init(js_runtime);
|
||||
ops::runtime_compiler::init(js_runtime);
|
||||
}
|
||||
worker.bootstrap(&options);
|
||||
|
||||
worker
|
||||
}
|
||||
|
||||
fn write_to_stdout_ignore_sigpipe(bytes: &[u8]) -> Result<(), std::io::Error> {
|
||||
use std::io::ErrorKind;
|
||||
|
||||
|
@ -253,7 +388,7 @@ async fn install_command(
|
|||
let program_state = ProgramState::new(preload_flags)?;
|
||||
let main_module = ModuleSpecifier::resolve_url_or_path(&module_url)?;
|
||||
let mut worker =
|
||||
MainWorker::new(&program_state, main_module.clone(), permissions);
|
||||
create_main_worker(&program_state, main_module.clone(), permissions);
|
||||
// First, fetch and compile the module; this step ensures that the module exists.
|
||||
worker.preload_module(&main_module).await?;
|
||||
tools::installer::install(flags, &module_url, args, name, root, force)
|
||||
|
@ -321,7 +456,7 @@ async fn eval_command(
|
|||
let permissions = Permissions::from_flags(&flags);
|
||||
let program_state = ProgramState::new(flags)?;
|
||||
let mut worker =
|
||||
MainWorker::new(&program_state, main_module.clone(), permissions);
|
||||
create_main_worker(&program_state, main_module.clone(), permissions);
|
||||
let main_module_url = main_module.as_url().to_owned();
|
||||
// Create a dummy source file.
|
||||
let source_code = if print {
|
||||
|
@ -664,7 +799,7 @@ async fn run_repl(flags: Flags) -> Result<(), AnyError> {
|
|||
let permissions = Permissions::from_flags(&flags);
|
||||
let program_state = ProgramState::new(flags)?;
|
||||
let mut worker =
|
||||
MainWorker::new(&program_state, main_module.clone(), permissions);
|
||||
create_main_worker(&program_state, main_module.clone(), permissions);
|
||||
worker.run_event_loop().await?;
|
||||
|
||||
tools::repl::run(&program_state, worker).await
|
||||
|
@ -675,8 +810,11 @@ async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> {
|
|||
let permissions = Permissions::from_flags(&flags);
|
||||
let main_module =
|
||||
ModuleSpecifier::resolve_url_or_path("./$deno$stdin.ts").unwrap();
|
||||
let mut worker =
|
||||
MainWorker::new(&program_state.clone(), main_module.clone(), permissions);
|
||||
let mut worker = create_main_worker(
|
||||
&program_state.clone(),
|
||||
main_module.clone(),
|
||||
permissions,
|
||||
);
|
||||
|
||||
let mut source = Vec::new();
|
||||
std::io::stdin().read_to_end(&mut source)?;
|
||||
|
@ -755,7 +893,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> {
|
|||
let main_module = main_module.clone();
|
||||
let program_state = ProgramState::new(flags)?;
|
||||
let mut worker =
|
||||
MainWorker::new(&program_state, main_module.clone(), permissions);
|
||||
create_main_worker(&program_state, main_module.clone(), permissions);
|
||||
debug!("main_module {}", main_module);
|
||||
worker.execute_module(&main_module).await?;
|
||||
worker.execute("window.dispatchEvent(new Event('load'))")?;
|
||||
|
@ -788,7 +926,7 @@ async fn run_command(flags: Flags, script: String) -> Result<(), AnyError> {
|
|||
let program_state = ProgramState::new(flags.clone())?;
|
||||
let permissions = Permissions::from_flags(&flags);
|
||||
let mut worker =
|
||||
MainWorker::new(&program_state, main_module.clone(), permissions);
|
||||
create_main_worker(&program_state, main_module.clone(), permissions);
|
||||
debug!("main_module {}", main_module);
|
||||
worker.execute_module(&main_module).await?;
|
||||
worker.execute("window.dispatchEvent(new Event('load'))")?;
|
||||
|
@ -857,7 +995,7 @@ async fn test_command(
|
|||
}
|
||||
|
||||
let mut worker =
|
||||
MainWorker::new(&program_state, main_module.clone(), permissions);
|
||||
create_main_worker(&program_state, main_module.clone(), permissions);
|
||||
|
||||
let mut maybe_coverage_collector = if flags.coverage {
|
||||
let session = worker.create_inspector_session();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::diagnostics::Diagnostics;
|
||||
use crate::program_state::ProgramState;
|
||||
use crate::source_maps::get_orig_position;
|
||||
use crate::source_maps::CachedMaps;
|
||||
use deno_core::error::AnyError;
|
||||
|
@ -11,6 +12,7 @@ use deno_core::OpState;
|
|||
use deno_core::ZeroCopyBuf;
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn init(rt: &mut deno_core::JsRuntime) {
|
||||
super::reg_json_sync(rt, "op_apply_source_map", op_apply_source_map);
|
||||
|
@ -33,13 +35,15 @@ fn op_apply_source_map(
|
|||
let args: ApplySourceMap = serde_json::from_value(args)?;
|
||||
|
||||
let mut mappings_map: CachedMaps = HashMap::new();
|
||||
let program_state = state.borrow::<Arc<ProgramState>>().clone();
|
||||
|
||||
let (orig_file_name, orig_line_number, orig_column_number) =
|
||||
get_orig_position(
|
||||
args.file_name,
|
||||
args.line_number.into(),
|
||||
args.column_number.into(),
|
||||
&mut mappings_map,
|
||||
super::program_state(state),
|
||||
program_state,
|
||||
);
|
||||
|
||||
Ok(json!({
|
||||
|
|
|
@ -27,7 +27,6 @@ pub mod websocket;
|
|||
pub mod worker_host;
|
||||
|
||||
use crate::metrics::metrics_op;
|
||||
use crate::program_state::ProgramState;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::json_op_async;
|
||||
use deno_core::json_op_sync;
|
||||
|
@ -39,7 +38,6 @@ use deno_core::ZeroCopyBuf;
|
|||
use std::cell::RefCell;
|
||||
use std::future::Future;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn reg_json_async<F, R>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
|
||||
where
|
||||
|
@ -57,24 +55,33 @@ where
|
|||
rt.register_op(name, metrics_op(json_op_sync(op_fn)));
|
||||
}
|
||||
|
||||
pub struct UnstableChecker {
|
||||
pub unstable: bool,
|
||||
}
|
||||
|
||||
impl UnstableChecker {
|
||||
/// Quits the process if the --unstable flag was not provided.
|
||||
///
|
||||
/// This is intentionally a non-recoverable check so that people cannot probe
|
||||
/// for unstable APIs from stable programs.
|
||||
// NOTE(bartlomieju): keep in sync with `cli/program_state.rs`
|
||||
pub fn check_unstable(&self, api_name: &str) {
|
||||
if !self.unstable {
|
||||
eprintln!(
|
||||
"Unstable API '{}'. The --unstable flag must be provided.",
|
||||
api_name
|
||||
);
|
||||
std::process::exit(70);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Helper for checking unstable features. Used for sync ops.
|
||||
pub fn check_unstable(state: &OpState, api_name: &str) {
|
||||
state.borrow::<Arc<ProgramState>>().check_unstable(api_name)
|
||||
state.borrow::<UnstableChecker>().check_unstable(api_name)
|
||||
}
|
||||
|
||||
/// Helper for checking unstable features. Used for async ops.
|
||||
pub fn check_unstable2(state: &Rc<RefCell<OpState>>, api_name: &str) {
|
||||
let state = state.borrow();
|
||||
state.borrow::<Arc<ProgramState>>().check_unstable(api_name)
|
||||
}
|
||||
|
||||
/// Helper for extracting the commonly used state. Used for sync ops.
|
||||
pub fn program_state(state: &OpState) -> Arc<ProgramState> {
|
||||
state.borrow::<Arc<ProgramState>>().clone()
|
||||
}
|
||||
|
||||
/// Helper for extracting the commonly used state. Used for async ops.
|
||||
pub fn global_state2(state: &Rc<RefCell<OpState>>) -> Arc<ProgramState> {
|
||||
let state = state.borrow();
|
||||
state.borrow::<Arc<ProgramState>>().clone()
|
||||
state.borrow::<UnstableChecker>().check_unstable(api_name)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::colors;
|
||||
use crate::metrics::Metrics;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::version;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::serde_json::json;
|
||||
|
@ -11,50 +9,17 @@ use deno_core::serde_json::Value;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use std::env;
|
||||
|
||||
type ApplySourceMaps = bool;
|
||||
|
||||
pub fn init(
|
||||
rt: &mut deno_core::JsRuntime,
|
||||
main_module: ModuleSpecifier,
|
||||
apply_source_maps: bool,
|
||||
) {
|
||||
pub fn init(rt: &mut deno_core::JsRuntime, main_module: ModuleSpecifier) {
|
||||
{
|
||||
let op_state = rt.op_state();
|
||||
let mut state = op_state.borrow_mut();
|
||||
state.put::<ModuleSpecifier>(main_module);
|
||||
state.put::<ApplySourceMaps>(apply_source_maps);
|
||||
}
|
||||
super::reg_json_sync(rt, "op_start", op_start);
|
||||
super::reg_json_sync(rt, "op_main_module", op_main_module);
|
||||
super::reg_json_sync(rt, "op_metrics", op_metrics);
|
||||
}
|
||||
|
||||
fn op_start(
|
||||
state: &mut OpState,
|
||||
_args: Value,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let apply_source_maps = *state.borrow::<ApplySourceMaps>();
|
||||
let gs = &super::program_state(state);
|
||||
|
||||
Ok(json!({
|
||||
"args": gs.flags.argv.clone(),
|
||||
"applySourceMaps": apply_source_maps,
|
||||
"debugFlag": gs.flags.log_level.map_or(false, |l| l == log::Level::Debug),
|
||||
"denoVersion": version::deno(),
|
||||
"noColor": !colors::use_color(),
|
||||
"pid": std::process::id(),
|
||||
"ppid": ppid(),
|
||||
"target": env!("TARGET"),
|
||||
"tsVersion": version::TYPESCRIPT,
|
||||
"unstableFlag": gs.flags.unstable,
|
||||
"v8Version": version::v8(),
|
||||
"versionFlag": gs.flags.version,
|
||||
}))
|
||||
}
|
||||
|
||||
fn op_main_module(
|
||||
state: &mut OpState,
|
||||
_args: Value,
|
||||
|
@ -93,7 +58,7 @@ fn op_metrics(
|
|||
}))
|
||||
}
|
||||
|
||||
fn ppid() -> Value {
|
||||
pub fn ppid() -> Value {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
// Adopted from rustup:
|
||||
|
|
|
@ -7,10 +7,12 @@ use crate::module_graph::BundleType;
|
|||
use crate::module_graph::EmitOptions;
|
||||
use crate::module_graph::GraphBuilder;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::program_state::ProgramState;
|
||||
use crate::specifier_handler::FetchHandler;
|
||||
use crate::specifier_handler::MemoryHandler;
|
||||
use crate::specifier_handler::SpecifierHandler;
|
||||
use crate::tsc_config;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::error::Context;
|
||||
|
@ -51,7 +53,7 @@ async fn op_compile(
|
|||
} else {
|
||||
super::check_unstable2(&state, "Deno.compile");
|
||||
}
|
||||
let program_state = super::global_state2(&state);
|
||||
let program_state = state.borrow().borrow::<Arc<ProgramState>>().clone();
|
||||
let runtime_permissions = {
|
||||
let state = state.borrow();
|
||||
state.borrow::<Permissions>().clone()
|
||||
|
|
|
@ -33,7 +33,17 @@ use tokio_tungstenite::tungstenite::{
|
|||
use tokio_tungstenite::{client_async, WebSocketStream};
|
||||
use webpki::DNSNameRef;
|
||||
|
||||
pub fn init(rt: &mut deno_core::JsRuntime) {
|
||||
#[derive(Clone)]
|
||||
struct WsCaFile(String);
|
||||
|
||||
pub fn init(rt: &mut deno_core::JsRuntime, maybe_ca_file: Option<&str>) {
|
||||
{
|
||||
let op_state = rt.op_state();
|
||||
let mut state = op_state.borrow_mut();
|
||||
if let Some(ca_file) = maybe_ca_file {
|
||||
state.put::<WsCaFile>(WsCaFile(ca_file.to_string()));
|
||||
}
|
||||
}
|
||||
super::reg_json_sync(rt, "op_ws_check_permission", op_ws_check_permission);
|
||||
super::reg_json_async(rt, "op_ws_create", op_ws_create);
|
||||
super::reg_json_async(rt, "op_ws_send", op_ws_send);
|
||||
|
@ -92,10 +102,7 @@ pub async fn op_ws_create(
|
|||
);
|
||||
}
|
||||
|
||||
let ca_file = {
|
||||
let program_state = super::global_state2(&state);
|
||||
program_state.flags.ca_file.clone()
|
||||
};
|
||||
let maybe_ca_file = state.borrow().try_borrow::<WsCaFile>().cloned();
|
||||
let uri: Uri = args.url.parse()?;
|
||||
let mut request = Request::builder().method(Method::GET).uri(&uri);
|
||||
|
||||
|
@ -128,8 +135,8 @@ pub async fn op_ws_create(
|
|||
.root_store
|
||||
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||
|
||||
if let Some(path) = ca_file {
|
||||
let key_file = File::open(path)?;
|
||||
if let Some(ws_ca_file) = maybe_ca_file {
|
||||
let key_file = File::open(ws_ca_file.0)?;
|
||||
let reader = &mut BufReader::new(key_file);
|
||||
config.root_store.add_pem_file(reader).unwrap();
|
||||
}
|
||||
|
|
|
@ -21,8 +21,27 @@ use std::cell::RefCell;
|
|||
use std::collections::HashMap;
|
||||
use std::convert::From;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
pub struct CreateWebWorkerArgs {
|
||||
pub name: String,
|
||||
pub worker_id: u32,
|
||||
pub permissions: Permissions,
|
||||
pub main_module: ModuleSpecifier,
|
||||
pub use_deno_namespace: bool,
|
||||
}
|
||||
|
||||
pub type CreateWebWorkerCb =
|
||||
dyn Fn(CreateWebWorkerArgs) -> WebWorker + Sync + Send;
|
||||
|
||||
/// A holder for callback that is used to create a new
|
||||
/// WebWorker. It's a struct instead of a type alias
|
||||
/// because `GothamState` used in `OpState` overrides
|
||||
/// value if type alises have the same underlying type
|
||||
#[derive(Clone)]
|
||||
pub struct CreateWebWorkerCbHolder(Arc<CreateWebWorkerCb>);
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct HostUnhandledErrorArgs {
|
||||
message: String,
|
||||
|
@ -31,12 +50,16 @@ struct HostUnhandledErrorArgs {
|
|||
pub fn init(
|
||||
rt: &mut deno_core::JsRuntime,
|
||||
sender: Option<mpsc::Sender<WorkerEvent>>,
|
||||
create_web_worker_cb: Arc<CreateWebWorkerCb>,
|
||||
) {
|
||||
{
|
||||
let op_state = rt.op_state();
|
||||
let mut state = op_state.borrow_mut();
|
||||
state.put::<WorkersTable>(WorkersTable::default());
|
||||
state.put::<WorkerId>(WorkerId::default());
|
||||
|
||||
let create_module_loader = CreateWebWorkerCbHolder(create_web_worker_cb);
|
||||
state.put::<CreateWebWorkerCbHolder>(create_module_loader);
|
||||
}
|
||||
super::reg_json_sync(rt, "op_create_worker", op_create_worker);
|
||||
super::reg_json_sync(
|
||||
|
@ -102,11 +125,12 @@ fn op_create_worker(
|
|||
}
|
||||
let permissions = state.borrow::<Permissions>().clone();
|
||||
let worker_id = state.take::<WorkerId>();
|
||||
let create_module_loader = state.take::<CreateWebWorkerCbHolder>();
|
||||
state.put::<CreateWebWorkerCbHolder>(create_module_loader.clone());
|
||||
state.put::<WorkerId>(worker_id + 1);
|
||||
|
||||
let module_specifier = ModuleSpecifier::resolve_url(&specifier)?;
|
||||
let worker_name = args_name.unwrap_or_else(|| "".to_string());
|
||||
let program_state = super::program_state(state);
|
||||
|
||||
let (handle_sender, handle_receiver) =
|
||||
std::sync::mpsc::sync_channel::<Result<WebWorkerHandle, AnyError>>(1);
|
||||
|
@ -121,14 +145,14 @@ fn op_create_worker(
|
|||
// - JS worker is useless - meaning it throws an exception and can't do anything else,
|
||||
// all action done upon it should be noops
|
||||
// - newly spawned thread exits
|
||||
let worker = WebWorker::new(
|
||||
worker_name,
|
||||
permissions,
|
||||
module_specifier.clone(),
|
||||
program_state,
|
||||
use_deno_namespace,
|
||||
|
||||
let worker = (create_module_loader.0)(CreateWebWorkerArgs {
|
||||
name: worker_name,
|
||||
worker_id,
|
||||
);
|
||||
permissions,
|
||||
main_module: module_specifier.clone(),
|
||||
use_deno_namespace,
|
||||
});
|
||||
|
||||
// Send thread safe handle to newly created worker to host thread
|
||||
handle_sender.send(Ok(worker.thread_safe_handle())).unwrap();
|
||||
|
|
|
@ -258,16 +258,6 @@ impl ProgramState {
|
|||
}
|
||||
}
|
||||
|
||||
/// Quits the process if the --unstable flag was not provided.
|
||||
///
|
||||
/// This is intentionally a non-recoverable check so that people cannot probe
|
||||
/// for unstable APIs from stable programs.
|
||||
pub fn check_unstable(&self, api_name: &str) {
|
||||
if !self.flags.unstable {
|
||||
exit_unstable(api_name);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn mock(
|
||||
argv: Vec<String>,
|
||||
|
|
|
@ -132,40 +132,31 @@ delete Object.prototype.__proto__;
|
|||
core.jsonOpSync("op_worker_close");
|
||||
}
|
||||
|
||||
function opStart() {
|
||||
return core.jsonOpSync("op_start");
|
||||
}
|
||||
|
||||
function opMainModule() {
|
||||
return core.jsonOpSync("op_main_module");
|
||||
}
|
||||
|
||||
// TODO(bartlomieju): temporary solution, must be fixed when moving
|
||||
// dispatches to separate crates
|
||||
function initOps() {
|
||||
function runtimeStart(runtimeOptions, source) {
|
||||
const opsMap = core.ops();
|
||||
for (const [name, opId] of Object.entries(opsMap)) {
|
||||
if (name === "op_write" || name === "op_read") {
|
||||
core.setAsyncHandler(opId, dispatchMinimal.asyncMsgFromRust);
|
||||
}
|
||||
}
|
||||
core.setMacrotaskCallback(timers.handleTimerMacrotask);
|
||||
}
|
||||
|
||||
function runtimeStart(source) {
|
||||
initOps();
|
||||
// First we send an empty `Start` message to let the privileged side know we
|
||||
// are ready. The response should be a `StartRes` message containing the CLI
|
||||
// args and other info.
|
||||
const s = opStart();
|
||||
version.setVersions(s.denoVersion, s.v8Version, s.tsVersion);
|
||||
build.setBuildInfo(s.target);
|
||||
util.setLogDebug(s.debugFlag, source);
|
||||
core.setMacrotaskCallback(timers.handleTimerMacrotask);
|
||||
version.setVersions(
|
||||
runtimeOptions.denoVersion,
|
||||
runtimeOptions.v8Version,
|
||||
runtimeOptions.tsVersion,
|
||||
);
|
||||
build.setBuildInfo(runtimeOptions.target);
|
||||
util.setLogDebug(runtimeOptions.debugFlag, source);
|
||||
// TODO(bartlomieju): a very crude way to disable
|
||||
// source mapping of errors. This condition is true
|
||||
// only for compiled standalone binaries.
|
||||
let prepareStackTrace;
|
||||
if (s.applySourceMaps) {
|
||||
if (runtimeOptions.applySourceMaps) {
|
||||
prepareStackTrace = core.createPrepareStackTrace(
|
||||
errorStack.opApplySourceMap,
|
||||
);
|
||||
|
@ -173,8 +164,6 @@ delete Object.prototype.__proto__;
|
|||
prepareStackTrace = core.createPrepareStackTrace();
|
||||
}
|
||||
Error.prepareStackTrace = prepareStackTrace;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
function registerErrors() {
|
||||
|
@ -283,7 +272,7 @@ delete Object.prototype.__proto__;
|
|||
|
||||
let hasBootstrapped = false;
|
||||
|
||||
function bootstrapMainRuntime() {
|
||||
function bootstrapMainRuntime(runtimeOptions) {
|
||||
if (hasBootstrapped) {
|
||||
throw new Error("Worker runtime already bootstrapped");
|
||||
}
|
||||
|
@ -300,7 +289,8 @@ delete Object.prototype.__proto__;
|
|||
defineEventHandler(window, "load", null);
|
||||
defineEventHandler(window, "unload", null);
|
||||
|
||||
const { args, noColor, pid, ppid, unstableFlag } = runtimeStart();
|
||||
runtimeStart(runtimeOptions);
|
||||
const { args, noColor, pid, ppid, unstableFlag } = runtimeOptions;
|
||||
|
||||
registerErrors();
|
||||
|
||||
|
@ -335,7 +325,12 @@ delete Object.prototype.__proto__;
|
|||
util.log("args", args);
|
||||
}
|
||||
|
||||
function bootstrapWorkerRuntime(name, useDenoNamespace, internalName) {
|
||||
function bootstrapWorkerRuntime(
|
||||
runtimeOptions,
|
||||
name,
|
||||
useDenoNamespace,
|
||||
internalName,
|
||||
) {
|
||||
if (hasBootstrapped) {
|
||||
throw new Error("Worker runtime already bootstrapped");
|
||||
}
|
||||
|
@ -349,9 +344,12 @@ delete Object.prototype.__proto__;
|
|||
Object.defineProperties(globalThis, { name: util.readOnly(name) });
|
||||
Object.setPrototypeOf(globalThis, DedicatedWorkerGlobalScope.prototype);
|
||||
eventTarget.setEventTargetData(globalThis);
|
||||
const { unstableFlag, pid, noColor, args } = runtimeStart(
|
||||
|
||||
runtimeStart(
|
||||
runtimeOptions,
|
||||
internalName ?? name,
|
||||
);
|
||||
const { unstableFlag, pid, noColor, args } = runtimeOptions;
|
||||
|
||||
registerErrors();
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::colors;
|
||||
use crate::flags::Flags;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::program_state::ProgramState;
|
||||
use crate::tokio_util;
|
||||
use crate::worker::MainWorker;
|
||||
use crate::worker::WorkerOptions;
|
||||
use deno_core::error::type_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::FutureExt;
|
||||
|
@ -21,6 +21,7 @@ use std::io::Write;
|
|||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
const MAGIC_TRAILER: &[u8; 8] = b"d3n0l4nd";
|
||||
|
||||
|
@ -109,16 +110,29 @@ async fn run(source_code: String, args: Vec<String>) -> Result<(), AnyError> {
|
|||
// TODO(lucacasonato): remove once you can specify this correctly through embedded metadata
|
||||
flags.unstable = true;
|
||||
let main_module = ModuleSpecifier::resolve_url(SPECIFIER)?;
|
||||
let program_state = ProgramState::new(flags.clone())?;
|
||||
let permissions = Permissions::allow_all();
|
||||
let module_loader = Rc::new(EmbeddedModuleLoader(source_code));
|
||||
let mut worker = MainWorker::from_options(
|
||||
&program_state,
|
||||
main_module.clone(),
|
||||
permissions,
|
||||
let create_web_worker_cb = Arc::new(|_| {
|
||||
todo!("Worker are currently not supported in standalone binaries");
|
||||
});
|
||||
|
||||
let options = WorkerOptions {
|
||||
apply_source_maps: false,
|
||||
args: flags.argv.clone(),
|
||||
debug_flag: false,
|
||||
unstable: true,
|
||||
ca_filepath: None,
|
||||
seed: None,
|
||||
js_error_create_fn: None,
|
||||
create_web_worker_cb,
|
||||
attach_inspector: false,
|
||||
maybe_inspector_server: None,
|
||||
should_break_on_first_statement: false,
|
||||
module_loader,
|
||||
None,
|
||||
);
|
||||
};
|
||||
let mut worker =
|
||||
MainWorker::from_options(main_module.clone(), permissions, &options);
|
||||
worker.bootstrap(&options);
|
||||
worker.execute_module(&main_module).await?;
|
||||
worker.execute("window.dispatchEvent(new Event('load'))")?;
|
||||
worker.run_event_loop().await?;
|
||||
|
|
|
@ -2646,11 +2646,6 @@ itest!(fmt_stdin_check_not_formatted {
|
|||
output_str: Some("Not formatted stdin\n"),
|
||||
});
|
||||
|
||||
itest!(circular1 {
|
||||
args: "run --reload circular1.js",
|
||||
output: "circular1.js.out",
|
||||
});
|
||||
|
||||
itest!(config {
|
||||
args: "run --reload --config config.tsconfig.json config.ts",
|
||||
exit_code: 1,
|
||||
|
|
|
@ -13,7 +13,3 @@ pub fn deno() -> String {
|
|||
pub fn is_canary() -> bool {
|
||||
option_env!("DENO_CANARY").is_some()
|
||||
}
|
||||
|
||||
pub fn v8() -> &'static str {
|
||||
deno_core::v8_version()
|
||||
}
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::colors;
|
||||
use crate::fmt_errors::PrettyJsError;
|
||||
use crate::inspector::DenoInspector;
|
||||
use crate::inspector::InspectorServer;
|
||||
use crate::js;
|
||||
use crate::metrics::Metrics;
|
||||
use crate::module_loader::CliModuleLoader;
|
||||
use crate::ops;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::program_state::ProgramState;
|
||||
use crate::source_maps::apply_source_map;
|
||||
use crate::tokio_util::create_basic_runtime;
|
||||
use crate::version;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::channel::mpsc;
|
||||
use deno_core::futures::future::poll_fn;
|
||||
use deno_core::futures::future::FutureExt;
|
||||
use deno_core::futures::stream::StreamExt;
|
||||
use deno_core::futures::task::AtomicWaker;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::v8;
|
||||
use deno_core::JsErrorCreateFn;
|
||||
use deno_core::JsRuntime;
|
||||
use deno_core::ModuleLoader;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::RuntimeOptions;
|
||||
use std::env;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
@ -115,6 +118,7 @@ fn create_channels(
|
|||
/// Each `WebWorker` is either a child of `MainWorker` or other
|
||||
/// `WebWorker`.
|
||||
pub struct WebWorker {
|
||||
id: u32,
|
||||
inspector: Option<Box<DenoInspector>>,
|
||||
// Following fields are pub because they are accessed
|
||||
// when creating a new WebWorker instance.
|
||||
|
@ -125,46 +129,48 @@ pub struct WebWorker {
|
|||
event_loop_idle: bool,
|
||||
terminate_rx: mpsc::Receiver<()>,
|
||||
handle: WebWorkerHandle,
|
||||
pub has_deno_namespace: bool,
|
||||
pub use_deno_namespace: bool,
|
||||
}
|
||||
|
||||
pub struct WebWorkerOptions {
|
||||
pub args: Vec<String>,
|
||||
pub debug_flag: bool,
|
||||
pub unstable: bool,
|
||||
pub ca_filepath: Option<String>,
|
||||
pub seed: Option<u64>,
|
||||
pub module_loader: Rc<dyn ModuleLoader>,
|
||||
pub create_web_worker_cb: Arc<ops::worker_host::CreateWebWorkerCb>,
|
||||
pub js_error_create_fn: Option<Rc<JsErrorCreateFn>>,
|
||||
pub use_deno_namespace: bool,
|
||||
pub attach_inspector: bool,
|
||||
pub maybe_inspector_server: Option<Arc<InspectorServer>>,
|
||||
pub apply_source_maps: bool,
|
||||
}
|
||||
|
||||
impl WebWorker {
|
||||
pub fn new(
|
||||
pub fn from_options(
|
||||
name: String,
|
||||
permissions: Permissions,
|
||||
main_module: ModuleSpecifier,
|
||||
program_state: Arc<ProgramState>,
|
||||
has_deno_namespace: bool,
|
||||
worker_id: u32,
|
||||
options: &WebWorkerOptions,
|
||||
) -> Self {
|
||||
let module_loader = CliModuleLoader::new_for_worker(program_state.clone());
|
||||
let global_state_ = program_state.clone();
|
||||
|
||||
let js_error_create_fn = Box::new(move |core_js_error| {
|
||||
let source_mapped_error =
|
||||
apply_source_map(&core_js_error, global_state_.clone());
|
||||
PrettyJsError::create(source_mapped_error)
|
||||
});
|
||||
|
||||
let mut js_runtime = JsRuntime::new(RuntimeOptions {
|
||||
module_loader: Some(module_loader),
|
||||
module_loader: Some(options.module_loader.clone()),
|
||||
startup_snapshot: Some(js::deno_isolate_init()),
|
||||
js_error_create_fn: Some(js_error_create_fn),
|
||||
js_error_create_fn: options.js_error_create_fn.clone(),
|
||||
get_error_class_fn: Some(&crate::errors::get_error_class_name),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let inspector =
|
||||
if let Some(inspector_server) = &program_state.maybe_inspector_server {
|
||||
Some(DenoInspector::new(
|
||||
&mut js_runtime,
|
||||
Some(inspector_server.clone()),
|
||||
))
|
||||
} else if program_state.flags.coverage || program_state.flags.repl {
|
||||
Some(DenoInspector::new(&mut js_runtime, None))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let inspector = if options.attach_inspector {
|
||||
Some(DenoInspector::new(
|
||||
&mut js_runtime,
|
||||
options.maybe_inspector_server.clone(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (terminate_tx, terminate_rx) = mpsc::channel::<()>(1);
|
||||
let isolate_handle = js_runtime.v8_isolate().thread_safe_handle();
|
||||
|
@ -172,15 +178,16 @@ impl WebWorker {
|
|||
create_channels(isolate_handle, terminate_tx);
|
||||
|
||||
let mut worker = Self {
|
||||
id: worker_id,
|
||||
inspector,
|
||||
internal_channels,
|
||||
js_runtime,
|
||||
name: name.clone(),
|
||||
name,
|
||||
waker: AtomicWaker::new(),
|
||||
event_loop_idle: false,
|
||||
terminate_rx,
|
||||
handle,
|
||||
has_deno_namespace,
|
||||
use_deno_namespace: options.use_deno_namespace,
|
||||
};
|
||||
|
||||
{
|
||||
|
@ -192,15 +199,21 @@ impl WebWorker {
|
|||
let op_state = js_runtime.op_state();
|
||||
let mut op_state = op_state.borrow_mut();
|
||||
op_state.put::<Metrics>(Default::default());
|
||||
op_state.put::<Arc<ProgramState>>(program_state.clone());
|
||||
op_state.put::<Permissions>(permissions);
|
||||
op_state.put::<ops::UnstableChecker>(ops::UnstableChecker {
|
||||
unstable: options.unstable,
|
||||
});
|
||||
}
|
||||
|
||||
ops::web_worker::init(js_runtime, sender.clone(), handle);
|
||||
ops::runtime::init(js_runtime, main_module, true);
|
||||
ops::fetch::init(js_runtime, program_state.flags.ca_file.as_deref());
|
||||
ops::runtime::init(js_runtime, main_module);
|
||||
ops::fetch::init(js_runtime, options.ca_filepath.as_deref());
|
||||
ops::timers::init(js_runtime);
|
||||
ops::worker_host::init(js_runtime, Some(sender));
|
||||
ops::worker_host::init(
|
||||
js_runtime,
|
||||
Some(sender),
|
||||
options.create_web_worker_cb.clone(),
|
||||
);
|
||||
ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close);
|
||||
ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources);
|
||||
ops::reg_json_sync(
|
||||
|
@ -208,11 +221,10 @@ impl WebWorker {
|
|||
"op_domain_to_ascii",
|
||||
deno_web::op_domain_to_ascii,
|
||||
);
|
||||
ops::errors::init(js_runtime);
|
||||
ops::io::init(js_runtime);
|
||||
ops::websocket::init(js_runtime);
|
||||
ops::websocket::init(js_runtime, options.ca_filepath.as_deref());
|
||||
|
||||
if has_deno_namespace {
|
||||
if options.use_deno_namespace {
|
||||
ops::fs_events::init(js_runtime);
|
||||
ops::fs::init(js_runtime);
|
||||
ops::net::init(js_runtime);
|
||||
|
@ -220,8 +232,7 @@ impl WebWorker {
|
|||
ops::permissions::init(js_runtime);
|
||||
ops::plugin::init(js_runtime);
|
||||
ops::process::init(js_runtime);
|
||||
ops::crypto::init(js_runtime, program_state.flags.seed);
|
||||
ops::runtime_compiler::init(js_runtime);
|
||||
ops::crypto::init(js_runtime, options.seed);
|
||||
ops::signal::init(js_runtime);
|
||||
ops::tls::init(js_runtime);
|
||||
ops::tty::init(js_runtime);
|
||||
|
@ -239,19 +250,38 @@ impl WebWorker {
|
|||
op_state.resource_table.add("stderr", Box::new(stream));
|
||||
}
|
||||
}
|
||||
|
||||
worker
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bootstrap(&mut self, options: &WebWorkerOptions) {
|
||||
let runtime_options = json!({
|
||||
"args": options.args,
|
||||
"applySourceMaps": options.apply_source_maps,
|
||||
"debugFlag": options.debug_flag,
|
||||
"denoVersion": version::deno(),
|
||||
"noColor": !colors::use_color(),
|
||||
"pid": std::process::id(),
|
||||
"ppid": ops::runtime::ppid(),
|
||||
"target": env!("TARGET"),
|
||||
"tsVersion": version::TYPESCRIPT,
|
||||
"unstableFlag": options.unstable,
|
||||
"v8Version": deno_core::v8_version(),
|
||||
});
|
||||
|
||||
let runtime_options_str =
|
||||
serde_json::to_string_pretty(&runtime_options).unwrap();
|
||||
|
||||
// Instead of using name for log we use `worker-${id}` because
|
||||
// WebWorkers can have empty string as name.
|
||||
let script = format!(
|
||||
"bootstrap.workerRuntime(\"{}\", {}, \"worker-{}\")",
|
||||
name, worker.has_deno_namespace, worker_id
|
||||
"bootstrap.workerRuntime({}, \"{}\", {}, \"worker-{}\")",
|
||||
runtime_options_str, self.name, options.use_deno_namespace, self.id
|
||||
);
|
||||
worker
|
||||
self
|
||||
.execute(&script)
|
||||
.expect("Failed to execute worker bootstrap script");
|
||||
|
||||
worker
|
||||
}
|
||||
|
||||
/// Same as execute2() but the filename defaults to "$CWD/__anonymous__".
|
||||
|
@ -421,22 +451,39 @@ pub fn run_web_worker(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::program_state::ProgramState;
|
||||
use crate::tokio_util;
|
||||
use deno_core::serde_json::json;
|
||||
|
||||
fn create_test_web_worker() -> WebWorker {
|
||||
let main_module =
|
||||
ModuleSpecifier::resolve_url_or_path("./hello.js").unwrap();
|
||||
let program_state = ProgramState::mock(vec!["deno".to_string()], None);
|
||||
WebWorker::new(
|
||||
let module_loader = Rc::new(deno_core::NoopModuleLoader);
|
||||
let create_web_worker_cb = Arc::new(|_| unreachable!());
|
||||
|
||||
let options = WebWorkerOptions {
|
||||
args: vec![],
|
||||
apply_source_maps: false,
|
||||
debug_flag: false,
|
||||
unstable: false,
|
||||
ca_filepath: None,
|
||||
seed: None,
|
||||
module_loader,
|
||||
create_web_worker_cb,
|
||||
js_error_create_fn: None,
|
||||
use_deno_namespace: false,
|
||||
attach_inspector: false,
|
||||
maybe_inspector_server: None,
|
||||
};
|
||||
|
||||
let mut worker = WebWorker::from_options(
|
||||
"TEST".to_string(),
|
||||
Permissions::allow_all(),
|
||||
main_module,
|
||||
program_state,
|
||||
false,
|
||||
1,
|
||||
)
|
||||
&options,
|
||||
);
|
||||
worker.bootstrap(&options);
|
||||
worker
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
184
cli/worker.rs
184
cli/worker.rs
|
@ -1,18 +1,19 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::fmt_errors::PrettyJsError;
|
||||
use crate::colors;
|
||||
use crate::inspector::DenoInspector;
|
||||
use crate::inspector::InspectorServer;
|
||||
use crate::inspector::InspectorSession;
|
||||
use crate::js;
|
||||
use crate::metrics::Metrics;
|
||||
use crate::module_loader::CliModuleLoader;
|
||||
use crate::ops;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::program_state::ProgramState;
|
||||
use crate::source_maps::apply_source_map;
|
||||
use crate::version;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::future::poll_fn;
|
||||
use deno_core::futures::future::FutureExt;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::JsErrorCreateFn;
|
||||
use deno_core::JsRuntime;
|
||||
|
@ -35,68 +36,51 @@ use std::task::Poll;
|
|||
/// are descendants of this worker.
|
||||
pub struct MainWorker {
|
||||
inspector: Option<Box<DenoInspector>>,
|
||||
js_runtime: JsRuntime,
|
||||
pub js_runtime: JsRuntime,
|
||||
should_break_on_first_statement: bool,
|
||||
}
|
||||
|
||||
pub struct WorkerOptions {
|
||||
pub apply_source_maps: bool,
|
||||
pub args: Vec<String>,
|
||||
pub debug_flag: bool,
|
||||
pub unstable: bool,
|
||||
pub ca_filepath: Option<String>,
|
||||
pub seed: Option<u64>,
|
||||
pub module_loader: Rc<dyn ModuleLoader>,
|
||||
// Callback that will be invoked when creating new instance
|
||||
// of WebWorker
|
||||
pub create_web_worker_cb: Arc<ops::worker_host::CreateWebWorkerCb>,
|
||||
pub js_error_create_fn: Option<Rc<JsErrorCreateFn>>,
|
||||
pub attach_inspector: bool,
|
||||
pub maybe_inspector_server: Option<Arc<InspectorServer>>,
|
||||
pub should_break_on_first_statement: bool,
|
||||
}
|
||||
|
||||
impl MainWorker {
|
||||
pub fn new(
|
||||
program_state: &Arc<ProgramState>,
|
||||
main_module: ModuleSpecifier,
|
||||
permissions: Permissions,
|
||||
) -> Self {
|
||||
let module_loader = CliModuleLoader::new(program_state.clone());
|
||||
|
||||
let global_state_ = program_state.clone();
|
||||
|
||||
let js_error_create_fn = Box::new(move |core_js_error| {
|
||||
let source_mapped_error =
|
||||
apply_source_map(&core_js_error, global_state_.clone());
|
||||
PrettyJsError::create(source_mapped_error)
|
||||
});
|
||||
|
||||
Self::from_options(
|
||||
program_state,
|
||||
main_module,
|
||||
permissions,
|
||||
module_loader,
|
||||
Some(js_error_create_fn),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn from_options(
|
||||
program_state: &Arc<ProgramState>,
|
||||
main_module: ModuleSpecifier,
|
||||
permissions: Permissions,
|
||||
module_loader: Rc<dyn ModuleLoader>,
|
||||
js_error_create_fn: Option<Box<JsErrorCreateFn>>,
|
||||
options: &WorkerOptions,
|
||||
) -> Self {
|
||||
// TODO(bartlomieju): this is hacky way to not apply source
|
||||
// maps in JS
|
||||
let apply_source_maps = js_error_create_fn.is_some();
|
||||
|
||||
let mut js_runtime = JsRuntime::new(RuntimeOptions {
|
||||
module_loader: Some(module_loader),
|
||||
module_loader: Some(options.module_loader.clone()),
|
||||
startup_snapshot: Some(js::deno_isolate_init()),
|
||||
js_error_create_fn,
|
||||
js_error_create_fn: options.js_error_create_fn.clone(),
|
||||
get_error_class_fn: Some(&crate::errors::get_error_class_name),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let inspector =
|
||||
if let Some(inspector_server) = &program_state.maybe_inspector_server {
|
||||
Some(DenoInspector::new(
|
||||
&mut js_runtime,
|
||||
Some(inspector_server.clone()),
|
||||
))
|
||||
} else if program_state.flags.coverage || program_state.flags.repl {
|
||||
Some(DenoInspector::new(&mut js_runtime, None))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let inspector = if options.attach_inspector {
|
||||
Some(DenoInspector::new(
|
||||
&mut js_runtime,
|
||||
options.maybe_inspector_server.clone(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let should_break_on_first_statement =
|
||||
inspector.is_some() && program_state.flags.inspect_brk.is_some();
|
||||
inspector.is_some() && options.should_break_on_first_statement;
|
||||
|
||||
let mut worker = Self {
|
||||
inspector,
|
||||
|
@ -111,15 +95,21 @@ impl MainWorker {
|
|||
let op_state = js_runtime.op_state();
|
||||
let mut op_state = op_state.borrow_mut();
|
||||
op_state.put::<Metrics>(Default::default());
|
||||
op_state.put::<Arc<ProgramState>>(program_state.clone());
|
||||
op_state.put::<Permissions>(permissions);
|
||||
op_state.put::<ops::UnstableChecker>(ops::UnstableChecker {
|
||||
unstable: options.unstable,
|
||||
});
|
||||
}
|
||||
|
||||
ops::runtime::init(js_runtime, main_module, apply_source_maps);
|
||||
ops::fetch::init(js_runtime, program_state.flags.ca_file.as_deref());
|
||||
ops::runtime::init(js_runtime, main_module);
|
||||
ops::fetch::init(js_runtime, options.ca_filepath.as_deref());
|
||||
ops::timers::init(js_runtime);
|
||||
ops::worker_host::init(js_runtime, None);
|
||||
ops::crypto::init(js_runtime, program_state.flags.seed);
|
||||
ops::worker_host::init(
|
||||
js_runtime,
|
||||
None,
|
||||
options.create_web_worker_cb.clone(),
|
||||
);
|
||||
ops::crypto::init(js_runtime, options.seed);
|
||||
ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close);
|
||||
ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources);
|
||||
ops::reg_json_sync(
|
||||
|
@ -127,7 +117,6 @@ impl MainWorker {
|
|||
"op_domain_to_ascii",
|
||||
deno_web::op_domain_to_ascii,
|
||||
);
|
||||
ops::errors::init(js_runtime);
|
||||
ops::fs_events::init(js_runtime);
|
||||
ops::fs::init(js_runtime);
|
||||
ops::io::init(js_runtime);
|
||||
|
@ -136,11 +125,10 @@ impl MainWorker {
|
|||
ops::permissions::init(js_runtime);
|
||||
ops::plugin::init(js_runtime);
|
||||
ops::process::init(js_runtime);
|
||||
ops::runtime_compiler::init(js_runtime);
|
||||
ops::signal::init(js_runtime);
|
||||
ops::tls::init(js_runtime);
|
||||
ops::tty::init(js_runtime);
|
||||
ops::websocket::init(js_runtime);
|
||||
ops::websocket::init(js_runtime, options.ca_filepath.as_deref());
|
||||
}
|
||||
{
|
||||
let op_state = js_runtime.op_state();
|
||||
|
@ -157,10 +145,32 @@ impl MainWorker {
|
|||
t.add("stderr", Box::new(stream));
|
||||
}
|
||||
}
|
||||
|
||||
worker
|
||||
.execute("bootstrap.mainRuntime()")
|
||||
}
|
||||
|
||||
pub fn bootstrap(&mut self, options: &WorkerOptions) {
|
||||
let runtime_options = json!({
|
||||
"args": options.args,
|
||||
"applySourceMaps": options.apply_source_maps,
|
||||
"debugFlag": options.debug_flag,
|
||||
"denoVersion": version::deno(),
|
||||
"noColor": !colors::use_color(),
|
||||
"pid": std::process::id(),
|
||||
"ppid": ops::runtime::ppid(),
|
||||
"target": env!("TARGET"),
|
||||
"tsVersion": version::TYPESCRIPT,
|
||||
"unstableFlag": options.unstable,
|
||||
"v8Version": deno_core::v8_version(),
|
||||
});
|
||||
|
||||
let script = format!(
|
||||
"bootstrap.mainRuntime({})",
|
||||
serde_json::to_string_pretty(&runtime_options).unwrap()
|
||||
);
|
||||
self
|
||||
.execute(&script)
|
||||
.expect("Failed to execute bootstrap script");
|
||||
worker
|
||||
}
|
||||
|
||||
/// Same as execute2() but the filename defaults to "$CWD/__anonymous__".
|
||||
|
@ -231,23 +241,28 @@ impl Drop for MainWorker {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::flags::DenoSubcommand;
|
||||
use crate::flags::Flags;
|
||||
use crate::program_state::ProgramState;
|
||||
|
||||
fn create_test_worker() -> MainWorker {
|
||||
let main_module =
|
||||
ModuleSpecifier::resolve_url_or_path("./hello.js").unwrap();
|
||||
let flags = Flags {
|
||||
subcommand: DenoSubcommand::Run {
|
||||
script: main_module.to_string(),
|
||||
},
|
||||
..Default::default()
|
||||
let permissions = Permissions::default();
|
||||
|
||||
let options = WorkerOptions {
|
||||
apply_source_maps: false,
|
||||
args: vec![],
|
||||
debug_flag: false,
|
||||
unstable: false,
|
||||
ca_filepath: None,
|
||||
seed: None,
|
||||
js_error_create_fn: None,
|
||||
create_web_worker_cb: Arc::new(|_| unreachable!()),
|
||||
attach_inspector: false,
|
||||
maybe_inspector_server: None,
|
||||
should_break_on_first_statement: false,
|
||||
module_loader: Rc::new(deno_core::FsModuleLoader),
|
||||
};
|
||||
let permissions = Permissions::from_flags(&flags);
|
||||
let program_state =
|
||||
ProgramState::mock(vec!["deno".to_string()], Some(flags));
|
||||
MainWorker::new(&program_state, main_module, permissions)
|
||||
|
||||
MainWorker::from_options(main_module, permissions, &options)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -273,26 +288,7 @@ mod tests {
|
|||
let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("tests/circular1.ts");
|
||||
let module_specifier =
|
||||
ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap();
|
||||
let mut worker = create_test_worker();
|
||||
let result = worker.execute_module(&module_specifier).await;
|
||||
if let Err(err) = result {
|
||||
eprintln!("execute_mod err {:?}", err);
|
||||
}
|
||||
if let Err(e) = worker.run_event_loop().await {
|
||||
panic!("Future got unexpected error: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn execute_006_url_imports() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("cli/tests/006_url_imports.ts");
|
||||
.join("tests/circular1.js");
|
||||
let module_specifier =
|
||||
ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap();
|
||||
let mut worker = create_test_worker();
|
||||
|
@ -323,7 +319,7 @@ mod tests {
|
|||
let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("cli/tests/002_hello.ts");
|
||||
.join("cli/tests/001_hello.js");
|
||||
let module_specifier =
|
||||
ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap();
|
||||
let result = worker.execute_module(&module_specifier).await;
|
||||
|
|
|
@ -51,6 +51,7 @@ pub use crate::modules::ModuleLoadId;
|
|||
pub use crate::modules::ModuleLoader;
|
||||
pub use crate::modules::ModuleSource;
|
||||
pub use crate::modules::ModuleSourceFuture;
|
||||
pub use crate::modules::NoopModuleLoader;
|
||||
pub use crate::modules::RecursiveModuleLoad;
|
||||
pub use crate::normalize_path::normalize_path;
|
||||
pub use crate::ops::json_op_async;
|
||||
|
|
|
@ -105,7 +105,7 @@ pub trait ModuleLoader {
|
|||
|
||||
/// Placeholder structure used when creating
|
||||
/// a runtime that doesn't support module loading.
|
||||
pub(crate) struct NoopModuleLoader;
|
||||
pub struct NoopModuleLoader;
|
||||
|
||||
impl ModuleLoader for NoopModuleLoader {
|
||||
fn resolve(
|
||||
|
|
|
@ -107,7 +107,7 @@ pub(crate) struct JsRuntimeState {
|
|||
HashMap<v8::Global<v8::Promise>, v8::Global<v8::Value>>,
|
||||
pending_dyn_mod_evaluate: HashMap<ModuleLoadId, DynImportModEvaluate>,
|
||||
pending_mod_evaluate: Option<ModEvaluate>,
|
||||
pub(crate) js_error_create_fn: Box<JsErrorCreateFn>,
|
||||
pub(crate) js_error_create_fn: Rc<JsErrorCreateFn>,
|
||||
pub(crate) shared: SharedQueue,
|
||||
pub(crate) pending_ops: FuturesUnordered<PendingOpFuture>,
|
||||
pub(crate) pending_unref_ops: FuturesUnordered<PendingOpFuture>,
|
||||
|
@ -168,7 +168,7 @@ pub struct RuntimeOptions {
|
|||
/// Allows a callback to be set whenever a V8 exception is made. This allows
|
||||
/// the caller to wrap the JsError into an error. By default this callback
|
||||
/// is set to `JsError::create()`.
|
||||
pub js_error_create_fn: Option<Box<JsErrorCreateFn>>,
|
||||
pub js_error_create_fn: Option<Rc<JsErrorCreateFn>>,
|
||||
|
||||
/// Allows to map error type to a string "class" used to represent
|
||||
/// error in JavaScript.
|
||||
|
@ -257,7 +257,7 @@ impl JsRuntime {
|
|||
|
||||
let js_error_create_fn = options
|
||||
.js_error_create_fn
|
||||
.unwrap_or_else(|| Box::new(JsError::create));
|
||||
.unwrap_or_else(|| Rc::new(JsError::create));
|
||||
let mut op_state = OpState::default();
|
||||
|
||||
if let Some(get_error_class_fn) = options.get_error_class_fn {
|
||||
|
|
Loading…
Reference in a new issue