summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2020-12-13 19:45:53 +0100
committerGitHub <noreply@github.com>2020-12-13 19:45:53 +0100
commit2e74f164b6dcf0ecbf8dd38fba9fae550d784bd0 (patch)
tree61abe8e09d5331ace5d9de529f0e2737a8e05dbb /cli
parent84ef9bd21fb48fb6b5fbc8dafc3de9f361bade3b (diff)
refactor: deno_runtime crate (#8640)
This commit moves Deno JS runtime, ops, permissions and inspector implementation to new "deno_runtime" crate located in "runtime/" directory. Details in "runtime/README.md". Co-authored-by: Ryan Dahl <ry@tinyclouds.org>
Diffstat (limited to 'cli')
-rw-r--r--cli/Cargo.toml11
-rw-r--r--cli/build.rs17
-rw-r--r--cli/errors.rs195
-rw-r--r--cli/file_fetcher.rs4
-rw-r--r--cli/file_watcher.rs13
-rw-r--r--cli/http_util.rs20
-rw-r--r--cli/inspector.rs952
-rw-r--r--cli/js.rs27
-rw-r--r--cli/main.rs53
-rw-r--r--cli/metrics.rs131
-rw-r--r--cli/module_loader.rs2
-rw-r--r--cli/ops/crypto.rs14
-rw-r--r--cli/ops/dispatch_minimal.rs205
-rw-r--r--cli/ops/fetch.rs22
-rw-r--r--cli/ops/fs.rs1702
-rw-r--r--cli/ops/fs_events.rs133
-rw-r--r--cli/ops/io.rs473
-rw-r--r--cli/ops/mod.rs56
-rw-r--r--cli/ops/net.rs566
-rw-r--r--cli/ops/net_unix.rs151
-rw-r--r--cli/ops/os.rs192
-rw-r--r--cli/ops/permissions.rs103
-rw-r--r--cli/ops/plugin.rs156
-rw-r--r--cli/ops/process.rs236
-rw-r--r--cli/ops/runtime.rs118
-rw-r--r--cli/ops/runtime_compiler.rs8
-rw-r--r--cli/ops/signal.rs142
-rw-r--r--cli/ops/timers.rs193
-rw-r--r--cli/ops/tls.rs431
-rw-r--r--cli/ops/tty.rs334
-rw-r--r--cli/ops/web_worker.rs37
-rw-r--r--cli/ops/websocket.rs326
-rw-r--r--cli/ops/worker_host.rs318
-rw-r--r--cli/permissions.rs1095
-rw-r--r--cli/program_state.rs4
-rw-r--r--cli/resolve_addr.rs72
-rw-r--r--cli/rt/00_bootstrap_namespace.js9
-rw-r--r--cli/rt/01_build.js26
-rw-r--r--cli/rt/01_colors.js92
-rw-r--r--cli/rt/01_errors.js162
-rw-r--r--cli/rt/01_internals.js23
-rw-r--r--cli/rt/01_version.js26
-rw-r--r--cli/rt/01_web_util.js160
-rw-r--r--cli/rt/02_console.js1732
-rw-r--r--cli/rt/06_util.js148
-rw-r--r--cli/rt/10_dispatch_minimal.js114
-rw-r--r--cli/rt/11_timers.js557
-rw-r--r--cli/rt/11_workers.js206
-rw-r--r--cli/rt/12_io.js135
-rw-r--r--cli/rt/13_buffer.js241
-rw-r--r--cli/rt/27_websocket.js316
-rw-r--r--cli/rt/30_files.js209
-rw-r--r--cli/rt/30_fs.js425
-rw-r--r--cli/rt/30_metrics.js13
-rw-r--r--cli/rt/30_net.js245
-rw-r--r--cli/rt/30_os.js66
-rw-r--r--cli/rt/40_compiler_api.js97
-rw-r--r--cli/rt/40_diagnostics.js23
-rw-r--r--cli/rt/40_error_stack.js23
-rw-r--r--cli/rt/40_fs_events.js52
-rw-r--r--cli/rt/40_net_unstable.js48
-rw-r--r--cli/rt/40_performance.js341
-rw-r--r--cli/rt/40_permissions.js65
-rw-r--r--cli/rt/40_plugins.js13
-rw-r--r--cli/rt/40_process.js122
-rw-r--r--cli/rt/40_read_file.js43
-rw-r--r--cli/rt/40_signals.js256
-rw-r--r--cli/rt/40_testing.js350
-rw-r--r--cli/rt/40_tls.js82
-rw-r--r--cli/rt/40_tty.js28
-rw-r--r--cli/rt/40_write_file.js92
-rw-r--r--cli/rt/41_prompt.js80
-rw-r--r--cli/rt/90_deno_ns.js137
-rw-r--r--cli/rt/99_main.js395
-rw-r--r--cli/rt/README.md59
-rw-r--r--cli/signal.rs62
-rw-r--r--cli/specifier_handler.rs2
-rw-r--r--cli/standalone.rs7
-rw-r--r--cli/tools/coverage.rs2
-rw-r--r--cli/tools/repl.rs4
-rw-r--r--cli/tools/upgrade.rs4
-rw-r--r--cli/web_worker.rs588
-rw-r--r--cli/worker.rs342
83 files changed, 75 insertions, 16659 deletions
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 7bc6221dd..7ad0cc5ca 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -20,10 +20,9 @@ harness = false
path = "./bench/main.rs"
[build-dependencies]
-deno_crypto = { path = "../op_crates/crypto", version = "0.4.0" }
deno_core = { path = "../core", version = "0.70.0" }
-deno_web = { path = "../op_crates/web", version = "0.21.0" }
deno_fetch = { path = "../op_crates/fetch", version = "0.13.0" }
+deno_web = { path = "../op_crates/web", version = "0.21.0" }
regex = "1.3.9"
serde = { version = "1.0.116", features = ["derive"] }
@@ -33,11 +32,9 @@ winapi = "0.3.9"
[dependencies]
deno_core = { path = "../core", version = "0.70.0" }
-deno_crypto = { path = "../op_crates/crypto", version = "0.4.0" }
deno_doc = "0.1.18"
-deno_fetch = { path = "../op_crates/fetch", version = "0.13.0" }
deno_lint = "0.2.13"
-deno_web = { path = "../op_crates/web", version = "0.21.0" }
+deno_runtime = { path = "../runtime", version = "0.1.0" }
atty = "0.2.14"
base64 = "0.12.3"
@@ -46,7 +43,6 @@ byteorder = "1.3.4"
clap = "2.33.3"
crossbeam-channel = "0.5.0"
dissimilar = "1.0.2"
-dlopen = "0.1.8"
dprint-plugin-typescript = "0.35.1"
encoding_rs = "0.8.24"
env_logger = "0.7.1"
@@ -72,7 +68,6 @@ sourcemap = "6.0.1"
swc_bundler = "0.17.6"
swc_common = { version = "0.10.7", features = ["sourcemap"] }
swc_ecmascript = { version = "0.15.0", features = ["codegen", "dep_graph", "parser", "react", "transforms", "visit"] }
-sys-info = "0.7.0"
tempfile = "3.1.0"
termcolor = "1.1.0"
tokio = { version = "0.2.22", features = ["full"] }
@@ -82,8 +77,6 @@ tokio-tungstenite = "0.11.0"
uuid = { version = "0.8.1", features = ["v4"] }
walkdir = "2.3.1"
warp = { version = "0.2.5", features = ["tls"] }
-webpki = "0.21.3"
-webpki-roots = "=0.19.0" # Pinned to v0.19.0 to match 'reqwest'.
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.9", features = ["knownfolders", "mswsock", "objbase", "shlobj", "tlhelp32", "winbase", "winerror", "winsock2"] }
diff --git a/cli/build.rs b/cli/build.rs
index b0088a9d8..4be71bb9e 100644
--- a/cli/build.rs
+++ b/cli/build.rs
@@ -13,14 +13,13 @@ use std::env;
use std::path::Path;
use std::path::PathBuf;
+// TODO(bartlomieju): this module contains a lot of duplicated
+// logic with `runtime/build.rs`, factor out to `deno_core`.
fn create_snapshot(
mut js_runtime: JsRuntime,
snapshot_path: &Path,
files: Vec<PathBuf>,
) {
- deno_web::init(&mut js_runtime);
- deno_fetch::init(&mut js_runtime);
- deno_crypto::init(&mut js_runtime);
// TODO(nayeemrmn): https://github.com/rust-lang/cargo/issues/3946 to get the
// workspace root.
let display_root = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap();
@@ -43,14 +42,6 @@ fn create_snapshot(
println!("Snapshot written to: {} ", snapshot_path.display());
}
-fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<PathBuf>) {
- let js_runtime = JsRuntime::new(RuntimeOptions {
- will_snapshot: true,
- ..Default::default()
- });
- create_snapshot(js_runtime, snapshot_path, files);
-}
-
#[derive(Debug, Deserialize)]
struct LoadArgs {
/// The fully qualified specifier that should be loaded.
@@ -265,12 +256,8 @@ fn main() {
let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
// Main snapshot
- let runtime_snapshot_path = o.join("CLI_SNAPSHOT.bin");
let compiler_snapshot_path = o.join("COMPILER_SNAPSHOT.bin");
- let js_files = get_js_files("rt");
- create_runtime_snapshot(&runtime_snapshot_path, js_files);
-
let js_files = get_js_files("tsc");
create_compiler_snapshot(&compiler_snapshot_path, js_files, &c);
diff --git a/cli/errors.rs b/cli/errors.rs
index 869cdee2c..29fd428c8 100644
--- a/cli/errors.rs
+++ b/cli/errors.rs
@@ -12,218 +12,25 @@
use crate::ast::DiagnosticBuffer;
use crate::import_map::ImportMapError;
use deno_core::error::AnyError;
-use deno_core::serde_json;
-use deno_core::url;
-use deno_core::ModuleResolutionError;
-use deno_fetch::reqwest;
-use rustyline::error::ReadlineError;
-use std::env;
-use std::error::Error;
-use std::io;
-
-fn get_dlopen_error_class(error: &dlopen::Error) -> &'static str {
- use dlopen::Error::*;
- match error {
- NullCharacter(_) => "InvalidData",
- OpeningLibraryError(ref e) => get_io_error_class(e),
- SymbolGettingError(ref e) => get_io_error_class(e),
- AddrNotMatchingDll(ref e) => get_io_error_class(e),
- NullSymbol => "NotFound",
- }
-}
-
-fn get_env_var_error_class(error: &env::VarError) -> &'static str {
- use env::VarError::*;
- match error {
- NotPresent => "NotFound",
- NotUnicode(..) => "InvalidData",
- }
-}
fn get_import_map_error_class(_: &ImportMapError) -> &'static str {
"URIError"
}
-fn get_io_error_class(error: &io::Error) -> &'static str {
- use io::ErrorKind::*;
- match error.kind() {
- NotFound => "NotFound",
- PermissionDenied => "PermissionDenied",
- ConnectionRefused => "ConnectionRefused",
- ConnectionReset => "ConnectionReset",
- ConnectionAborted => "ConnectionAborted",
- NotConnected => "NotConnected",
- AddrInUse => "AddrInUse",
- AddrNotAvailable => "AddrNotAvailable",
- BrokenPipe => "BrokenPipe",
- AlreadyExists => "AlreadyExists",
- InvalidInput => "TypeError",
- InvalidData => "InvalidData",
- TimedOut => "TimedOut",
- Interrupted => "Interrupted",
- WriteZero => "WriteZero",
- UnexpectedEof => "UnexpectedEof",
- Other => "Error",
- WouldBlock => unreachable!(),
- // Non-exhaustive enum - might add new variants
- // in the future
- _ => unreachable!(),
- }
-}
-
-fn get_module_resolution_error_class(
- _: &ModuleResolutionError,
-) -> &'static str {
- "URIError"
-}
-
-fn get_notify_error_class(error: &notify::Error) -> &'static str {
- use notify::ErrorKind::*;
- match error.kind {
- Generic(_) => "Error",
- Io(ref e) => get_io_error_class(e),
- PathNotFound => "NotFound",
- WatchNotFound => "NotFound",
- InvalidConfig(_) => "InvalidData",
- }
-}
-
-fn get_readline_error_class(error: &ReadlineError) -> &'static str {
- use ReadlineError::*;
- match error {
- Io(err) => get_io_error_class(err),
- Eof => "UnexpectedEof",
- Interrupted => "Interrupted",
- #[cfg(unix)]
- Errno(err) => get_nix_error_class(err),
- _ => unimplemented!(),
- }
-}
-
-fn get_regex_error_class(error: &regex::Error) -> &'static str {
- use regex::Error::*;
- match error {
- Syntax(_) => "SyntaxError",
- CompiledTooBig(_) => "RangeError",
- _ => "Error",
- }
-}
-
-fn get_request_error_class(error: &reqwest::Error) -> &'static str {
- error
- .source()
- .and_then(|inner_err| {
- (inner_err
- .downcast_ref::<io::Error>()
- .map(get_io_error_class))
- .or_else(|| {
- inner_err
- .downcast_ref::<serde_json::error::Error>()
- .map(get_serde_json_error_class)
- })
- .or_else(|| {
- inner_err
- .downcast_ref::<url::ParseError>()
- .map(get_url_parse_error_class)
- })
- })
- .unwrap_or("Http")
-}
-
-fn get_serde_json_error_class(
- error: &serde_json::error::Error,
-) -> &'static str {
- use deno_core::serde_json::error::*;
- match error.classify() {
- Category::Io => error
- .source()
- .and_then(|e| e.downcast_ref::<io::Error>())
- .map(get_io_error_class)
- .unwrap(),
- Category::Syntax => "SyntaxError",
- Category::Data => "InvalidData",
- Category::Eof => "UnexpectedEof",
- }
-}
-
fn get_diagnostic_class(_: &DiagnosticBuffer) -> &'static str {
"SyntaxError"
}
-fn get_url_parse_error_class(_error: &url::ParseError) -> &'static str {
- "URIError"
-}
-
-#[cfg(unix)]
-fn get_nix_error_class(error: &nix::Error) -> &'static str {
- use nix::errno::Errno::*;
- match error {
- nix::Error::Sys(ECHILD) => "NotFound",
- nix::Error::Sys(EINVAL) => "TypeError",
- nix::Error::Sys(ENOENT) => "NotFound",
- nix::Error::Sys(ENOTTY) => "BadResource",
- nix::Error::Sys(EPERM) => "PermissionDenied",
- nix::Error::Sys(ESRCH) => "NotFound",
- nix::Error::Sys(UnknownErrno) => "Error",
- nix::Error::Sys(_) => "Error",
- nix::Error::InvalidPath => "TypeError",
- nix::Error::InvalidUtf8 => "InvalidData",
- nix::Error::UnsupportedOperation => unreachable!(),
- }
-}
-
pub(crate) fn get_error_class_name(e: &AnyError) -> &'static str {
- deno_core::error::get_custom_error_class(e)
- .or_else(|| {
- e.downcast_ref::<dlopen::Error>()
- .map(get_dlopen_error_class)
- })
- .or_else(|| {
- e.downcast_ref::<env::VarError>()
- .map(get_env_var_error_class)
- })
+ deno_runtime::errors::get_error_class_name(e)
.or_else(|| {
e.downcast_ref::<ImportMapError>()
.map(get_import_map_error_class)
})
- .or_else(|| e.downcast_ref::<io::Error>().map(get_io_error_class))
- .or_else(|| {
- e.downcast_ref::<ModuleResolutionError>()
- .map(get_module_resolution_error_class)
- })
- .or_else(|| {
- e.downcast_ref::<notify::Error>()
- .map(get_notify_error_class)
- })
- .or_else(|| {
- e.downcast_ref::<ReadlineError>()
- .map(get_readline_error_class)
- })
- .or_else(|| {
- e.downcast_ref::<reqwest::Error>()
- .map(get_request_error_class)
- })
- .or_else(|| e.downcast_ref::<regex::Error>().map(get_regex_error_class))
- .or_else(|| {
- e.downcast_ref::<serde_json::error::Error>()
- .map(get_serde_json_error_class)
- })
.or_else(|| {
e.downcast_ref::<DiagnosticBuffer>()
.map(get_diagnostic_class)
})
- .or_else(|| {
- e.downcast_ref::<url::ParseError>()
- .map(get_url_parse_error_class)
- })
- .or_else(|| {
- #[cfg(unix)]
- let maybe_get_nix_error_class =
- || e.downcast_ref::<nix::Error>().map(get_nix_error_class);
- #[cfg(not(unix))]
- let maybe_get_nix_error_class = || Option::<&'static str>::None;
- (maybe_get_nix_error_class)()
- })
.unwrap_or_else(|| {
panic!("Error '{}' contains boxed error of unknown type", e);
})
diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs
index 7b730e455..86c0ac966 100644
--- a/cli/file_fetcher.rs
+++ b/cli/file_fetcher.rs
@@ -7,8 +7,8 @@ use crate::http_util::fetch_once;
use crate::http_util::get_user_agent;
use crate::http_util::FetchOnceResult;
use crate::media_type::MediaType;
-use crate::permissions::Permissions;
use crate::text_encoding;
+use deno_runtime::permissions::Permissions;
use deno_core::error::custom_error;
use deno_core::error::generic_error;
@@ -17,7 +17,7 @@ use deno_core::error::AnyError;
use deno_core::futures;
use deno_core::futures::future::FutureExt;
use deno_core::ModuleSpecifier;
-use deno_fetch::reqwest;
+use deno_runtime::deno_fetch::reqwest;
use std::collections::HashMap;
use std::fs;
use std::future::Future;
diff --git a/cli/file_watcher.rs b/cli/file_watcher.rs
index 4aa93c581..ef7aae603 100644
--- a/cli/file_watcher.rs
+++ b/cli/file_watcher.rs
@@ -240,16 +240,17 @@ fn new_watcher(
) -> Result<RecommendedWatcher, AnyError> {
let event_detected = Arc::clone(&debounce.event_detected);
- let mut watcher: RecommendedWatcher = Watcher::new_immediate(
- move |res: Result<NotifyEvent, NotifyError>| {
+ let mut watcher: RecommendedWatcher =
+ Watcher::new_immediate(move |res: Result<NotifyEvent, NotifyError>| {
if let Ok(event) = res {
- if matches!(event.kind, EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_))
- {
+ if matches!(
+ event.kind,
+ EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_)
+ ) {
event_detected.store(true, Ordering::Relaxed);
}
}
- },
- )?;
+ })?;
watcher.configure(Config::PreciseEvents(true)).unwrap();
diff --git a/cli/http_util.rs b/cli/http_util.rs
index 4bd59e32b..97e3453ec 100644
--- a/cli/http_util.rs
+++ b/cli/http_util.rs
@@ -6,16 +6,16 @@ use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::futures;
use deno_core::url::Url;
-use deno_fetch::reqwest;
-use deno_fetch::reqwest::header::HeaderMap;
-use deno_fetch::reqwest::header::HeaderValue;
-use deno_fetch::reqwest::header::IF_NONE_MATCH;
-use deno_fetch::reqwest::header::LOCATION;
-use deno_fetch::reqwest::header::USER_AGENT;
-use deno_fetch::reqwest::redirect::Policy;
-use deno_fetch::reqwest::Client;
-use deno_fetch::reqwest::Response;
-use deno_fetch::reqwest::StatusCode;
+use deno_runtime::deno_fetch::reqwest;
+use deno_runtime::deno_fetch::reqwest::header::HeaderMap;
+use deno_runtime::deno_fetch::reqwest::header::HeaderValue;
+use deno_runtime::deno_fetch::reqwest::header::IF_NONE_MATCH;
+use deno_runtime::deno_fetch::reqwest::header::LOCATION;
+use deno_runtime::deno_fetch::reqwest::header::USER_AGENT;
+use deno_runtime::deno_fetch::reqwest::redirect::Policy;
+use deno_runtime::deno_fetch::reqwest::Client;
+use deno_runtime::deno_fetch::reqwest::Response;
+use deno_runtime::deno_fetch::reqwest::StatusCode;
use std::cmp::min;
use std::collections::HashMap;
use std::fs::File;
diff --git a/cli/inspector.rs b/cli/inspector.rs
deleted file mode 100644
index 89fd5bf57..000000000
--- a/cli/inspector.rs
+++ /dev/null
@@ -1,952 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-//! The documentation for the inspector API is sparse, but these are helpful:
-//! https://chromedevtools.github.io/devtools-protocol/
-//! https://hyperandroid.com/2020/02/12/v8-inspector-from-an-embedder-standpoint/
-
-use core::convert::Infallible as Never; // Alias for the future `!` type.
-use deno_core::error::generic_error;
-use deno_core::error::AnyError;
-use deno_core::futures::channel::mpsc;
-use deno_core::futures::channel::mpsc::UnboundedReceiver;
-use deno_core::futures::channel::mpsc::UnboundedSender;
-use deno_core::futures::channel::oneshot;
-use deno_core::futures::future::Future;
-use deno_core::futures::pin_mut;
-use deno_core::futures::prelude::*;
-use deno_core::futures::select;
-use deno_core::futures::stream::FuturesUnordered;
-use deno_core::futures::task;
-use deno_core::futures::task::Context;
-use deno_core::futures::task::Poll;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::v8;
-use std::cell::BorrowMutError;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::ffi::c_void;
-use std::mem::replace;
-use std::mem::take;
-use std::mem::MaybeUninit;
-use std::net::SocketAddr;
-use std::ops::Deref;
-use std::ops::DerefMut;
-use std::pin::Pin;
-use std::process;
-use std::ptr;
-use std::ptr::NonNull;
-use std::sync::Arc;
-use std::sync::Mutex;
-use std::thread;
-use uuid::Uuid;
-use warp::filters::ws;
-use warp::Filter;
-
-pub struct InspectorServer {
- pub host: SocketAddr,
- register_inspector_tx: UnboundedSender<InspectorInfo>,
- shutdown_server_tx: Option<oneshot::Sender<()>>,
- thread_handle: Option<thread::JoinHandle<()>>,
-}
-
-impl InspectorServer {
- pub fn new(host: SocketAddr, name: String) -> Self {
- let (register_inspector_tx, register_inspector_rx) =
- mpsc::unbounded::<InspectorInfo>();
-
- let (shutdown_server_tx, shutdown_server_rx) = oneshot::channel();
-
- let thread_handle = thread::spawn(move || {
- crate::tokio_util::run_basic(server(
- host,
- register_inspector_rx,
- shutdown_server_rx,
- name,
- ))
- });
-
- Self {
- host,
- register_inspector_tx,
- shutdown_server_tx: Some(shutdown_server_tx),
- thread_handle: Some(thread_handle),
- }
- }
-
- fn register_inspector(&self, info: InspectorInfo) {
- self.register_inspector_tx.unbounded_send(info).unwrap();
- }
-}
-
-impl Drop for InspectorServer {
- fn drop(&mut self) {
- if let Some(shutdown_server_tx) = self.shutdown_server_tx.take() {
- shutdown_server_tx
- .send(())
- .expect("unable to send shutdown signal");
- }
-
- if let Some(thread_handle) = self.thread_handle.take() {
- thread_handle.join().expect("unable to join thread");
- }
- }
-}
-
-/// Inspector information that is sent from the isolate thread to the server
-/// thread when a new inspector is created.
-struct InspectorInfo {
- host: SocketAddr,
- uuid: Uuid,
- thread_name: Option<String>,
- new_websocket_tx: UnboundedSender<WebSocketProxy>,
- canary_rx: oneshot::Receiver<Never>,
-}
-
-impl InspectorInfo {
- fn get_json_metadata(&self) -> Value {
- json!({
- "description": "deno",
- "devtoolsFrontendUrl": self.get_frontend_url(),
- "faviconUrl": "https://deno.land/favicon.ico",
- "id": self.uuid.to_string(),
- "title": self.get_title(),
- "type": "deno",
- // TODO(ry): "url": "file://",
- "webSocketDebuggerUrl": self.get_websocket_debugger_url(),
- })
- }
-
- fn get_websocket_debugger_url(&self) -> String {
- format!("ws://{}/ws/{}", &self.host, &self.uuid)
- }
-
- fn get_frontend_url(&self) -> String {
- format!(
- "devtools://devtools/bundled/inspector.html?v8only=true&ws={}/ws/{}",
- &self.host, &self.uuid
- )
- }
-
- fn get_title(&self) -> String {
- format!(
- "[{}] deno{}",
- process::id(),
- self
- .thread_name
- .as_ref()
- .map(|n| format!(" - {}", n))
- .unwrap_or_default()
- )
- }
-}
-
-async fn server(
- host: SocketAddr,
- register_inspector_rx: UnboundedReceiver<InspectorInfo>,
- shutdown_server_rx: oneshot::Receiver<()>,
- name: String,
-) {
- // TODO: put the `inspector_map` in an `Rc<RefCell<_>>` instead. This is
- // currently not possible because warp requires all filters to implement
- // `Send`, which should not be necessary because we are using the
- // single-threaded Tokio runtime.
- let inspector_map = HashMap::<Uuid, InspectorInfo>::new();
- let inspector_map = Arc::new(Mutex::new(inspector_map));
-
- let inspector_map_ = inspector_map.clone();
- let register_inspector_handler = register_inspector_rx
- .map(|info| {
- eprintln!(
- "Debugger listening on {}",
- info.get_websocket_debugger_url()
- );
- let mut g = inspector_map_.lock().unwrap();
- if g.insert(info.uuid, info).is_some() {
- panic!("Inspector UUID already in map");
- }
- })
- .collect::<()>();
-
- let inspector_map_ = inspector_map_.clone();
- let deregister_inspector_handler = future::poll_fn(|cx| {
- let mut g = inspector_map_.lock().unwrap();
- g.retain(|_, info| info.canary_rx.poll_unpin(cx) == Poll::Pending);
- Poll::<Never>::Pending
- })
- .fuse();
-
- let inspector_map_ = inspector_map.clone();
- let websocket_route = warp::path("ws")
- .and(warp::path::param())
- .and(warp::ws())
- .and_then(move |uuid: String, ws: warp::ws::Ws| {
- future::ready(
- Uuid::parse_str(&uuid)
- .ok()
- .and_then(|uuid| {
- let g = inspector_map_.lock().unwrap();
- g.get(&uuid).map(|info| info.new_websocket_tx.clone()).map(
- |new_websocket_tx| {
- ws.on_upgrade(move |websocket| async move {
- let (proxy, pump) = create_websocket_proxy(websocket);
- let _ = new_websocket_tx.unbounded_send(proxy);
- pump.await;
- })
- },
- )
- })
- .ok_or_else(warp::reject::not_found),
- )
- });
-
- let json_version_response = json!({
- "Browser": name,
- "Protocol-Version": "1.3",
- "V8-Version": deno_core::v8_version(),
- });
- let json_version_route = warp::path!("json" / "version")
- .map(move || warp::reply::json(&json_version_response));
-
- let inspector_map_ = inspector_map.clone();
- let json_list_route = warp::path("json").map(move || {
- let g = inspector_map_.lock().unwrap();
- let json_values = g
- .values()
- .map(|info| info.get_json_metadata())
- .collect::<Vec<_>>();
- warp::reply::json(&json!(json_values))
- });
-
- let server_routes =
- websocket_route.or(json_version_route).or(json_list_route);
- let server_handler = warp::serve(server_routes)
- .try_bind_with_graceful_shutdown(host, async {
- shutdown_server_rx.await.ok();
- })
- .map(|(_, fut)| fut)
- .unwrap_or_else(|err| {
- eprintln!("Cannot start inspector server: {}.", err);
- process::exit(1);
- })
- .fuse();
-
- pin_mut!(register_inspector_handler);
- pin_mut!(deregister_inspector_handler);
- pin_mut!(server_handler);
-
- select! {
- _ = register_inspector_handler => {},
- _ = deregister_inspector_handler => unreachable!(),
- _ = server_handler => {},
- }
-}
-
-type WebSocketProxySender = UnboundedSender<ws::Message>;
-type WebSocketProxyReceiver =
- UnboundedReceiver<Result<ws::Message, warp::Error>>;
-
-/// Encapsulates an UnboundedSender/UnboundedReceiver pair that together form
-/// a duplex channel for sending/receiving websocket messages.
-struct WebSocketProxy {
- tx: WebSocketProxySender,
- rx: WebSocketProxyReceiver,
-}
-
-impl WebSocketProxy {
- pub fn split(self) -> (WebSocketProxySender, WebSocketProxyReceiver) {
- (self.tx, self.rx)
- }
-}
-
-/// Creates a future that proxies messages sent and received on a warp WebSocket
-/// to a UnboundedSender/UnboundedReceiver pair. We need this to sidestep
-/// Tokio's task budget, which causes issues when DenoInspector::poll_sessions()
-/// needs to block the thread because JavaScript execution is paused.
-///
-/// This works because UnboundedSender/UnboundedReceiver are implemented in the
-/// 'futures' crate, therefore they can't participate in Tokio's cooperative
-/// task yielding.
-///
-/// A tuple is returned, where the first element is a duplex channel that can
-/// be used to send/receive messages on the websocket, and the second element
-/// is a future that does the forwarding.
-fn create_websocket_proxy(
- websocket: ws::WebSocket,
-) -> (WebSocketProxy, impl Future<Output = ()> + Send) {
- // The 'outbound' channel carries messages sent to the websocket.
- let (outbound_tx, outbound_rx) = mpsc::unbounded();
-
- // The 'inbound' channel carries messages received from the websocket.
- let (inbound_tx, inbound_rx) = mpsc::unbounded();
-
- let proxy = WebSocketProxy {
- tx: outbound_tx,
- rx: inbound_rx,
- };
-
- // The pump future takes care of forwarding messages between the websocket
- // and channels. It resolves to () when either side disconnects, ignoring any
- // errors.
- let pump = async move {
- let (websocket_tx, websocket_rx) = websocket.split();
-
- let outbound_pump =
- outbound_rx.map(Ok).forward(websocket_tx).map_err(|_| ());
-
- let inbound_pump = websocket_rx
- .map(|msg| inbound_tx.unbounded_send(msg))
- .map_err(|_| ())
- .try_collect::<()>();
-
- let _ = future::try_join(outbound_pump, inbound_pump).await;
- };
-
- (proxy, pump)
-}
-
-#[derive(Clone, Copy)]
-enum PollState {
- Idle,
- Woken,
- Polling,
- Parked,
- Dropped,
-}
-
-pub struct DenoInspector {
- v8_inspector_client: v8::inspector::V8InspectorClientBase,
- v8_inspector: v8::UniqueRef<v8::inspector::V8Inspector>,
- sessions: RefCell<InspectorSessions>,
- flags: RefCell<InspectorFlags>,
- waker: Arc<InspectorWaker>,
- _canary_tx: oneshot::Sender<Never>,
- pub server: Option<Arc<InspectorServer>>,
- pub debugger_url: Option<String>,
-}
-
-impl Deref for DenoInspector {
- type Target = v8::inspector::V8Inspector;
- fn deref(&self) -> &Self::Target {
- &self.v8_inspector
- }
-}
-
-impl DerefMut for DenoInspector {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.v8_inspector
- }
-}
-
-impl Drop for DenoInspector {
- fn drop(&mut self) {
- // Since the waker is cloneable, it might outlive the inspector itself.
- // Set the poll state to 'dropped' so it doesn't attempt to request an
- // interrupt from the isolate.
- self.waker.update(|w| w.poll_state = PollState::Dropped);
- // V8 automatically deletes all sessions when an Inspector instance is
- // deleted, however InspectorSession also has a drop handler that cleans
- // up after itself. To avoid a double free, make sure the inspector is
- // dropped last.
- take(&mut *self.sessions.borrow_mut());
- }
-}
-
-impl v8::inspector::V8InspectorClientImpl for DenoInspector {
- fn base(&self) -> &v8::inspector::V8InspectorClientBase {
- &self.v8_inspector_client
- }
-
- fn base_mut(&mut self) -> &mut v8::inspector::V8InspectorClientBase {
- &mut self.v8_inspector_client
- }
-
- fn run_message_loop_on_pause(&mut self, context_group_id: i32) {
- assert_eq!(context_group_id, DenoInspectorSession::CONTEXT_GROUP_ID);
- self.flags.borrow_mut().on_pause = true;
- let _ = self.poll_sessions(None);
- }
-
- fn quit_message_loop_on_pause(&mut self) {
- self.flags.borrow_mut().on_pause = false;
- }
-
- fn run_if_waiting_for_debugger(&mut self, context_group_id: i32) {
- assert_eq!(context_group_id, DenoInspectorSession::CONTEXT_GROUP_ID);
- self.flags.borrow_mut().session_handshake_done = true;
- }
-}
-
-/// DenoInspector implements a Future so that it can poll for new incoming
-/// connections and messages from the WebSocket server. The Worker that owns
-/// this DenoInspector will call our poll function from Worker::poll().
-impl Future for DenoInspector {
- type Output = ();
- fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
- self.poll_sessions(Some(cx)).unwrap()
- }
-}
-
-impl DenoInspector {
- const CONTEXT_GROUP_ID: i32 = 1;
-
- pub fn new(
- js_runtime: &mut deno_core::JsRuntime,
- server: Option<Arc<InspectorServer>>,
- ) -> Box<Self> {
- let context = js_runtime.global_context();
- let scope = &mut v8::HandleScope::new(js_runtime.v8_isolate());
-
- let (new_websocket_tx, new_websocket_rx) =
- mpsc::unbounded::<WebSocketProxy>();
- let (canary_tx, canary_rx) = oneshot::channel::<Never>();
-
- // Create DenoInspector instance.
- let mut self_ = new_box_with(|self_ptr| {
- let v8_inspector_client =
- v8::inspector::V8InspectorClientBase::new::<Self>();
- let v8_inspector =
- v8::inspector::V8Inspector::create(scope, unsafe { &mut *self_ptr });
-
- let sessions = InspectorSessions::new(self_ptr, new_websocket_rx);
- let flags = InspectorFlags::new();
- let waker = InspectorWaker::new(scope.thread_safe_handle());
-
- let debugger_url = if let Some(server) = server.clone() {
- let info = InspectorInfo {
- host: server.host,
- uuid: Uuid::new_v4(),
- thread_name: thread::current().name().map(|n| n.to_owned()),
- new_websocket_tx,
- canary_rx,
- };
-
- let debugger_url = info.get_websocket_debugger_url();
- server.register_inspector(info);
- Some(debugger_url)
- } else {
- None
- };
-
- Self {
- v8_inspector_client,
- v8_inspector,
- sessions,
- flags,
- waker,
- _canary_tx: canary_tx,
- server,
- debugger_url,
- }
- });
-
- // Tell the inspector about the global context.
- let context = v8::Local::new(scope, context);
- let context_name = v8::inspector::StringView::from(&b"global context"[..]);
- self_.context_created(context, Self::CONTEXT_GROUP_ID, context_name);
-
- // Poll the session handler so we will get notified whenever there is
- // new_incoming debugger activity.
- let _ = self_.poll_sessions(None).unwrap();
-
- self_
- }
-
- fn poll_sessions(
- &self,
- mut invoker_cx: Option<&mut Context>,
- ) -> Result<Poll<()>, BorrowMutError> {
- // Short-circuit if there is no server
- if self.server.is_none() {
- return Ok(Poll::Ready(()));
- }
-
- // The futures this function uses do not have re-entrant poll() functions.
- // However it is can happpen that poll_sessions() gets re-entered, e.g.
- // when an interrupt request is honored while the inspector future is polled
- // by the task executor. We let the caller know by returning some error.
- let mut sessions = self.sessions.try_borrow_mut()?;
-
- self.waker.update(|w| {
- match w.poll_state {
- PollState::Idle | PollState::Woken => w.poll_state = PollState::Polling,
- _ => unreachable!(),
- };
- });
-
- // Create a new Context object that will make downstream futures
- // use the InspectorWaker when they are ready to be polled again.
- let waker_ref = task::waker_ref(&self.waker);
- let cx = &mut Context::from_waker(&waker_ref);
-
- loop {
- loop {
- // Do one "handshake" with a newly connected session at a time.
- if let Some(session) = &mut sessions.handshake {
- let poll_result = session.poll_unpin(cx);
- let handshake_done =
- replace(&mut self.flags.borrow_mut().session_handshake_done, false);
- match poll_result {
- Poll::Pending if handshake_done => {
- let session = sessions.handshake.take().unwrap();
- sessions.established.push(session);
- take(&mut self.flags.borrow_mut().waiting_for_session);
- }
- Poll::Ready(_) => sessions.handshake = None,
- Poll::Pending => break,
- };
- }
-
- // Accept new connections.
- match sessions.new_incoming.poll_next_unpin(cx) {
- Poll::Ready(Some(session)) => {
- let prev = sessions.handshake.replace(session);
- assert!(prev.is_none());
- continue;
- }
- Poll::Ready(None) => {}
- Poll::Pending => {}
- }
-
- // Poll established sessions.
- match sessions.established.poll_next_unpin(cx) {
- Poll::Ready(Some(_)) => continue,
- Poll::Ready(None) => break,
- Poll::Pending => break,
- };
- }
-
- let should_block = sessions.handshake.is_some()
- || self.flags.borrow().on_pause
- || self.flags.borrow().waiting_for_session;
-
- let new_state = self.waker.update(|w| {
- match w.poll_state {
- PollState::Woken => {
- // The inspector was woken while the session handler was being
- // polled, so we poll it another time.
- w.poll_state = PollState::Polling;
- }
- PollState::Polling if !should_block => {
- // The session handler doesn't need to be polled any longer, and
- // there's no reason to block (execution is not paused), so this
- // function is about to return.
- w.poll_state = PollState::Idle;
- // Register the task waker that can be used to wake the parent
- // task that will poll the inspector future.
- if let Some(cx) = invoker_cx.take() {
- w.task_waker.replace(cx.waker().clone());
- }
- // Register the address of the inspector, which allows the waker
- // to request an interrupt from the isolate.
- w.inspector_ptr = NonNull::new(self as *const _ as *mut Self);
- }
- PollState::Polling if should_block => {
- // Isolate execution has been paused but there are no more
- // events to process, so this thread will be parked. Therefore,
- // store the current thread handle in the waker so it knows
- // which thread to unpark when new events arrive.
- w.poll_state = PollState::Parked;
- w.parked_thread.replace(thread::current());
- }
- _ => unreachable!(),
- };
- w.poll_state
- });
- match new_state {
- PollState::Idle => break Ok(Poll::Pending), // Yield to task.
- PollState::Polling => {} // Poll the session handler again.
- PollState::Parked => thread::park(), // Park the thread.
- _ => unreachable!(),
- };
- }
- }
-
- /// This function blocks the thread until at least one inspector client has
- /// established a websocket connection and successfully completed the
- /// handshake. After that, it instructs V8 to pause at the next statement.
- pub fn wait_for_session_and_break_on_next_statement(&mut self) {
- loop {
- match self.sessions.get_mut().established.iter_mut().next() {
- Some(session) => break session.break_on_next_statement(),
- None => {
- self.flags.get_mut().waiting_for_session = true;
- let _ = self.poll_sessions(None).unwrap();
- }
- };
- }
- }
-}
-
-#[derive(Default)]
-struct InspectorFlags {
- waiting_for_session: bool,
- session_handshake_done: bool,
- on_pause: bool,
-}
-
-impl InspectorFlags {
- fn new() -> RefCell<Self> {
- let self_ = Self::default();
- RefCell::new(self_)
- }
-}
-
-struct InspectorSessions {
- new_incoming:
- Pin<Box<dyn Stream<Item = Box<DenoInspectorSession>> + 'static>>,
- handshake: Option<Box<DenoInspectorSession>>,
- established: FuturesUnordered<Box<DenoInspectorSession>>,
-}
-
-impl InspectorSessions {
- fn new(
- inspector_ptr: *mut DenoInspector,
- new_websocket_rx: UnboundedReceiver<WebSocketProxy>,
- ) -> RefCell<Self> {
- let new_incoming = new_websocket_rx
- .map(move |websocket| DenoInspectorSession::new(inspector_ptr, websocket))
- .boxed_local();
- let self_ = Self {
- new_incoming,
- ..Default::default()
- };
- RefCell::new(self_)
- }
-}
-
-impl Default for InspectorSessions {
- fn default() -> Self {
- Self {
- new_incoming: stream::empty().boxed_local(),
- handshake: None,
- established: FuturesUnordered::new(),
- }
- }
-}
-
-struct InspectorWakerInner {
- poll_state: PollState,
- task_waker: Option<task::Waker>,
- parked_thread: Option<thread::Thread>,
- inspector_ptr: Option<NonNull<DenoInspector>>,
- isolate_handle: v8::IsolateHandle,
-}
-
-unsafe impl Send for InspectorWakerInner {}
-
-struct InspectorWaker(Mutex<InspectorWakerInner>);
-
-impl InspectorWaker {
- fn new(isolate_handle: v8::IsolateHandle) -> Arc<Self> {
- let inner = InspectorWakerInner {
- poll_state: PollState::Idle,
- task_waker: None,
- parked_thread: None,
- inspector_ptr: None,
- isolate_handle,
- };
- Arc::new(Self(Mutex::new(inner)))
- }
-
- fn update<F, R>(&self, update_fn: F) -> R
- where
- F: FnOnce(&mut InspectorWakerInner) -> R,
- {
- let mut g = self.0.lock().unwrap();
- update_fn(&mut g)
- }
-}
-
-impl task::ArcWake for InspectorWaker {
- fn wake_by_ref(arc_self: &Arc<Self>) {
- arc_self.update(|w| {
- match w.poll_state {
- PollState::Idle => {
- // Wake the task, if any, that has polled the Inspector future last.
- if let Some(waker) = w.task_waker.take() {
- waker.wake()
- }
- // Request an interrupt from the isolate if it's running and there's
- // not unhandled interrupt request in flight.
- if let Some(arg) = w
- .inspector_ptr
- .take()
- .map(|ptr| ptr.as_ptr() as *mut c_void)
- {
- w.isolate_handle.request_interrupt(handle_interrupt, arg);
- }
- extern "C" fn handle_interrupt(
- _isolate: &mut v8::Isolate,
- arg: *mut c_void,
- ) {
- let inspector = unsafe { &*(arg as *mut DenoInspector) };
- let _ = inspector.poll_sessions(None);
- }
- }
- PollState::Parked => {
- // Unpark the isolate thread.
- let parked_thread = w.parked_thread.take().unwrap();
- assert_ne!(parked_thread.id(), thread::current().id());
- parked_thread.unpark();
- }
- _ => {}
- };
- w.poll_state = PollState::Woken;
- });
- }
-}
-
-struct DenoInspectorSession {
- v8_channel: v8::inspector::ChannelBase,
- v8_session: v8::UniqueRef<v8::inspector::V8InspectorSession>,
- websocket_tx: WebSocketProxySender,
- websocket_rx_handler: Pin<Box<dyn Future<Output = ()> + 'static>>,
-}
-
-impl Deref for DenoInspectorSession {
- type Target = v8::inspector::V8InspectorSession;
- fn deref(&self) -> &Self::Target {
- &self.v8_session
- }
-}
-
-impl DerefMut for DenoInspectorSession {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.v8_session
- }
-}
-
-impl DenoInspectorSession {
- const CONTEXT_GROUP_ID: i32 = 1;
-
- pub fn new(
- inspector_ptr: *mut DenoInspector,
- websocket: WebSocketProxy,
- ) -> Box<Self> {
- new_box_with(move |self_ptr| {
- let v8_channel = v8::inspector::ChannelBase::new::<Self>();
- let v8_session = unsafe { &mut *inspector_ptr }.connect(
- Self::CONTEXT_GROUP_ID,
- // Todo(piscisaureus): V8Inspector::connect() should require that
- // the 'v8_channel' argument cannot move.
- unsafe { &mut *self_ptr },
- v8::inspector::StringView::empty(),
- );
-
- let (websocket_tx, websocket_rx) = websocket.split();
- let websocket_rx_handler =
- Self::receive_from_websocket(self_ptr, websocket_rx);
-
- Self {
- v8_channel,
- v8_session,
- websocket_tx,
- websocket_rx_handler,
- }
- })
- }
-
- /// Returns a future that receives messages from the websocket and dispatches
- /// them to the V8 session.
- fn receive_from_websocket(
- self_ptr: *mut Self,
- websocket_rx: WebSocketProxyReceiver,
- ) -> Pin<Box<dyn Future<Output = ()> + 'static>> {
- async move {
- eprintln!("Debugger session started.");
-
- let result = websocket_rx
- .map_ok(move |msg| {
- let msg = msg.as_bytes();
- let msg = v8::inspector::StringView::from(msg);
- unsafe { &mut *self_ptr }.dispatch_protocol_message(msg);
- })
- .try_collect::<()>()
- .await;
-
- match result {
- Ok(_) => eprintln!("Debugger session ended."),
- Err(err) => eprintln!("Debugger session ended: {}.", err),
- };
- }
- .boxed_local()
- }
-
- fn send_to_websocket(&self, msg: v8::UniquePtr<v8::inspector::StringBuffer>) {
- let msg = msg.unwrap().string().to_string();
- let msg = ws::Message::text(msg);
- let _ = self.websocket_tx.unbounded_send(msg);
- }
-
- pub fn break_on_next_statement(&mut self) {
- let reason = v8::inspector::StringView::from(&b"debugCommand"[..]);
- let detail = v8::inspector::StringView::empty();
- self.schedule_pause_on_next_statement(reason, detail);
- }
-}
-
-impl v8::inspector::ChannelImpl for DenoInspectorSession {
- fn base(&self) -> &v8::inspector::ChannelBase {
- &self.v8_channel
- }
-
- fn base_mut(&mut self) -> &mut v8::inspector::ChannelBase {
- &mut self.v8_channel
- }
-
- fn send_response(
- &mut self,
- _call_id: i32,
- message: v8::UniquePtr<v8::inspector::StringBuffer>,
- ) {
- self.send_to_websocket(message);
- }
-
- fn send_notification(
- &mut self,
- message: v8::UniquePtr<v8::inspector::StringBuffer>,
- ) {
- self.send_to_websocket(message);
- }
-
- fn flush_protocol_notifications(&mut self) {}
-}
-
-impl Future for DenoInspectorSession {
- type Output = ();
- fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
- self.websocket_rx_handler.poll_unpin(cx)
- }
-}
-
-/// A local inspector session that can be used to send and receive protocol messages directly on
-/// the same thread as an isolate.
-pub struct InspectorSession {
- v8_channel: v8::inspector::ChannelBase,
- v8_session: v8::UniqueRef<v8::inspector::V8InspectorSession>,
- response_tx_map: HashMap<i32, oneshot::Sender<serde_json::Value>>,
- next_message_id: i32,
- notification_queue: Vec<Value>,
-}
-
-impl Deref for InspectorSession {
- type Target = v8::inspector::V8InspectorSession;
- fn deref(&self) -> &Self::Target {
- &self.v8_session
- }
-}
-
-impl DerefMut for InspectorSession {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.v8_session
- }
-}
-
-impl v8::inspector::ChannelImpl for InspectorSession {
- fn base(&self) -> &v8::inspector::ChannelBase {
- &self.v8_channel
- }
-
- fn base_mut(&mut self) -> &mut v8::inspector::ChannelBase {
- &mut self.v8_channel
- }
-
- fn send_response(
- &mut self,
- call_id: i32,
- message: v8::UniquePtr<v8::inspector::StringBuffer>,
- ) {
- let raw_message = message.unwrap().string().to_string();
- let message = serde_json::from_str(&raw_message).unwrap();
-
- self
- .response_tx_map
- .remove(&call_id)
- .unwrap()
- .send(message)
- .unwrap();
- }
-
- fn send_notification(
- &mut self,
- message: v8::UniquePtr<v8::inspector::StringBuffer>,
- ) {
- let raw_message = message.unwrap().string().to_string();
- let message = serde_json::from_str(&raw_message).unwrap();
-
- self.notification_queue.push(message);
- }
-
- fn flush_protocol_notifications(&mut self) {}
-}
-
-impl InspectorSession {
- const CONTEXT_GROUP_ID: i32 = 1;
-
- pub fn new(inspector_ptr: *mut DenoInspector) -> Box<Self> {
- new_box_with(move |self_ptr| {
- let v8_channel = v8::inspector::ChannelBase::new::<Self>();
- let v8_session = unsafe { &mut *inspector_ptr }.connect(
- Self::CONTEXT_GROUP_ID,
- unsafe { &mut *self_ptr },
- v8::inspector::StringView::empty(),
- );
-
- let response_tx_map = HashMap::new();
- let next_message_id = 0;
-
- let notification_queue = Vec::new();
-
- Self {
- v8_channel,
- v8_session,
- response_tx_map,
- next_message_id,
- notification_queue,
- }
- })
- }
-
- pub fn notifications(&mut self) -> Vec<Value> {
- self.notification_queue.split_off(0)
- }
-
- pub async fn post_message(
- &mut self,
- method: &str,
- params: Option<serde_json::Value>,
- ) -> Result<serde_json::Value, AnyError> {
- let id = self.next_message_id;
- self.next_message_id += 1;
-
- let (response_tx, response_rx) = oneshot::channel::<serde_json::Value>();
- self.response_tx_map.insert(id, response_tx);
-
- let message = json!({
- "id": id,
- "method": method,
- "params": params,
- });
-
- let raw_message = serde_json::to_string(&message).unwrap();
- let raw_message = v8::inspector::StringView::from(raw_message.as_bytes());
- self.v8_session.dispatch_protocol_message(raw_message);
-
- let response = response_rx.await.unwrap();
- if let Some(error) = response.get("error") {
- return Err(generic_error(error.to_string()));
- }
-
- let result = response.get("result").unwrap().clone();
- Ok(result)
- }
-}
-
-fn new_box_with<T>(new_fn: impl FnOnce(*mut T) -> T) -> Box<T> {
- let b = Box::new(MaybeUninit::<T>::uninit());
- let p = Box::into_raw(b) as *mut T;
- unsafe { ptr::write(p, new_fn(p)) };
- unsafe { Box::from_raw(p) }
-}
diff --git a/cli/js.rs b/cli/js.rs
index 3d2a17f36..7cfa961a1 100644
--- a/cli/js.rs
+++ b/cli/js.rs
@@ -4,8 +4,6 @@ use deno_core::Snapshot;
pub const TS_VERSION: &str = env!("TS_VERSION");
-pub static CLI_SNAPSHOT: &[u8] =
- include_bytes!(concat!(env!("OUT_DIR"), "/CLI_SNAPSHOT.bin"));
pub static COMPILER_SNAPSHOT: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/COMPILER_SNAPSHOT.bin"));
pub static DENO_NS_LIB: &str = include_str!("dts/lib.deno.ns.d.ts");
@@ -16,12 +14,6 @@ pub static SHARED_GLOBALS_LIB: &str =
pub static WINDOW_LIB: &str = include_str!("dts/lib.deno.window.d.ts");
pub static UNSTABLE_NS_LIB: &str = include_str!("dts/lib.deno.unstable.d.ts");
-pub fn deno_isolate_init() -> Snapshot {
- debug!("Deno isolate init with snapshots.");
- let data = CLI_SNAPSHOT;
- Snapshot::Static(data)
-}
-
pub fn compiler_isolate_init() -> Snapshot {
debug!("Deno compiler isolate init with snapshots.");
let data = COMPILER_SNAPSHOT;
@@ -29,25 +21,6 @@ pub fn compiler_isolate_init() -> Snapshot {
}
#[test]
-fn cli_snapshot() {
- let mut js_runtime = deno_core::JsRuntime::new(deno_core::RuntimeOptions {
- startup_snapshot: Some(deno_isolate_init()),
- ..Default::default()
- });
- js_runtime
- .execute(
- "<anon>",
- r#"
- if (!(bootstrap.mainRuntime && bootstrap.workerRuntime)) {
- throw Error("bad");
- }
- console.log("we have console.log!!!");
- "#,
- )
- .unwrap();
-}
-
-#[test]
fn compiler_snapshot() {
let mut js_runtime = deno_core::JsRuntime::new(deno_core::RuntimeOptions {
startup_snapshot: Some(compiler_isolate_init()),
diff --git a/cli/main.rs b/cli/main.rs
index 38deec5bb..b6b6b295b 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -25,19 +25,14 @@ mod http_cache;
mod http_util;
mod import_map;
mod info;
-mod inspector;
mod js;
mod lockfile;
mod lsp;
mod media_type;
-mod metrics;
mod module_graph;
mod module_loader;
mod ops;
-mod permissions;
mod program_state;
-mod resolve_addr;
-mod signal;
mod source_maps;
mod specifier_handler;
mod standalone;
@@ -47,8 +42,6 @@ mod tools;
mod tsc;
mod tsc_config;
mod version;
-mod web_worker;
-mod worker;
use crate::file_fetcher::File;
use crate::file_fetcher::FileFetcher;
@@ -59,18 +52,12 @@ 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;
@@ -81,6 +68,13 @@ use deno_core::v8_set_flags;
use deno_core::ModuleSpecifier;
use deno_doc as doc;
use deno_doc::parser::DocFileLoader;
+use deno_runtime::ops::worker_host::CreateWebWorkerCb;
+use deno_runtime::permissions::Permissions;
+use deno_runtime::permissions::PermissionsOptions;
+use deno_runtime::web_worker::WebWorker;
+use deno_runtime::web_worker::WebWorkerOptions;
+use deno_runtime::worker::MainWorker;
+use deno_runtime::worker::WorkerOptions;
use log::Level;
use log::LevelFilter;
use std::cell::RefCell;
@@ -93,6 +87,23 @@ use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
+impl From<Flags> for PermissionsOptions {
+ fn from(flags: Flags) -> Self {
+ Self {
+ allow_env: flags.allow_env,
+ allow_hrtime: flags.allow_hrtime,
+ allow_net: flags.allow_net,
+ allow_plugin: flags.allow_plugin,
+ allow_read: flags.allow_read,
+ allow_run: flags.allow_run,
+ allow_write: flags.allow_write,
+ net_allowlist: flags.net_allowlist,
+ read_allowlist: flags.read_allowlist,
+ write_allowlist: flags.write_allowlist,
+ }
+ }
+}
+
fn create_web_worker_callback(
program_state: Arc<ProgramState>,
) -> Arc<CreateWebWorkerCb> {
@@ -132,6 +143,7 @@ fn create_web_worker_callback(
runtime_version: version::deno(),
ts_version: version::TYPESCRIPT.to_string(),
no_color: !colors::use_color(),
+ get_error_class_fn: Some(&crate::errors::get_error_class_name),
};
let mut worker = WebWorker::from_options(
@@ -207,6 +219,7 @@ pub fn create_main_worker(
runtime_version: version::deno(),
ts_version: version::TYPESCRIPT.to_string(),
no_color: !colors::use_color(),
+ get_error_class_fn: Some(&crate::errors::get_error_class_name),
};
let mut worker = MainWorker::from_options(main_module, permissions, &options);
@@ -392,7 +405,7 @@ async fn install_command(
let mut preload_flags = flags.clone();
preload_flags.inspect = None;
preload_flags.inspect_brk = None;
- let permissions = Permissions::from_flags(&preload_flags);
+ let permissions = Permissions::from_options(&preload_flags.clone().into());
let program_state = ProgramState::new(preload_flags)?;
let main_module = ModuleSpecifier::resolve_url_or_path(&module_url)?;
let mut worker =
@@ -461,7 +474,7 @@ async fn eval_command(
// Force TypeScript compile.
let main_module =
ModuleSpecifier::resolve_url_or_path("./$deno$eval.ts").unwrap();
- let permissions = Permissions::from_flags(&flags);
+ let permissions = Permissions::from_options(&flags.clone().into());
let program_state = ProgramState::new(flags)?;
let mut worker =
create_main_worker(&program_state, main_module.clone(), permissions);
@@ -804,7 +817,7 @@ async fn format_command(
async fn run_repl(flags: Flags) -> Result<(), AnyError> {
let main_module =
ModuleSpecifier::resolve_url_or_path("./$deno$repl.ts").unwrap();
- let permissions = Permissions::from_flags(&flags);
+ let permissions = Permissions::from_options(&flags.clone().into());
let program_state = ProgramState::new(flags)?;
let mut worker =
create_main_worker(&program_state, main_module.clone(), permissions);
@@ -815,7 +828,7 @@ async fn run_repl(flags: Flags) -> Result<(), AnyError> {
async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> {
let program_state = ProgramState::new(flags.clone())?;
- let permissions = Permissions::from_flags(&flags);
+ let permissions = Permissions::from_options(&flags.clone().into());
let main_module =
ModuleSpecifier::resolve_url_or_path("./$deno$stdin.ts").unwrap();
let mut worker = create_main_worker(
@@ -896,7 +909,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> {
let operation = |main_module: ModuleSpecifier| {
let flags = flags.clone();
- let permissions = Permissions::from_flags(&flags);
+ let permissions = Permissions::from_options(&flags.clone().into());
async move {
let main_module = main_module.clone();
let program_state = ProgramState::new(flags)?;
@@ -932,7 +945,7 @@ async fn run_command(flags: Flags, script: String) -> Result<(), AnyError> {
let main_module = ModuleSpecifier::resolve_url_or_path(&script)?;
let program_state = ProgramState::new(flags.clone())?;
- let permissions = Permissions::from_flags(&flags);
+ let permissions = Permissions::from_options(&flags.clone().into());
let mut worker =
create_main_worker(&program_state, main_module.clone(), permissions);
debug!("main_module {}", main_module);
@@ -953,7 +966,7 @@ async fn test_command(
filter: Option<String>,
) -> Result<(), AnyError> {
let program_state = ProgramState::new(flags.clone())?;
- let permissions = Permissions::from_flags(&flags);
+ let permissions = Permissions::from_options(&flags.clone().into());
let cwd = std::env::current_dir().expect("No current directory");
let include = include.unwrap_or_else(|| vec![".".to_string()]);
let test_modules =
diff --git a/cli/metrics.rs b/cli/metrics.rs
deleted file mode 100644
index c70e0dab9..000000000
--- a/cli/metrics.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-#[derive(Default, Debug)]
-pub struct Metrics {
- pub ops_dispatched: u64,
- pub ops_dispatched_sync: u64,
- pub ops_dispatched_async: u64,
- pub ops_dispatched_async_unref: u64,
- pub ops_completed: u64,
- pub ops_completed_sync: u64,
- pub ops_completed_async: u64,
- pub ops_completed_async_unref: u64,
- pub bytes_sent_control: u64,
- pub bytes_sent_data: u64,
- pub bytes_received: u64,
-}
-
-impl Metrics {
- fn op_dispatched(
- &mut self,
- bytes_sent_control: usize,
- bytes_sent_data: usize,
- ) {
- self.ops_dispatched += 1;
- self.bytes_sent_control += bytes_sent_control as u64;
- self.bytes_sent_data += bytes_sent_data as u64;
- }
-
- fn op_completed(&mut self, bytes_received: usize) {
- self.ops_completed += 1;
- self.bytes_received += bytes_received as u64;
- }
-
- pub fn op_sync(
- &mut self,
- bytes_sent_control: usize,
- bytes_sent_data: usize,
- bytes_received: usize,
- ) {
- self.ops_dispatched_sync += 1;
- self.op_dispatched(bytes_sent_control, bytes_sent_data);
- self.ops_completed_sync += 1;
- self.op_completed(bytes_received);
- }
-
- pub fn op_dispatched_async(
- &mut self,
- bytes_sent_control: usize,
- bytes_sent_data: usize,
- ) {
- self.ops_dispatched_async += 1;
- self.op_dispatched(bytes_sent_control, bytes_sent_data)
- }
-
- pub fn op_dispatched_async_unref(
- &mut self,
- bytes_sent_control: usize,
- bytes_sent_data: usize,
- ) {
- self.ops_dispatched_async_unref += 1;
- self.op_dispatched(bytes_sent_control, bytes_sent_data)
- }
-
- pub fn op_completed_async(&mut self, bytes_received: usize) {
- self.ops_completed_async += 1;
- self.op_completed(bytes_received);
- }
-
- pub fn op_completed_async_unref(&mut self, bytes_received: usize) {
- self.ops_completed_async_unref += 1;
- self.op_completed(bytes_received);
- }
-}
-
-use deno_core::BufVec;
-use deno_core::Op;
-use deno_core::OpFn;
-use deno_core::OpState;
-use std::cell::RefCell;
-use std::rc::Rc;
-
-pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
- Box::new(move |op_state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
- // TODOs:
- // * The 'bytes' metrics seem pretty useless, especially now that the
- // distinction between 'control' and 'data' buffers has become blurry.
- // * Tracking completion of async ops currently makes us put the boxed
- // future into _another_ box. Keeping some counters may not be expensive
- // in itself, but adding a heap allocation for every metric seems bad.
- let mut buf_len_iter = bufs.iter().map(|buf| buf.len());
- let bytes_sent_control = buf_len_iter.next().unwrap_or(0);
- let bytes_sent_data = buf_len_iter.sum();
-
- let op = (op_fn)(op_state.clone(), bufs);
-
- let op_state_ = op_state.clone();
- let mut s = op_state.borrow_mut();
- let metrics = s.borrow_mut::<Metrics>();
-
- use deno_core::futures::future::FutureExt;
-
- match op {
- Op::Sync(buf) => {
- metrics.op_sync(bytes_sent_control, bytes_sent_data, buf.len());
- Op::Sync(buf)
- }
- Op::Async(fut) => {
- metrics.op_dispatched_async(bytes_sent_control, bytes_sent_data);
- let fut = fut
- .inspect(move |buf| {
- let mut s = op_state_.borrow_mut();
- let metrics = s.borrow_mut::<Metrics>();
- metrics.op_completed_async(buf.len());
- })
- .boxed_local();
- Op::Async(fut)
- }
- Op::AsyncUnref(fut) => {
- metrics.op_dispatched_async_unref(bytes_sent_control, bytes_sent_data);
- let fut = fut
- .inspect(move |buf| {
- let mut s = op_state_.borrow_mut();
- let metrics = s.borrow_mut::<Metrics>();
- metrics.op_completed_async_unref(buf.len());
- })
- .boxed_local();
- Op::AsyncUnref(fut)
- }
- other => other,
- }
- })
-}
diff --git a/cli/module_loader.rs b/cli/module_loader.rs
index 9dda2c24a..da75b8510 100644
--- a/cli/module_loader.rs
+++ b/cli/module_loader.rs
@@ -2,7 +2,6 @@
use crate::import_map::ImportMap;
use crate::module_graph::TypeLib;
-use crate::permissions::Permissions;
use crate::program_state::ProgramState;
use deno_core::error::AnyError;
use deno_core::futures::future::FutureExt;
@@ -11,6 +10,7 @@ use deno_core::ModuleLoadId;
use deno_core::ModuleLoader;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
+use deno_runtime::permissions::Permissions;
use std::cell::RefCell;
use std::pin::Pin;
use std::rc::Rc;
diff --git a/cli/ops/crypto.rs b/cli/ops/crypto.rs
deleted file mode 100644
index a73843a33..000000000
--- a/cli/ops/crypto.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-use deno_crypto::op_get_random_values;
-use deno_crypto::rand::rngs::StdRng;
-use deno_crypto::rand::SeedableRng;
-
-pub fn init(rt: &mut deno_core::JsRuntime, maybe_seed: Option<u64>) {
- if let Some(seed) = maybe_seed {
- let rng = StdRng::seed_from_u64(seed);
- let op_state = rt.op_state();
- let mut state = op_state.borrow_mut();
- state.put::<StdRng>(rng);
- }
- super::reg_json_sync(rt, "op_get_random_values", op_get_random_values);
-}
diff --git a/cli/ops/dispatch_minimal.rs b/cli/ops/dispatch_minimal.rs
deleted file mode 100644
index ae8fa819d..000000000
--- a/cli/ops/dispatch_minimal.rs
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::error::AnyError;
-use deno_core::futures::future::FutureExt;
-use deno_core::BufVec;
-use deno_core::Op;
-use deno_core::OpFn;
-use deno_core::OpState;
-use std::cell::RefCell;
-use std::future::Future;
-use std::iter::repeat;
-use std::mem::size_of_val;
-use std::pin::Pin;
-use std::rc::Rc;
-use std::slice;
-
-pub enum MinimalOp {
- Sync(Result<i32, AnyError>),
- Async(Pin<Box<dyn Future<Output = Result<i32, AnyError>>>>),
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-// This corresponds to RecordMinimal on the TS side.
-pub struct Record {
- pub promise_id: i32,
- pub arg: i32,
- pub result: i32,
-}
-
-impl Into<Box<[u8]>> for Record {
- fn into(self) -> Box<[u8]> {
- let vec = vec![self.promise_id, self.arg, self.result];
- let buf32 = vec.into_boxed_slice();
- let ptr = Box::into_raw(buf32) as *mut [u8; 3 * 4];
- unsafe { Box::from_raw(ptr) }
- }
-}
-
-pub struct ErrorRecord {
- pub promise_id: i32,
- pub arg: i32,
- pub error_len: i32,
- pub error_class: &'static [u8],
- pub error_message: Vec<u8>,
-}
-
-impl Into<Box<[u8]>> for ErrorRecord {
- fn into(self) -> Box<[u8]> {
- let Self {
- promise_id,
- arg,
- error_len,
- error_class,
- error_message,
- ..
- } = self;
- let header_i32 = [promise_id, arg, error_len];
- let header_u8 = unsafe {
- slice::from_raw_parts(
- &header_i32 as *const _ as *const u8,
- size_of_val(&header_i32),
- )
- };
- let padded_len =
- (header_u8.len() + error_class.len() + error_message.len() + 3usize)
- & !3usize;
- header_u8
- .iter()
- .cloned()
- .chain(error_class.iter().cloned())
- .chain(error_message.into_iter())
- .chain(repeat(b' '))
- .take(padded_len)
- .collect()
- }
-}
-
-#[test]
-fn test_error_record() {
- let expected = vec![
- 1, 0, 0, 0, 255, 255, 255, 255, 11, 0, 0, 0, 66, 97, 100, 82, 101, 115,
- 111, 117, 114, 99, 101, 69, 114, 114, 111, 114,
- ];
- let err_record = ErrorRecord {
- promise_id: 1,
- arg: -1,
- error_len: 11,
- error_class: b"BadResource",
- error_message: b"Error".to_vec(),
- };
- let buf: Box<[u8]> = err_record.into();
- assert_eq!(buf, expected.into_boxed_slice());
-}
-
-pub fn parse_min_record(bytes: &[u8]) -> Option<Record> {
- if bytes.len() % std::mem::size_of::<i32>() != 0 {
- return None;
- }
- let p = bytes.as_ptr();
- #[allow(clippy::cast_ptr_alignment)]
- let p32 = p as *const i32;
- let s = unsafe { std::slice::from_raw_parts(p32, bytes.len() / 4) };
-
- if s.len() != 3 {
- return None;
- }
- let ptr = s.as_ptr();
- let ints = unsafe { std::slice::from_raw_parts(ptr, 3) };
- Some(Record {
- promise_id: ints[0],
- arg: ints[1],
- result: ints[2],
- })
-}
-
-#[test]
-fn test_parse_min_record() {
- let buf = vec![1, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0];
- assert_eq!(
- parse_min_record(&buf),
- Some(Record {
- promise_id: 1,
- arg: 3,
- result: 4
- })
- );
-
- let buf = vec![];
- assert_eq!(parse_min_record(&buf), None);
-
- let buf = vec![5];
- assert_eq!(parse_min_record(&buf), None);
-}
-
-pub fn minimal_op<F>(op_fn: F) -> Box<OpFn>
-where
- F: Fn(Rc<RefCell<OpState>>, bool, i32, BufVec) -> MinimalOp + 'static,
-{
- Box::new(move |state: Rc<RefCell<OpState>>, bufs: BufVec| {
- let mut bufs_iter = bufs.into_iter();
- let record_buf = bufs_iter.next().expect("Expected record at position 0");
- let zero_copy = bufs_iter.collect::<BufVec>();
-
- let mut record = match parse_min_record(&record_buf) {
- Some(r) => r,
- None => {
- let error_class = b"TypeError";
- let error_message = b"Unparsable control buffer";
- let error_record = ErrorRecord {
- promise_id: 0,
- arg: -1,
- error_len: error_class.len() as i32,
- error_class,
- error_message: error_message[..].to_owned(),
- };
- return Op::Sync(error_record.into());
- }
- };
- let is_sync = record.promise_id == 0;
- let rid = record.arg;
- let min_op = op_fn(state.clone(), is_sync, rid, zero_copy);
-
- match min_op {
- MinimalOp::Sync(sync_result) => Op::Sync(match sync_result {
- Ok(r) => {
- record.result = r;
- record.into()
- }
- Err(err) => {
- let error_class = (state.borrow().get_error_class_fn)(&err);
- let error_record = ErrorRecord {
- promise_id: record.promise_id,
- arg: -1,
- error_len: error_class.len() as i32,
- error_class: error_class.as_bytes(),
- error_message: err.to_string().as_bytes().to_owned(),
- };
- error_record.into()
- }
- }),
- MinimalOp::Async(min_fut) => {
- let fut = async move {
- match min_fut.await {
- Ok(r) => {
- record.result = r;
- record.into()
- }
- Err(err) => {
- let error_class = (state.borrow().get_error_class_fn)(&err);
- let error_record = ErrorRecord {
- promise_id: record.promise_id,
- arg: -1,
- error_len: error_class.len() as i32,
- error_class: error_class.as_bytes(),
- error_message: err.to_string().as_bytes().to_owned(),
- };
- error_record.into()
- }
- }
- };
- Op::Async(fut.boxed_local())
- }
- }
- })
-}
diff --git a/cli/ops/fetch.rs b/cli/ops/fetch.rs
deleted file mode 100644
index 18e9e9c9f..000000000
--- a/cli/ops/fetch.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-use crate::http_util;
-use crate::permissions::Permissions;
-use deno_fetch::reqwest;
-
-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();
- state.put::<reqwest::Client>({
- http_util::create_http_client(http_util::get_user_agent(), maybe_ca_file)
- .unwrap()
- });
- }
- super::reg_json_async(rt, "op_fetch", deno_fetch::op_fetch::<Permissions>);
- super::reg_json_async(rt, "op_fetch_read", deno_fetch::op_fetch_read);
- super::reg_json_sync(
- rt,
- "op_create_http_client",
- deno_fetch::op_create_http_client::<Permissions>,
- );
-}
diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs
deleted file mode 100644
index 865c5bcca..000000000
--- a/cli/ops/fs.rs
+++ /dev/null
@@ -1,1702 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-// Some deserializer fields are only used on Unix and Windows build fails without it
-use super::io::std_file_resource;
-use super::io::{FileMetadata, StreamResource, StreamResourceHolder};
-use crate::fs_util::canonicalize_path;
-use crate::permissions::Permissions;
-use deno_core::error::custom_error;
-use deno_core::error::type_error;
-use deno_core::error::AnyError;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use deno_crypto::rand::thread_rng;
-use deno_crypto::rand::Rng;
-use serde::Deserialize;
-use std::cell::RefCell;
-use std::convert::From;
-use std::env::{current_dir, set_current_dir, temp_dir};
-use std::io;
-use std::io::{Seek, SeekFrom};
-use std::path::{Path, PathBuf};
-use std::rc::Rc;
-use std::time::SystemTime;
-use std::time::UNIX_EPOCH;
-
-#[cfg(not(unix))]
-use deno_core::error::generic_error;
-#[cfg(not(unix))]
-use deno_core::error::not_supported;
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- super::reg_json_sync(rt, "op_open_sync", op_open_sync);
- super::reg_json_async(rt, "op_open_async", op_open_async);
-
- super::reg_json_sync(rt, "op_seek_sync", op_seek_sync);
- super::reg_json_async(rt, "op_seek_async", op_seek_async);
-
- super::reg_json_sync(rt, "op_fdatasync_sync", op_fdatasync_sync);
- super::reg_json_async(rt, "op_fdatasync_async", op_fdatasync_async);
-
- super::reg_json_sync(rt, "op_fsync_sync", op_fsync_sync);
- super::reg_json_async(rt, "op_fsync_async", op_fsync_async);
-
- super::reg_json_sync(rt, "op_fstat_sync", op_fstat_sync);
- super::reg_json_async(rt, "op_fstat_async", op_fstat_async);
-
- super::reg_json_sync(rt, "op_umask", op_umask);
- super::reg_json_sync(rt, "op_chdir", op_chdir);
-
- super::reg_json_sync(rt, "op_mkdir_sync", op_mkdir_sync);
- super::reg_json_async(rt, "op_mkdir_async", op_mkdir_async);
-
- super::reg_json_sync(rt, "op_chmod_sync", op_chmod_sync);
- super::reg_json_async(rt, "op_chmod_async", op_chmod_async);
-
- super::reg_json_sync(rt, "op_chown_sync", op_chown_sync);
- super::reg_json_async(rt, "op_chown_async", op_chown_async);
-
- super::reg_json_sync(rt, "op_remove_sync", op_remove_sync);
- super::reg_json_async(rt, "op_remove_async", op_remove_async);
-
- super::reg_json_sync(rt, "op_copy_file_sync", op_copy_file_sync);
- super::reg_json_async(rt, "op_copy_file_async", op_copy_file_async);
-
- super::reg_json_sync(rt, "op_stat_sync", op_stat_sync);
- super::reg_json_async(rt, "op_stat_async", op_stat_async);
-
- super::reg_json_sync(rt, "op_realpath_sync", op_realpath_sync);
- super::reg_json_async(rt, "op_realpath_async", op_realpath_async);
-
- super::reg_json_sync(rt, "op_read_dir_sync", op_read_dir_sync);
- super::reg_json_async(rt, "op_read_dir_async", op_read_dir_async);
-
- super::reg_json_sync(rt, "op_rename_sync", op_rename_sync);
- super::reg_json_async(rt, "op_rename_async", op_rename_async);
-
- super::reg_json_sync(rt, "op_link_sync", op_link_sync);
- super::reg_json_async(rt, "op_link_async", op_link_async);
-
- super::reg_json_sync(rt, "op_symlink_sync", op_symlink_sync);
- super::reg_json_async(rt, "op_symlink_async", op_symlink_async);
-
- super::reg_json_sync(rt, "op_read_link_sync", op_read_link_sync);
- super::reg_json_async(rt, "op_read_link_async", op_read_link_async);
-
- super::reg_json_sync(rt, "op_ftruncate_sync", op_ftruncate_sync);
- super::reg_json_async(rt, "op_ftruncate_async", op_ftruncate_async);
-
- super::reg_json_sync(rt, "op_truncate_sync", op_truncate_sync);
- super::reg_json_async(rt, "op_truncate_async", op_truncate_async);
-
- super::reg_json_sync(rt, "op_make_temp_dir_sync", op_make_temp_dir_sync);
- super::reg_json_async(rt, "op_make_temp_dir_async", op_make_temp_dir_async);
-
- super::reg_json_sync(rt, "op_make_temp_file_sync", op_make_temp_file_sync);
- super::reg_json_async(rt, "op_make_temp_file_async", op_make_temp_file_async);
-
- super::reg_json_sync(rt, "op_cwd", op_cwd);
-
- super::reg_json_sync(rt, "op_futime_sync", op_futime_sync);
- super::reg_json_async(rt, "op_futime_async", op_futime_async);
-
- super::reg_json_sync(rt, "op_utime_sync", op_utime_sync);
- super::reg_json_async(rt, "op_utime_async", op_utime_async);
-}
-
-fn into_string(s: std::ffi::OsString) -> Result<String, AnyError> {
- s.into_string().map_err(|s| {
- let message = format!("File name or path {:?} is not valid UTF-8", s);
- custom_error("InvalidData", message)
- })
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct OpenArgs {
- path: String,
- mode: Option<u32>,
- options: OpenOptions,
-}
-
-#[derive(Deserialize, Default, Debug)]
-#[serde(rename_all = "camelCase")]
-#[serde(default)]
-struct OpenOptions {
- read: bool,
- write: bool,
- create: bool,
- truncate: bool,
- append: bool,
- create_new: bool,
-}
-
-fn open_helper(
- state: &mut OpState,
- args: Value,
-) -> Result<(PathBuf, std::fs::OpenOptions), AnyError> {
- let args: OpenArgs = serde_json::from_value(args)?;
- let path = Path::new(&args.path).to_path_buf();
-
- let mut open_options = std::fs::OpenOptions::new();
-
- if let Some(mode) = args.mode {
- // mode only used if creating the file on Unix
- // if not specified, defaults to 0o666
- #[cfg(unix)]
- {
- use std::os::unix::fs::OpenOptionsExt;
- open_options.mode(mode & 0o777);
- }
- #[cfg(not(unix))]
- let _ = mode; // avoid unused warning
- }
-
- let permissions = state.borrow::<Permissions>();
- let options = args.options;
-
- if options.read {
- permissions.check_read(&path)?;
- }
-
- if options.write || options.append {
- permissions.check_write(&path)?;
- }
-
- open_options
- .read(options.read)
- .create(options.create)
- .write(options.write)
- .truncate(options.truncate)
- .append(options.append)
- .create_new(options.create_new);
-
- Ok((path, open_options))
-}
-
-fn op_open_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let (path, open_options) = open_helper(state, args)?;
- let std_file = open_options.open(path)?;
- let tokio_file = tokio::fs::File::from_std(std_file);
- let rid = state.resource_table.add(
- "fsFile",
- Box::new(StreamResourceHolder::new(StreamResource::FsFile(Some((
- tokio_file,
- FileMetadata::default(),
- ))))),
- );
- Ok(json!(rid))
-}
-
-async fn op_open_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let (path, open_options) = open_helper(&mut state.borrow_mut(), args)?;
- let tokio_file = tokio::fs::OpenOptions::from(open_options)
- .open(path)
- .await?;
- let rid = state.borrow_mut().resource_table.add(
- "fsFile",
- Box::new(StreamResourceHolder::new(StreamResource::FsFile(Some((
- tokio_file,
- FileMetadata::default(),
- ))))),
- );
- Ok(json!(rid))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct SeekArgs {
- rid: i32,
- offset: i64,
- whence: i32,
-}
-
-fn seek_helper(args: Value) -> Result<(u32, SeekFrom), AnyError> {
- let args: SeekArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let offset = args.offset;
- let whence = args.whence as u32;
- // Translate seek mode to Rust repr.
- let seek_from = match whence {
- 0 => SeekFrom::Start(offset as u64),
- 1 => SeekFrom::Current(offset),
- 2 => SeekFrom::End(offset),
- _ => {
- return Err(type_error(format!("Invalid seek mode: {}", whence)));
- }
- };
-
- Ok((rid, seek_from))
-}
-
-fn op_seek_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let (rid, seek_from) = seek_helper(args)?;
- let pos = std_file_resource(state, rid, |r| match r {
- Ok(std_file) => std_file.seek(seek_from).map_err(AnyError::from),
- Err(_) => Err(type_error(
- "cannot seek on this type of resource".to_string(),
- )),
- })?;
- Ok(json!(pos))
-}
-
-async fn op_seek_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let (rid, seek_from) = seek_helper(args)?;
- // TODO(ry) This is a fake async op. We need to use poll_fn,
- // tokio::fs::File::start_seek and tokio::fs::File::poll_complete
- let pos = std_file_resource(&mut state.borrow_mut(), rid, |r| match r {
- Ok(std_file) => std_file.seek(seek_from).map_err(AnyError::from),
- Err(_) => Err(type_error(
- "cannot seek on this type of resource".to_string(),
- )),
- })?;
- Ok(json!(pos))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct FdatasyncArgs {
- rid: i32,
-}
-
-fn op_fdatasync_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: FdatasyncArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- std_file_resource(state, rid, |r| match r {
- Ok(std_file) => std_file.sync_data().map_err(AnyError::from),
- Err(_) => Err(type_error("cannot sync this type of resource".to_string())),
- })?;
- Ok(json!({}))
-}
-
-async fn op_fdatasync_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: FdatasyncArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- std_file_resource(&mut state.borrow_mut(), rid, |r| match r {
- Ok(std_file) => std_file.sync_data().map_err(AnyError::from),
- Err(_) => Err(type_error("cannot sync this type of resource".to_string())),
- })?;
- Ok(json!({}))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct FsyncArgs {
- rid: i32,
-}
-
-fn op_fsync_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: FsyncArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- std_file_resource(state, rid, |r| match r {
- Ok(std_file) => std_file.sync_all().map_err(AnyError::from),
- Err(_) => Err(type_error("cannot sync this type of resource".to_string())),
- })?;
- Ok(json!({}))
-}
-
-async fn op_fsync_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: FsyncArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- std_file_resource(&mut state.borrow_mut(), rid, |r| match r {
- Ok(std_file) => std_file.sync_all().map_err(AnyError::from),
- Err(_) => Err(type_error("cannot sync this type of resource".to_string())),
- })?;
- Ok(json!({}))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct FstatArgs {
- rid: i32,
-}
-
-fn op_fstat_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.fstat");
- let args: FstatArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let metadata = std_file_resource(state, rid, |r| match r {
- Ok(std_file) => std_file.metadata().map_err(AnyError::from),
- Err(_) => Err(type_error("cannot stat this type of resource".to_string())),
- })?;
- Ok(get_stat_json(metadata))
-}
-
-async fn op_fstat_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- super::check_unstable2(&state, "Deno.fstat");
-
- let args: FstatArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let metadata =
- std_file_resource(&mut state.borrow_mut(), rid, |r| match r {
- Ok(std_file) => std_file.metadata().map_err(AnyError::from),
- Err(_) => {
- Err(type_error("cannot stat this type of resource".to_string()))
- }
- })?;
- Ok(get_stat_json(metadata))
-}
-
-#[derive(Deserialize)]
-struct UmaskArgs {
- mask: Option<u32>,
-}
-
-fn op_umask(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.umask");
- let args: UmaskArgs = serde_json::from_value(args)?;
- // TODO implement umask for Windows
- // see https://github.com/nodejs/node/blob/master/src/node_process_methods.cc
- // and https://docs.microsoft.com/fr-fr/cpp/c-runtime-library/reference/umask?view=vs-2019
- #[cfg(not(unix))]
- {
- let _ = args.mask; // avoid unused warning.
- Err(not_supported())
- }
- #[cfg(unix)]
- {
- use nix::sys::stat::mode_t;
- use nix::sys::stat::umask;
- use nix::sys::stat::Mode;
- let r = if let Some(mask) = args.mask {
- // If mask provided, return previous.
- umask(Mode::from_bits_truncate(mask as mode_t))
- } else {
- // If no mask provided, we query the current. Requires two syscalls.
- let prev = umask(Mode::from_bits_truncate(0o777));
- let _ = umask(prev);
- prev
- };
- Ok(json!(r.bits() as u32))
- }
-}
-
-#[derive(Deserialize)]
-struct ChdirArgs {
- directory: String,
-}
-
-fn op_chdir(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: ChdirArgs = serde_json::from_value(args)?;
- let d = PathBuf::from(&args.directory);
- state.borrow::<Permissions>().check_read(&d)?;
- set_current_dir(&d)?;
- Ok(json!({}))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct MkdirArgs {
- path: String,
- recursive: bool,
- mode: Option<u32>,
-}
-
-fn op_mkdir_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: MkdirArgs = serde_json::from_value(args)?;
- let path = Path::new(&args.path).to_path_buf();
- let mode = args.mode.unwrap_or(0o777) & 0o777;
- state.borrow::<Permissions>().check_write(&path)?;
- debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive);
- let mut builder = std::fs::DirBuilder::new();
- builder.recursive(args.recursive);
- #[cfg(unix)]
- {
- use std::os::unix::fs::DirBuilderExt;
- builder.mode(mode);
- }
- builder.create(path)?;
- Ok(json!({}))
-}
-
-async fn op_mkdir_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: MkdirArgs = serde_json::from_value(args)?;
- let path = Path::new(&args.path).to_path_buf();
- let mode = args.mode.unwrap_or(0o777) & 0o777;
-
- {
- let state = state.borrow();
- state.borrow::<Permissions>().check_write(&path)?;
- }
-
- tokio::task::spawn_blocking(move || {
- debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive);
- let mut builder = std::fs::DirBuilder::new();
- builder.recursive(args.recursive);
- #[cfg(unix)]
- {
- use std::os::unix::fs::DirBuilderExt;
- builder.mode(mode);
- }
- builder.create(path)?;
- Ok(json!({}))
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct ChmodArgs {
- path: String,
- mode: u32,
-}
-
-fn op_chmod_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: ChmodArgs = serde_json::from_value(args)?;
- let path = Path::new(&args.path).to_path_buf();
- let mode = args.mode & 0o777;
-
- state.borrow::<Permissions>().check_write(&path)?;
- debug!("op_chmod_sync {} {:o}", path.display(), mode);
- #[cfg(unix)]
- {
- use std::os::unix::fs::PermissionsExt;
- let permissions = PermissionsExt::from_mode(mode);
- std::fs::set_permissions(&path, permissions)?;
- Ok(json!({}))
- }
- // TODO Implement chmod for Windows (#4357)
- #[cfg(not(unix))]
- {
- // Still check file/dir exists on Windows
- let _metadata = std::fs::metadata(&path)?;
- Err(generic_error("Not implemented"))
- }
-}
-
-async fn op_chmod_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: ChmodArgs = serde_json::from_value(args)?;
- let path = Path::new(&args.path).to_path_buf();
- let mode = args.mode & 0o777;
-
- {
- let state = state.borrow();
- state.borrow::<Permissions>().check_write(&path)?;
- }
-
- tokio::task::spawn_blocking(move || {
- debug!("op_chmod_async {} {:o}", path.display(), mode);
- #[cfg(unix)]
- {
- use std::os::unix::fs::PermissionsExt;
- let permissions = PermissionsExt::from_mode(mode);
- std::fs::set_permissions(&path, permissions)?;
- Ok(json!({}))
- }
- // TODO Implement chmod for Windows (#4357)
- #[cfg(not(unix))]
- {
- // Still check file/dir exists on Windows
- let _metadata = std::fs::metadata(&path)?;
- Err(not_supported())
- }
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct ChownArgs {
- path: String,
- uid: Option<u32>,
- gid: Option<u32>,
-}
-
-fn op_chown_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: ChownArgs = serde_json::from_value(args)?;
- let path = Path::new(&args.path).to_path_buf();
- state.borrow::<Permissions>().check_write(&path)?;
- debug!(
- "op_chown_sync {} {:?} {:?}",
- path.display(),
- args.uid,
- args.gid,
- );
- #[cfg(unix)]
- {
- use nix::unistd::{chown, Gid, Uid};
- let nix_uid = args.uid.map(Uid::from_raw);
- let nix_gid = args.gid.map(Gid::from_raw);
- chown(&path, nix_uid, nix_gid)?;
- Ok(json!({}))
- }
- // TODO Implement chown for Windows
- #[cfg(not(unix))]
- {
- Err(generic_error("Not implemented"))
- }
-}
-
-async fn op_chown_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: ChownArgs = serde_json::from_value(args)?;
- let path = Path::new(&args.path).to_path_buf();
-
- {
- let state = state.borrow();
- state.borrow::<Permissions>().check_write(&path)?;
- }
-
- tokio::task::spawn_blocking(move || {
- debug!(
- "op_chown_async {} {:?} {:?}",
- path.display(),
- args.uid,
- args.gid,
- );
- #[cfg(unix)]
- {
- use nix::unistd::{chown, Gid, Uid};
- let nix_uid = args.uid.map(Uid::from_raw);
- let nix_gid = args.gid.map(Gid::from_raw);
- chown(&path, nix_uid, nix_gid)?;
- Ok(json!({}))
- }
- // TODO Implement chown for Windows
- #[cfg(not(unix))]
- Err(not_supported())
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct RemoveArgs {
- path: String,
- recursive: bool,
-}
-
-fn op_remove_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: RemoveArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- let recursive = args.recursive;
-
- state.borrow::<Permissions>().check_write(&path)?;
-
- #[cfg(not(unix))]
- use std::os::windows::prelude::MetadataExt;
-
- let metadata = std::fs::symlink_metadata(&path)?;
-
- debug!("op_remove_sync {} {}", path.display(), recursive);
- let file_type = metadata.file_type();
- if file_type.is_file() {
- std::fs::remove_file(&path)?;
- } else if recursive {
- std::fs::remove_dir_all(&path)?;
- } else if file_type.is_symlink() {
- #[cfg(unix)]
- std::fs::remove_file(&path)?;
- #[cfg(not(unix))]
- {
- use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY;
- if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
- std::fs::remove_dir(&path)?;
- } else {
- std::fs::remove_file(&path)?;
- }
- }
- } else if file_type.is_dir() {
- std::fs::remove_dir(&path)?;
- } else {
- // pipes, sockets, etc...
- std::fs::remove_file(&path)?;
- }
- Ok(json!({}))
-}
-
-async fn op_remove_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: RemoveArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- let recursive = args.recursive;
-
- {
- let state = state.borrow();
- state.borrow::<Permissions>().check_write(&path)?;
- }
-
- tokio::task::spawn_blocking(move || {
- #[cfg(not(unix))]
- use std::os::windows::prelude::MetadataExt;
-
- let metadata = std::fs::symlink_metadata(&path)?;
-
- debug!("op_remove_async {} {}", path.display(), recursive);
- let file_type = metadata.file_type();
- if file_type.is_file() {
- std::fs::remove_file(&path)?;
- } else if recursive {
- std::fs::remove_dir_all(&path)?;
- } else if file_type.is_symlink() {
- #[cfg(unix)]
- std::fs::remove_file(&path)?;
- #[cfg(not(unix))]
- {
- use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY;
- if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
- std::fs::remove_dir(&path)?;
- } else {
- std::fs::remove_file(&path)?;
- }
- }
- } else if file_type.is_dir() {
- std::fs::remove_dir(&path)?;
- } else {
- // pipes, sockets, etc...
- std::fs::remove_file(&path)?;
- }
- Ok(json!({}))
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct CopyFileArgs {
- from: String,
- to: String,
-}
-
-fn op_copy_file_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: CopyFileArgs = serde_json::from_value(args)?;
- let from = PathBuf::from(&args.from);
- let to = PathBuf::from(&args.to);
-
- let permissions = state.borrow::<Permissions>();
- permissions.check_read(&from)?;
- permissions.check_write(&to)?;
-
- debug!("op_copy_file_sync {} {}", from.display(), to.display());
- // On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput
- // See https://github.com/rust-lang/rust/issues/54800
- // Once the issue is resolved, we should remove this workaround.
- if cfg!(unix) && !from.is_file() {
- return Err(custom_error("NotFound", "File not found"));
- }
-
- // returns size of from as u64 (we ignore)
- std::fs::copy(&from, &to)?;
- Ok(json!({}))
-}
-
-async fn op_copy_file_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: CopyFileArgs = serde_json::from_value(args)?;
- let from = PathBuf::from(&args.from);
- let to = PathBuf::from(&args.to);
-
- {
- let state = state.borrow();
- let permissions = state.borrow::<Permissions>();
- permissions.check_read(&from)?;
- permissions.check_write(&to)?;
- }
-
- debug!("op_copy_file_async {} {}", from.display(), to.display());
- tokio::task::spawn_blocking(move || {
- // On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput
- // See https://github.com/rust-lang/rust/issues/54800
- // Once the issue is resolved, we should remove this workaround.
- if cfg!(unix) && !from.is_file() {
- return Err(custom_error("NotFound", "File not found"));
- }
-
- // returns size of from as u64 (we ignore)
- std::fs::copy(&from, &to)?;
- Ok(json!({}))
- })
- .await
- .unwrap()
-}
-
-fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> Value {
- match maybe_time {
- Ok(time) => {
- let msec = time
- .duration_since(UNIX_EPOCH)
- .map(|t| t.as_secs_f64() * 1000f64)
- .unwrap_or_else(|err| err.duration().as_secs_f64() * -1000f64);
- serde_json::Number::from_f64(msec)
- .map(Value::Number)
- .unwrap_or(Value::Null)
- }
- Err(_) => Value::Null,
- }
-}
-
-#[inline(always)]
-fn get_stat_json(metadata: std::fs::Metadata) -> Value {
- // Unix stat member (number types only). 0 if not on unix.
- macro_rules! usm {
- ($member:ident) => {{
- #[cfg(unix)]
- {
- metadata.$member()
- }
- #[cfg(not(unix))]
- {
- 0
- }
- }};
- }
-
- #[cfg(unix)]
- use std::os::unix::fs::MetadataExt;
- let json_val = json!({
- "isFile": metadata.is_file(),
- "isDirectory": metadata.is_dir(),
- "isSymlink": metadata.file_type().is_symlink(),
- "size": metadata.len(),
- // In milliseconds, like JavaScript. Available on both Unix or Windows.
- "mtime": to_msec(metadata.modified()),
- "atime": to_msec(metadata.accessed()),
- "birthtime": to_msec(metadata.created()),
- // Following are only valid under Unix.
- "dev": usm!(dev),
- "ino": usm!(ino),
- "mode": usm!(mode),
- "nlink": usm!(nlink),
- "uid": usm!(uid),
- "gid": usm!(gid),
- "rdev": usm!(rdev),
- // TODO(kevinkassimo): *time_nsec requires BigInt.
- // Probably should be treated as String if we need to add them.
- "blksize": usm!(blksize),
- "blocks": usm!(blocks),
- });
- json_val
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct StatArgs {
- path: String,
- lstat: bool,
-}
-
-fn op_stat_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: StatArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- let lstat = args.lstat;
- state.borrow::<Permissions>().check_read(&path)?;
- debug!("op_stat_sync {} {}", path.display(), lstat);
- let metadata = if lstat {
- std::fs::symlink_metadata(&path)?
- } else {
- std::fs::metadata(&path)?
- };
- Ok(get_stat_json(metadata))
-}
-
-async fn op_stat_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: StatArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- let lstat = args.lstat;
-
- {
- let state = state.borrow();
- state.borrow::<Permissions>().check_read(&path)?;
- }
-
- tokio::task::spawn_blocking(move || {
- debug!("op_stat_async {} {}", path.display(), lstat);
- let metadata = if lstat {
- std::fs::symlink_metadata(&path)?
- } else {
- std::fs::metadata(&path)?
- };
- Ok(get_stat_json(metadata))
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct RealpathArgs {
- path: String,
-}
-
-fn op_realpath_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: RealpathArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
-
- let permissions = state.borrow::<Permissions>();
- permissions.check_read(&path)?;
- if path.is_relative() {
- permissions.check_read_blind(&current_dir()?, "CWD")?;
- }
-
- debug!("op_realpath_sync {}", path.display());
- // corresponds to the realpath on Unix and
- // CreateFile and GetFinalPathNameByHandle on Windows
- let realpath = canonicalize_path(&path)?;
- let realpath_str = into_string(realpath.into_os_string())?;
- Ok(json!(realpath_str))
-}
-
-async fn op_realpath_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: RealpathArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
-
- {
- let state = state.borrow();
- let permissions = state.borrow::<Permissions>();
- permissions.check_read(&path)?;
- if path.is_relative() {
- permissions.check_read_blind(&current_dir()?, "CWD")?;
- }
- }
-
- tokio::task::spawn_blocking(move || {
- debug!("op_realpath_async {}", path.display());
- // corresponds to the realpath on Unix and
- // CreateFile and GetFinalPathNameByHandle on Windows
- let realpath = canonicalize_path(&path)?;
- let realpath_str = into_string(realpath.into_os_string())?;
- Ok(json!(realpath_str))
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct ReadDirArgs {
- path: String,
-}
-
-fn op_read_dir_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: ReadDirArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
-
- state.borrow::<Permissions>().check_read(&path)?;
-
- debug!("op_read_dir_sync {}", path.display());
- let entries: Vec<_> = std::fs::read_dir(path)?
- .filter_map(|entry| {
- let entry = entry.unwrap();
- let file_type = entry.file_type().unwrap();
- // Not all filenames can be encoded as UTF-8. Skip those for now.
- if let Ok(name) = into_string(entry.file_name()) {
- Some(json!({
- "name": name,
- "isFile": file_type.is_file(),
- "isDirectory": file_type.is_dir(),
- "isSymlink": file_type.is_symlink()
- }))
- } else {
- None
- }
- })
- .collect();
-
- Ok(json!({ "entries": entries }))
-}
-
-async fn op_read_dir_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: ReadDirArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- {
- let state = state.borrow();
- state.borrow::<Permissions>().check_read(&path)?;
- }
- tokio::task::spawn_blocking(move || {
- debug!("op_read_dir_async {}", path.display());
- let entries: Vec<_> = std::fs::read_dir(path)?
- .filter_map(|entry| {
- let entry = entry.unwrap();
- let file_type = entry.file_type().unwrap();
- // Not all filenames can be encoded as UTF-8. Skip those for now.
- if let Ok(name) = into_string(entry.file_name()) {
- Some(json!({
- "name": name,
- "isFile": file_type.is_file(),
- "isDirectory": file_type.is_dir(),
- "isSymlink": file_type.is_symlink()
- }))
- } else {
- None
- }
- })
- .collect();
-
- Ok(json!({ "entries": entries }))
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct RenameArgs {
- oldpath: String,
- newpath: String,
-}
-
-fn op_rename_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: RenameArgs = serde_json::from_value(args)?;
- let oldpath = PathBuf::from(&args.oldpath);
- let newpath = PathBuf::from(&args.newpath);
-
- let permissions = state.borrow::<Permissions>();
- permissions.check_read(&oldpath)?;
- permissions.check_write(&oldpath)?;
- permissions.check_write(&newpath)?;
- debug!("op_rename_sync {} {}", oldpath.display(), newpath.display());
- std::fs::rename(&oldpath, &newpath)?;
- Ok(json!({}))
-}
-
-async fn op_rename_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: RenameArgs = serde_json::from_value(args)?;
- let oldpath = PathBuf::from(&args.oldpath);
- let newpath = PathBuf::from(&args.newpath);
- {
- let state = state.borrow();
- let permissions = state.borrow::<Permissions>();
- permissions.check_read(&oldpath)?;
- permissions.check_write(&oldpath)?;
- permissions.check_write(&newpath)?;
- }
- tokio::task::spawn_blocking(move || {
- debug!(
- "op_rename_async {} {}",
- oldpath.display(),
- newpath.display()
- );
- std::fs::rename(&oldpath, &newpath)?;
- Ok(json!({}))
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct LinkArgs {
- oldpath: String,
- newpath: String,
-}
-
-fn op_link_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.link");
- let args: LinkArgs = serde_json::from_value(args)?;
- let oldpath = PathBuf::from(&args.oldpath);
- let newpath = PathBuf::from(&args.newpath);
-
- let permissions = state.borrow::<Permissions>();
- permissions.check_read(&oldpath)?;
- permissions.check_write(&newpath)?;
-
- debug!("op_link_sync {} {}", oldpath.display(), newpath.display());
- std::fs::hard_link(&oldpath, &newpath)?;
- Ok(json!({}))
-}
-
-async fn op_link_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- super::check_unstable2(&state, "Deno.link");
-
- let args: LinkArgs = serde_json::from_value(args)?;
- let oldpath = PathBuf::from(&args.oldpath);
- let newpath = PathBuf::from(&args.newpath);
-
- {
- let state = state.borrow();
- let permissions = state.borrow::<Permissions>();
- permissions.check_read(&oldpath)?;
- permissions.check_write(&newpath)?;
- }
-
- tokio::task::spawn_blocking(move || {
- debug!("op_link_async {} {}", oldpath.display(), newpath.display());
- std::fs::hard_link(&oldpath, &newpath)?;
- Ok(json!({}))
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct SymlinkArgs {
- oldpath: String,
- newpath: String,
- #[cfg(not(unix))]
- options: Option<SymlinkOptions>,
-}
-
-#[cfg(not(unix))]
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct SymlinkOptions {
- _type: String,
-}
-
-fn op_symlink_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.symlink");
- let args: SymlinkArgs = serde_json::from_value(args)?;
- let oldpath = PathBuf::from(&args.oldpath);
- let newpath = PathBuf::from(&args.newpath);
-
- state.borrow::<Permissions>().check_write(&newpath)?;
-
- debug!(
- "op_symlink_sync {} {}",
- oldpath.display(),
- newpath.display()
- );
- #[cfg(unix)]
- {
- use std::os::unix::fs::symlink;
- symlink(&oldpath, &newpath)?;
- Ok(json!({}))
- }
- #[cfg(not(unix))]
- {
- use std::os::windows::fs::{symlink_dir, symlink_file};
-
- match args.options {
- Some(options) => match options._type.as_ref() {
- "file" => symlink_file(&oldpath, &newpath)?,
- "dir" => symlink_dir(&oldpath, &newpath)?,
- _ => return Err(type_error("unsupported type")),
- },
- None => {
- let old_meta = std::fs::metadata(&oldpath);
- match old_meta {
- Ok(metadata) => {
- if metadata.is_file() {
- symlink_file(&oldpath, &newpath)?
- } else if metadata.is_dir() {
- symlink_dir(&oldpath, &newpath)?
- }
- }
- Err(_) => return Err(type_error("you must pass a `options` argument for non-existent target path in windows".to_string())),
- }
- }
- };
- Ok(json!({}))
- }
-}
-
-async fn op_symlink_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- super::check_unstable2(&state, "Deno.symlink");
-
- let args: SymlinkArgs = serde_json::from_value(args)?;
- let oldpath = PathBuf::from(&args.oldpath);
- let newpath = PathBuf::from(&args.newpath);
-
- {
- let state = state.borrow();
- state.borrow::<Permissions>().check_write(&newpath)?;
- }
-
- tokio::task::spawn_blocking(move || {
- debug!("op_symlink_async {} {}", oldpath.display(), newpath.display());
- #[cfg(unix)]
- {
- use std::os::unix::fs::symlink;
- symlink(&oldpath, &newpath)?;
- Ok(json!({}))
- }
- #[cfg(not(unix))]
- {
- use std::os::windows::fs::{symlink_dir, symlink_file};
-
- match args.options {
- Some(options) => match options._type.as_ref() {
- "file" => symlink_file(&oldpath, &newpath)?,
- "dir" => symlink_dir(&oldpath, &newpath)?,
- _ => return Err(type_error("unsupported type")),
- },
- None => {
- let old_meta = std::fs::metadata(&oldpath);
- match old_meta {
- Ok(metadata) => {
- if metadata.is_file() {
- symlink_file(&oldpath, &newpath)?
- } else if metadata.is_dir() {
- symlink_dir(&oldpath, &newpath)?
- }
- }
- Err(_) => return Err(type_error("you must pass a `options` argument for non-existent target path in windows".to_string())),
- }
- }
- };
- Ok(json!({}))
- }
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct ReadLinkArgs {
- path: String,
-}
-
-fn op_read_link_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: ReadLinkArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
-
- state.borrow::<Permissions>().check_read(&path)?;
-
- debug!("op_read_link_value {}", path.display());
- let target = std::fs::read_link(&path)?.into_os_string();
- let targetstr = into_string(target)?;
- Ok(json!(targetstr))
-}
-
-async fn op_read_link_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: ReadLinkArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- {
- let state = state.borrow();
- state.borrow::<Permissions>().check_read(&path)?;
- }
- tokio::task::spawn_blocking(move || {
- debug!("op_read_link_async {}", path.display());
- let target = std::fs::read_link(&path)?.into_os_string();
- let targetstr = into_string(target)?;
- Ok(json!(targetstr))
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct FtruncateArgs {
- rid: i32,
- len: i32,
-}
-
-fn op_ftruncate_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.ftruncate");
- let args: FtruncateArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let len = args.len as u64;
- std_file_resource(state, rid, |r| match r {
- Ok(std_file) => std_file.set_len(len).map_err(AnyError::from),
- Err(_) => Err(type_error("cannot truncate this type of resource")),
- })?;
- Ok(json!({}))
-}
-
-async fn op_ftruncate_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- super::check_unstable2(&state, "Deno.ftruncate");
- let args: FtruncateArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let len = args.len as u64;
- std_file_resource(&mut state.borrow_mut(), rid, |r| match r {
- Ok(std_file) => std_file.set_len(len).map_err(AnyError::from),
- Err(_) => Err(type_error("cannot truncate this type of resource")),
- })?;
- Ok(json!({}))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct TruncateArgs {
- path: String,
- len: u64,
-}
-
-fn op_truncate_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: TruncateArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- let len = args.len;
-
- state.borrow::<Permissions>().check_write(&path)?;
-
- debug!("op_truncate_sync {} {}", path.display(), len);
- let f = std::fs::OpenOptions::new().write(true).open(&path)?;
- f.set_len(len)?;
- Ok(json!({}))
-}
-
-async fn op_truncate_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: TruncateArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- let len = args.len;
- {
- let state = state.borrow();
- state.borrow::<Permissions>().check_write(&path)?;
- }
- tokio::task::spawn_blocking(move || {
- debug!("op_truncate_async {} {}", path.display(), len);
- let f = std::fs::OpenOptions::new().write(true).open(&path)?;
- f.set_len(len)?;
- Ok(json!({}))
- })
- .await
- .unwrap()
-}
-
-fn make_temp(
- dir: Option<&Path>,
- prefix: Option<&str>,
- suffix: Option<&str>,
- is_dir: bool,
-) -> std::io::Result<PathBuf> {
- let prefix_ = prefix.unwrap_or("");
- let suffix_ = suffix.unwrap_or("");
- let mut buf: PathBuf = match dir {
- Some(ref p) => p.to_path_buf(),
- None => temp_dir(),
- }
- .join("_");
- let mut rng = thread_rng();
- loop {
- let unique = rng.gen::<u32>();
- buf.set_file_name(format!("{}{:08x}{}", prefix_, unique, suffix_));
- let r = if is_dir {
- #[allow(unused_mut)]
- let mut builder = std::fs::DirBuilder::new();
- #[cfg(unix)]
- {
- use std::os::unix::fs::DirBuilderExt;
- builder.mode(0o700);
- }
- builder.create(buf.as_path())
- } else {
- let mut open_options = std::fs::OpenOptions::new();
- open_options.write(true).create_new(true);
- #[cfg(unix)]
- {
- use std::os::unix::fs::OpenOptionsExt;
- open_options.mode(0o600);
- }
- open_options.open(buf.as_path())?;
- Ok(())
- };
- match r {
- Err(ref e) if e.kind() == std::io::ErrorKind::AlreadyExists => continue,
- Ok(_) => return Ok(buf),
- Err(e) => return Err(e),
- }
- }
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct MakeTempArgs {
- dir: Option<String>,
- prefix: Option<String>,
- suffix: Option<String>,
-}
-
-fn op_make_temp_dir_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: MakeTempArgs = serde_json::from_value(args)?;
-
- let dir = args.dir.map(|s| PathBuf::from(&s));
- let prefix = args.prefix.map(String::from);
- let suffix = args.suffix.map(String::from);
-
- state
- .borrow::<Permissions>()
- .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?;
-
- // TODO(piscisaureus): use byte vector for paths, not a string.
- // See https://github.com/denoland/deno/issues/627.
- // We can't assume that paths are always valid utf8 strings.
- let path = make_temp(
- // Converting Option<String> to Option<&str>
- dir.as_deref(),
- prefix.as_deref(),
- suffix.as_deref(),
- true,
- )?;
- let path_str = into_string(path.into_os_string())?;
-
- Ok(json!(path_str))
-}
-
-async fn op_make_temp_dir_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: MakeTempArgs = serde_json::from_value(args)?;
-
- let dir = args.dir.map(|s| PathBuf::from(&s));
- let prefix = args.prefix.map(String::from);
- let suffix = args.suffix.map(String::from);
- {
- let state = state.borrow();
- state
- .borrow::<Permissions>()
- .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?;
- }
- tokio::task::spawn_blocking(move || {
- // TODO(piscisaureus): use byte vector for paths, not a string.
- // See https://github.com/denoland/deno/issues/627.
- // We can't assume that paths are always valid utf8 strings.
- let path = make_temp(
- // Converting Option<String> to Option<&str>
- dir.as_deref(),
- prefix.as_deref(),
- suffix.as_deref(),
- true,
- )?;
- let path_str = into_string(path.into_os_string())?;
-
- Ok(json!(path_str))
- })
- .await
- .unwrap()
-}
-
-fn op_make_temp_file_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: MakeTempArgs = serde_json::from_value(args)?;
-
- let dir = args.dir.map(|s| PathBuf::from(&s));
- let prefix = args.prefix.map(String::from);
- let suffix = args.suffix.map(String::from);
-
- state
- .borrow::<Permissions>()
- .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?;
-
- // TODO(piscisaureus): use byte vector for paths, not a string.
- // See https://github.com/denoland/deno/issues/627.
- // We can't assume that paths are always valid utf8 strings.
- let path = make_temp(
- // Converting Option<String> to Option<&str>
- dir.as_deref(),
- prefix.as_deref(),
- suffix.as_deref(),
- false,
- )?;
- let path_str = into_string(path.into_os_string())?;
-
- Ok(json!(path_str))
-}
-
-async fn op_make_temp_file_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: MakeTempArgs = serde_json::from_value(args)?;
-
- let dir = args.dir.map(|s| PathBuf::from(&s));
- let prefix = args.prefix.map(String::from);
- let suffix = args.suffix.map(String::from);
- {
- let state = state.borrow();
- state
- .borrow::<Permissions>()
- .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?;
- }
- tokio::task::spawn_blocking(move || {
- // TODO(piscisaureus): use byte vector for paths, not a string.
- // See https://github.com/denoland/deno/issues/627.
- // We can't assume that paths are always valid utf8 strings.
- let path = make_temp(
- // Converting Option<String> to Option<&str>
- dir.as_deref(),
- prefix.as_deref(),
- suffix.as_deref(),
- false,
- )?;
- let path_str = into_string(path.into_os_string())?;
-
- Ok(json!(path_str))
- })
- .await
- .unwrap()
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct FutimeArgs {
- rid: i32,
- atime: (i64, u32),
- mtime: (i64, u32),
-}
-
-fn op_futime_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.futimeSync");
- let args: FutimeArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
- let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
-
- std_file_resource(state, rid, |r| match r {
- Ok(std_file) => {
- filetime::set_file_handle_times(std_file, Some(atime), Some(mtime))
- .map_err(AnyError::from)
- }
- Err(_) => Err(type_error(
- "cannot futime on this type of resource".to_string(),
- )),
- })?;
-
- Ok(json!({}))
-}
-
-async fn op_futime_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let mut state = state.borrow_mut();
- super::check_unstable(&state, "Deno.futime");
- let args: FutimeArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
- let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
- // TODO Not actually async! https://github.com/denoland/deno/issues/7400
- std_file_resource(&mut state, rid, |r| match r {
- Ok(std_file) => {
- filetime::set_file_handle_times(std_file, Some(atime), Some(mtime))
- .map_err(AnyError::from)
- }
- Err(_) => Err(type_error(
- "cannot futime on this type of resource".to_string(),
- )),
- })?;
-
- Ok(json!({}))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct UtimeArgs {
- path: String,
- atime: (i64, u32),
- mtime: (i64, u32),
-}
-
-fn op_utime_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.utime");
-
- let args: UtimeArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
- let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
-
- state.borrow::<Permissions>().check_write(&path)?;
- filetime::set_file_times(path, atime, mtime)?;
- Ok(json!({}))
-}
-
-async fn op_utime_async(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let state = state.borrow();
- super::check_unstable(&state, "Deno.utime");
-
- let args: UtimeArgs = serde_json::from_value(args)?;
- let path = PathBuf::from(&args.path);
- let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
- let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
-
- state.borrow::<Permissions>().check_write(&path)?;
-
- tokio::task::spawn_blocking(move || {
- filetime::set_file_times(path, atime, mtime)?;
- Ok(json!({}))
- })
- .await
- .unwrap()
-}
-
-fn op_cwd(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let path = current_dir()?;
- state
- .borrow::<Permissions>()
- .check_read_blind(&path, "CWD")?;
- let path_str = into_string(path.into_os_string())?;
- Ok(json!(path_str))
-}
diff --git a/cli/ops/fs_events.rs b/cli/ops/fs_events.rs
deleted file mode 100644
index 4832c915c..000000000
--- a/cli/ops/fs_events.rs
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::permissions::Permissions;
-use deno_core::error::bad_resource_id;
-use deno_core::error::AnyError;
-use deno_core::futures::future::poll_fn;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use notify::event::Event as NotifyEvent;
-use notify::Error as NotifyError;
-use notify::EventKind;
-use notify::RecommendedWatcher;
-use notify::RecursiveMode;
-use notify::Watcher;
-use serde::Deserialize;
-use serde::Serialize;
-use std::cell::RefCell;
-use std::convert::From;
-use std::path::PathBuf;
-use std::rc::Rc;
-use tokio::sync::mpsc;
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- super::reg_json_sync(rt, "op_fs_events_open", op_fs_events_open);
- super::reg_json_async(rt, "op_fs_events_poll", op_fs_events_poll);
-}
-
-struct FsEventsResource {
- #[allow(unused)]
- watcher: RecommendedWatcher,
- receiver: mpsc::Receiver<Result<FsEvent, AnyError>>,
-}
-
-/// Represents a file system event.
-///
-/// We do not use the event directly from the notify crate. We flatten
-/// the structure into this simpler structure. We want to only make it more
-/// complex as needed.
-///
-/// Feel free to expand this struct as long as you can add tests to demonstrate
-/// the complexity.
-#[derive(Serialize, Debug)]
-struct FsEvent {
- kind: String,
- paths: Vec<PathBuf>,
-}
-
-impl From<NotifyEvent> for FsEvent {
- fn from(e: NotifyEvent) -> Self {
- let kind = match e.kind {
- EventKind::Any => "any",
- EventKind::Access(_) => "access",
- EventKind::Create(_) => "create",
- EventKind::Modify(_) => "modify",
- EventKind::Remove(_) => "remove",
- EventKind::Other => todo!(), // What's this for? Leaving it out for now.
- }
- .to_string();
- FsEvent {
- kind,
- paths: e.paths,
- }
- }
-}
-
-fn op_fs_events_open(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- #[derive(Deserialize)]
- struct OpenArgs {
- recursive: bool,
- paths: Vec<String>,
- }
- let args: OpenArgs = serde_json::from_value(args)?;
- let (sender, receiver) = mpsc::channel::<Result<FsEvent, AnyError>>(16);
- let sender = std::sync::Mutex::new(sender);
- let mut watcher: RecommendedWatcher =
- Watcher::new_immediate(move |res: Result<NotifyEvent, NotifyError>| {
- let res2 = res.map(FsEvent::from).map_err(AnyError::from);
- let mut sender = sender.lock().unwrap();
- // Ignore result, if send failed it means that watcher was already closed,
- // but not all messages have been flushed.
- let _ = sender.try_send(res2);
- })?;
- let recursive_mode = if args.recursive {
- RecursiveMode::Recursive
- } else {
- RecursiveMode::NonRecursive
- };
- for path in &args.paths {
- state
- .borrow::<Permissions>()
- .check_read(&PathBuf::from(path))?;
- watcher.watch(path, recursive_mode)?;
- }
- let resource = FsEventsResource { watcher, receiver };
- let rid = state.resource_table.add("fsEvents", Box::new(resource));
- Ok(json!(rid))
-}
-
-async fn op_fs_events_poll(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- #[derive(Deserialize)]
- struct PollArgs {
- rid: u32,
- }
- let PollArgs { rid } = serde_json::from_value(args)?;
- poll_fn(move |cx| {
- let mut state = state.borrow_mut();
- let watcher = state
- .resource_table
- .get_mut::<FsEventsResource>(rid)
- .ok_or_else(bad_resource_id)?;
- watcher
- .receiver
- .poll_recv(cx)
- .map(|maybe_result| match maybe_result {
- Some(Ok(value)) => Ok(json!({ "value": value, "done": false })),
- Some(Err(err)) => Err(err),
- None => Ok(json!({ "done": true })),
- })
- })
- .await
-}
diff --git a/cli/ops/io.rs b/cli/ops/io.rs
deleted file mode 100644
index 0f8af905a..000000000
--- a/cli/ops/io.rs
+++ /dev/null
@@ -1,473 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use super::dispatch_minimal::minimal_op;
-use super::dispatch_minimal::MinimalOp;
-use crate::metrics::metrics_op;
-use deno_core::error::bad_resource_id;
-use deno_core::error::resource_unavailable;
-use deno_core::error::type_error;
-use deno_core::error::AnyError;
-use deno_core::futures;
-use deno_core::futures::future::poll_fn;
-use deno_core::futures::future::FutureExt;
-use deno_core::futures::ready;
-use deno_core::BufVec;
-use deno_core::JsRuntime;
-use deno_core::OpState;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::pin::Pin;
-use std::rc::Rc;
-use std::sync::atomic::{AtomicUsize, Ordering};
-use std::task::Context;
-use std::task::Poll;
-use tokio::io::{AsyncRead, AsyncWrite};
-use tokio::net::TcpStream;
-use tokio_rustls::client::TlsStream as ClientTlsStream;
-use tokio_rustls::server::TlsStream as ServerTlsStream;
-
-#[cfg(not(windows))]
-use std::os::unix::io::FromRawFd;
-
-#[cfg(windows)]
-use std::os::windows::io::FromRawHandle;
-
-lazy_static! {
- /// Due to portability issues on Windows handle to stdout is created from raw
- /// file descriptor. The caveat of that approach is fact that when this
- /// handle is dropped underlying file descriptor is closed - that is highly
- /// not desirable in case of stdout. That's why we store this global handle
- /// that is then cloned when obtaining stdio for process. In turn when
- /// resource table is dropped storing reference to that handle, the handle
- /// itself won't be closed (so Deno.core.print) will still work.
- // TODO(ry) It should be possible to close stdout.
- static ref STDIN_HANDLE: Option<std::fs::File> = {
- #[cfg(not(windows))]
- let stdin = unsafe { Some(std::fs::File::from_raw_fd(0)) };
- #[cfg(windows)]
- let stdin = unsafe {
- let handle = winapi::um::processenv::GetStdHandle(
- winapi::um::winbase::STD_INPUT_HANDLE,
- );
- if handle.is_null() {
- return None;
- }
- Some(std::fs::File::from_raw_handle(handle))
- };
- stdin
- };
- static ref STDOUT_HANDLE: Option<std::fs::File> = {
- #[cfg(not(windows))]
- let stdout = unsafe { Some(std::fs::File::from_raw_fd(1)) };
- #[cfg(windows)]
- let stdout = unsafe {
- let handle = winapi::um::processenv::GetStdHandle(
- winapi::um::winbase::STD_OUTPUT_HANDLE,
- );
- if handle.is_null() {
- return None;
- }
- Some(std::fs::File::from_raw_handle(handle))
- };
- stdout
- };
- static ref STDERR_HANDLE: Option<std::fs::File> = {
- #[cfg(not(windows))]
- let stderr = unsafe { Some(std::fs::File::from_raw_fd(2)) };
- #[cfg(windows)]
- let stderr = unsafe {
- let handle = winapi::um::processenv::GetStdHandle(
- winapi::um::winbase::STD_ERROR_HANDLE,
- );
- if handle.is_null() {
- return None;
- }
- Some(std::fs::File::from_raw_handle(handle))
- };
- stderr
- };
-}
-
-pub fn init(rt: &mut JsRuntime) {
- rt.register_op("op_read", metrics_op(minimal_op(op_read)));
- rt.register_op("op_write", metrics_op(minimal_op(op_write)));
-}
-
-pub fn get_stdio() -> (
- Option<StreamResourceHolder>,
- Option<StreamResourceHolder>,
- Option<StreamResourceHolder>,
-) {
- let stdin = get_stdio_stream(&STDIN_HANDLE);
- let stdout = get_stdio_stream(&STDOUT_HANDLE);
- let stderr = get_stdio_stream(&STDERR_HANDLE);
-
- (stdin, stdout, stderr)
-}
-
-fn get_stdio_stream(
- handle: &Option<std::fs::File>,
-) -> Option<StreamResourceHolder> {
- match handle {
- None => None,
- Some(file_handle) => match file_handle.try_clone() {
- Ok(clone) => Some(StreamResourceHolder::new(StreamResource::FsFile(
- Some((tokio::fs::File::from_std(clone), FileMetadata::default())),
- ))),
- Err(_e) => None,
- },
- }
-}
-
-fn no_buffer_specified() -> AnyError {
- type_error("no buffer specified")
-}
-
-#[cfg(unix)]
-use nix::sys::termios;
-
-#[derive(Default)]
-pub struct TTYMetadata {
- #[cfg(unix)]
- pub mode: Option<termios::Termios>,
-}
-
-#[derive(Default)]
-pub struct FileMetadata {
- pub tty: TTYMetadata,
-}
-
-pub struct StreamResourceHolder {
- pub resource: StreamResource,
- waker: HashMap<usize, futures::task::AtomicWaker>,
- waker_counter: AtomicUsize,
-}
-
-impl StreamResourceHolder {
- pub fn new(resource: StreamResource) -> StreamResourceHolder {
- StreamResourceHolder {
- resource,
- // Atleast one task is expecter for the resource
- waker: HashMap::with_capacity(1),
- // Tracks wakers Ids
- waker_counter: AtomicUsize::new(0),
- }
- }
-}
-
-impl Drop for StreamResourceHolder {
- fn drop(&mut self) {
- self.wake_tasks();
- }
-}
-
-impl StreamResourceHolder {
- pub fn track_task(&mut self, cx: &Context) -> Result<usize, AnyError> {
- let waker = futures::task::AtomicWaker::new();
- waker.register(cx.waker());
- // Its OK if it overflows
- let task_waker_id = self.waker_counter.fetch_add(1, Ordering::Relaxed);
- self.waker.insert(task_waker_id, waker);
- Ok(task_waker_id)
- }
-
- pub fn wake_tasks(&mut self) {
- for waker in self.waker.values() {
- waker.wake();
- }
- }
-
- pub fn untrack_task(&mut self, task_waker_id: usize) {
- self.waker.remove(&task_waker_id);
- }
-}
-
-pub enum StreamResource {
- FsFile(Option<(tokio::fs::File, FileMetadata)>),
- TcpStream(Option<tokio::net::TcpStream>),
- #[cfg(not(windows))]
- UnixStream(tokio::net::UnixStream),
- ServerTlsStream(Box<ServerTlsStream<TcpStream>>),
- ClientTlsStream(Box<ClientTlsStream<TcpStream>>),
- ChildStdin(tokio::process::ChildStdin),
- ChildStdout(tokio::process::ChildStdout),
- ChildStderr(tokio::process::ChildStderr),
-}
-
-trait UnpinAsyncRead: AsyncRead + Unpin {}
-trait UnpinAsyncWrite: AsyncWrite + Unpin {}
-
-impl<T: AsyncRead + Unpin> UnpinAsyncRead for T {}
-impl<T: AsyncWrite + Unpin> UnpinAsyncWrite for T {}
-
-/// `DenoAsyncRead` is the same as the `tokio_io::AsyncRead` trait
-/// but uses an `AnyError` error instead of `std::io:Error`
-pub trait DenoAsyncRead {
- fn poll_read(
- &mut self,
- cx: &mut Context,
- buf: &mut [u8],
- ) -> Poll<Result<usize, AnyError>>;
-}
-
-impl DenoAsyncRead for StreamResource {
- fn poll_read(
- &mut self,
- cx: &mut Context,
- buf: &mut [u8],
- ) -> Poll<Result<usize, AnyError>> {
- use StreamResource::*;
- let f: &mut dyn UnpinAsyncRead = match self {
- FsFile(Some((f, _))) => f,
- FsFile(None) => return Poll::Ready(Err(resource_unavailable())),
- TcpStream(Some(f)) => f,
- #[cfg(not(windows))]
- UnixStream(f) => f,
- ClientTlsStream(f) => f,
- ServerTlsStream(f) => f,
- ChildStdout(f) => f,
- ChildStderr(f) => f,
- _ => return Err(bad_resource_id()).into(),
- };
- let v = ready!(Pin::new(f).poll_read(cx, buf))?;
- Ok(v).into()
- }
-}
-
-pub fn op_read(
- state: Rc<RefCell<OpState>>,
- is_sync: bool,
- rid: i32,
- mut zero_copy: BufVec,
-) -> MinimalOp {
- debug!("read rid={}", rid);
- match zero_copy.len() {
- 0 => return MinimalOp::Sync(Err(no_buffer_specified())),
- 1 => {}
- _ => panic!("Invalid number of arguments"),
- }
-
- if is_sync {
- MinimalOp::Sync({
- // First we look up the rid in the resource table.
- std_file_resource(&mut state.borrow_mut(), rid as u32, move |r| match r {
- Ok(std_file) => {
- use std::io::Read;
- std_file
- .read(&mut zero_copy[0])
- .map(|n: usize| n as i32)
- .map_err(AnyError::from)
- }
- Err(_) => Err(type_error("sync read not allowed on this resource")),
- })
- })
- } else {
- let mut zero_copy = zero_copy[0].clone();
- MinimalOp::Async(
- poll_fn(move |cx| {
- let mut state = state.borrow_mut();
- let resource_holder = state
- .resource_table
- .get_mut::<StreamResourceHolder>(rid as u32)
- .ok_or_else(bad_resource_id)?;
-
- let mut task_tracker_id: Option<usize> = None;
- let nread = match resource_holder.resource.poll_read(cx, &mut zero_copy)
- {
- Poll::Ready(t) => {
- if let Some(id) = task_tracker_id {
- resource_holder.untrack_task(id);
- }
- t
- }
- Poll::Pending => {
- task_tracker_id.replace(resource_holder.track_task(cx)?);
- return Poll::Pending;
- }
- }?;
- Poll::Ready(Ok(nread as i32))
- })
- .boxed_local(),
- )
- }
-}
-
-/// `DenoAsyncWrite` is the same as the `tokio_io::AsyncWrite` trait
-/// but uses an `AnyError` error instead of `std::io:Error`
-pub trait DenoAsyncWrite {
- fn poll_write(
- &mut self,
- cx: &mut Context,
- buf: &[u8],
- ) -> Poll<Result<usize, AnyError>>;
-
- fn poll_close(&mut self, cx: &mut Context) -> Poll<Result<(), AnyError>>;
-
- fn poll_flush(&mut self, cx: &mut Context) -> Poll<Result<(), AnyError>>;
-}
-
-impl DenoAsyncWrite for StreamResource {
- fn poll_write(
- &mut self,
- cx: &mut Context,
- buf: &[u8],
- ) -> Poll<Result<usize, AnyError>> {
- use StreamResource::*;
- let f: &mut dyn UnpinAsyncWrite = match self {
- FsFile(Some((f, _))) => f,
- FsFile(None) => return Poll::Pending,
- TcpStream(Some(f)) => f,
- #[cfg(not(windows))]
- UnixStream(f) => f,
- ClientTlsStream(f) => f,
- ServerTlsStream(f) => f,
- ChildStdin(f) => f,
- _ => return Err(bad_resource_id()).into(),
- };
-
- let v = ready!(Pin::new(f).poll_write(cx, buf))?;
- Ok(v).into()
- }
-
- fn poll_flush(&mut self, cx: &mut Context) -> Poll<Result<(), AnyError>> {
- use StreamResource::*;
- let f: &mut dyn UnpinAsyncWrite = match self {
- FsFile(Some((f, _))) => f,
- FsFile(None) => return Poll::Pending,
- TcpStream(Some(f)) => f,
- #[cfg(not(windows))]
- UnixStream(f) => f,
- ClientTlsStream(f) => f,
- ServerTlsStream(f) => f,
- ChildStdin(f) => f,
- _ => return Err(bad_resource_id()).into(),
- };
-
- ready!(Pin::new(f).poll_flush(cx))?;
- Ok(()).into()
- }
-
- fn poll_close(&mut self, _cx: &mut Context) -> Poll<Result<(), AnyError>> {
- unimplemented!()
- }
-}
-
-pub fn op_write(
- state: Rc<RefCell<OpState>>,
- is_sync: bool,
- rid: i32,
- zero_copy: BufVec,
-) -> MinimalOp {
- debug!("write rid={}", rid);
- match zero_copy.len() {
- 0 => return MinimalOp::Sync(Err(no_buffer_specified())),
- 1 => {}
- _ => panic!("Invalid number of arguments"),
- }
-
- if is_sync {
- MinimalOp::Sync({
- // First we look up the rid in the resource table.
- std_file_resource(&mut state.borrow_mut(), rid as u32, move |r| match r {
- Ok(std_file) => {
- use std::io::Write;
- std_file
- .write(&zero_copy[0])
- .map(|nwritten: usize| nwritten as i32)
- .map_err(AnyError::from)
- }
- Err(_) => Err(type_error("sync read not allowed on this resource")),
- })
- })
- } else {
- let zero_copy = zero_copy[0].clone();
- MinimalOp::Async(
- async move {
- let nwritten = poll_fn(|cx| {
- let mut state = state.borrow_mut();
- let resource_holder = state
- .resource_table
- .get_mut::<StreamResourceHolder>(rid as u32)
- .ok_or_else(bad_resource_id)?;
- resource_holder.resource.poll_write(cx, &zero_copy)
- })
- .await?;
-
- // TODO(bartlomieju): this step was added during upgrade to Tokio 0.2
- // and the reasons for the need to explicitly flush are not fully known.
- // Figure out why it's needed and preferably remove it.
- // https://github.com/denoland/deno/issues/3565
- poll_fn(|cx| {
- let mut state = state.borrow_mut();
- let resource_holder = state
- .resource_table
- .get_mut::<StreamResourceHolder>(rid as u32)
- .ok_or_else(bad_resource_id)?;
- resource_holder.resource.poll_flush(cx)
- })
- .await?;
-
- Ok(nwritten as i32)
- }
- .boxed_local(),
- )
- }
-}
-
-/// Helper function for operating on a std::fs::File stored in the resource table.
-///
-/// We store file system file resources as tokio::fs::File, so this is a little
-/// utility function that gets a std::fs:File when you need to do blocking
-/// operations.
-///
-/// Returns ErrorKind::Busy if the resource is being used by another op.
-pub fn std_file_resource<F, T>(
- state: &mut OpState,
- rid: u32,
- mut f: F,
-) -> Result<T, AnyError>
-where
- F: FnMut(
- Result<&mut std::fs::File, &mut StreamResource>,
- ) -> Result<T, AnyError>,
-{
- // First we look up the rid in the resource table.
- let mut r = state.resource_table.get_mut::<StreamResourceHolder>(rid);
- if let Some(ref mut resource_holder) = r {
- // Sync write only works for FsFile. It doesn't make sense to do this
- // for non-blocking sockets. So we error out if not FsFile.
- match &mut resource_holder.resource {
- StreamResource::FsFile(option_file_metadata) => {
- // The object in the resource table is a tokio::fs::File - but in
- // order to do a blocking write on it, we must turn it into a
- // std::fs::File. Hopefully this code compiles down to nothing.
- if let Some((tokio_file, metadata)) = option_file_metadata.take() {
- match tokio_file.try_into_std() {
- Ok(mut std_file) => {
- let result = f(Ok(&mut std_file));
- // Turn the std_file handle back into a tokio file, put it back
- // in the resource table.
- let tokio_file = tokio::fs::File::from_std(std_file);
- resource_holder.resource =
- StreamResource::FsFile(Some((tokio_file, metadata)));
- // return the result.
- result
- }
- Err(tokio_file) => {
- // This function will return an error containing the file if
- // some operation is in-flight.
- resource_holder.resource =
- StreamResource::FsFile(Some((tokio_file, metadata)));
- Err(resource_unavailable())
- }
- }
- } else {
- Err(resource_unavailable())
- }
- }
- _ => f(Err(&mut resource_holder.resource)),
- }
- } else {
- Err(bad_resource_id())
- }
-}
diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs
index 56c0f1ad5..24eca3e77 100644
--- a/cli/ops/mod.rs
+++ b/cli/ops/mod.rs
@@ -1,32 +1,8 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-mod dispatch_minimal;
-pub use dispatch_minimal::MinimalOp;
-
-pub mod crypto;
pub mod errors;
-pub mod fetch;
-pub mod fs;
-pub mod fs_events;
-pub mod io;
-pub mod net;
-#[cfg(unix)]
-mod net_unix;
-pub mod os;
-pub mod permissions;
-pub mod plugin;
-pub mod process;
-pub mod runtime;
pub mod runtime_compiler;
-pub mod signal;
-pub mod timers;
-pub mod tls;
-pub mod tty;
-pub mod web_worker;
-pub mod websocket;
-pub mod worker_host;
-use crate::metrics::metrics_op;
use deno_core::error::AnyError;
use deno_core::json_op_async;
use deno_core::json_op_sync;
@@ -35,6 +11,7 @@ use deno_core::BufVec;
use deno_core::JsRuntime;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
+use deno_runtime::metrics::metrics_op;
use std::cell::RefCell;
use std::future::Future;
use std::rc::Rc;
@@ -54,34 +31,3 @@ 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::<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::<UnstableChecker>().check_unstable(api_name)
-}
diff --git a/cli/ops/net.rs b/cli/ops/net.rs
deleted file mode 100644
index 98ff83fc0..000000000
--- a/cli/ops/net.rs
+++ /dev/null
@@ -1,566 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::ops::io::StreamResource;
-use crate::ops::io::StreamResourceHolder;
-use crate::permissions::Permissions;
-use crate::resolve_addr::resolve_addr;
-use deno_core::error::bad_resource;
-use deno_core::error::bad_resource_id;
-use deno_core::error::custom_error;
-use deno_core::error::generic_error;
-use deno_core::error::type_error;
-use deno_core::error::AnyError;
-use deno_core::futures;
-use deno_core::futures::future::poll_fn;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use serde::Deserialize;
-use std::cell::RefCell;
-use std::net::Shutdown;
-use std::net::SocketAddr;
-use std::rc::Rc;
-use std::task::Context;
-use std::task::Poll;
-use tokio::net::TcpListener;
-use tokio::net::TcpStream;
-use tokio::net::UdpSocket;
-
-#[cfg(unix)]
-use super::net_unix;
-#[cfg(unix)]
-use std::path::Path;
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- super::reg_json_async(rt, "op_accept", op_accept);
- super::reg_json_async(rt, "op_connect", op_connect);
- super::reg_json_sync(rt, "op_shutdown", op_shutdown);
- super::reg_json_sync(rt, "op_listen", op_listen);
- super::reg_json_async(rt, "op_datagram_receive", op_datagram_receive);
- super::reg_json_async(rt, "op_datagram_send", op_datagram_send);
-}
-
-#[derive(Deserialize)]
-pub(crate) struct AcceptArgs {
- pub rid: i32,
- pub transport: String,
-}
-
-async fn accept_tcp(
- state: Rc<RefCell<OpState>>,
- args: AcceptArgs,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let rid = args.rid as u32;
-
- let accept_fut = poll_fn(|cx| {
- let mut state = state.borrow_mut();
- let listener_resource = state
- .resource_table
- .get_mut::<TcpListenerResource>(rid)
- .ok_or_else(|| bad_resource("Listener has been closed"))?;
- let listener = &mut listener_resource.listener;
- match listener.poll_accept(cx).map_err(AnyError::from) {
- Poll::Ready(Ok((stream, addr))) => {
- listener_resource.untrack_task();
- Poll::Ready(Ok((stream, addr)))
- }
- Poll::Pending => {
- listener_resource.track_task(cx)?;
- Poll::Pending
- }
- Poll::Ready(Err(e)) => {
- listener_resource.untrack_task();
- Poll::Ready(Err(e))
- }
- }
- });
- let (tcp_stream, _socket_addr) = accept_fut.await?;
- let local_addr = tcp_stream.local_addr()?;
- let remote_addr = tcp_stream.peer_addr()?;
-
- let mut state = state.borrow_mut();
- let rid = state.resource_table.add(
- "tcpStream",
- Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some(
- tcp_stream,
- )))),
- );
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "hostname": local_addr.ip().to_string(),
- "port": local_addr.port(),
- "transport": "tcp",
- },
- "remoteAddr": {
- "hostname": remote_addr.ip().to_string(),
- "port": remote_addr.port(),
- "transport": "tcp",
- }
- }))
-}
-
-async fn op_accept(
- state: Rc<RefCell<OpState>>,
- args: Value,
- bufs: BufVec,
-) -> Result<Value, AnyError> {
- let args: AcceptArgs = serde_json::from_value(args)?;
- match args.transport.as_str() {
- "tcp" => accept_tcp(state, args, bufs).await,
- #[cfg(unix)]
- "unix" => net_unix::accept_unix(state, args, bufs).await,
- _ => Err(generic_error(format!(
- "Unsupported transport protocol {}",
- args.transport
- ))),
- }
-}
-
-#[derive(Deserialize)]
-pub(crate) struct ReceiveArgs {
- pub rid: i32,
- pub transport: String,
-}
-
-async fn receive_udp(
- state: Rc<RefCell<OpState>>,
- args: ReceiveArgs,
- zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- assert_eq!(zero_copy.len(), 1, "Invalid number of arguments");
- let mut zero_copy = zero_copy[0].clone();
-
- let rid = args.rid as u32;
-
- let receive_fut = poll_fn(|cx| {
- let mut state = state.borrow_mut();
- let resource = state
- .resource_table
- .get_mut::<UdpSocketResource>(rid)
- .ok_or_else(|| bad_resource("Socket has been closed"))?;
- let socket = &mut resource.socket;
- socket
- .poll_recv_from(cx, &mut zero_copy)
- .map_err(AnyError::from)
- });
- let (size, remote_addr) = receive_fut.await?;
- Ok(json!({
- "size": size,
- "remoteAddr": {
- "hostname": remote_addr.ip().to_string(),
- "port": remote_addr.port(),
- "transport": "udp",
- }
- }))
-}
-
-async fn op_datagram_receive(
- state: Rc<RefCell<OpState>>,
- args: Value,
- zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- assert_eq!(zero_copy.len(), 1, "Invalid number of arguments");
-
- let args: ReceiveArgs = serde_json::from_value(args)?;
- match args.transport.as_str() {
- "udp" => receive_udp(state, args, zero_copy).await,
- #[cfg(unix)]
- "unixpacket" => net_unix::receive_unix_packet(state, args, zero_copy).await,
- _ => Err(generic_error(format!(
- "Unsupported transport protocol {}",
- args.transport
- ))),
- }
-}
-
-#[derive(Deserialize)]
-struct SendArgs {
- rid: i32,
- transport: String,
- #[serde(flatten)]
- transport_args: ArgsEnum,
-}
-
-async fn op_datagram_send(
- state: Rc<RefCell<OpState>>,
- args: Value,
- zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- assert_eq!(zero_copy.len(), 1, "Invalid number of arguments");
- let zero_copy = zero_copy[0].clone();
-
- match serde_json::from_value(args)? {
- SendArgs {
- rid,
- transport,
- transport_args: ArgsEnum::Ip(args),
- } if transport == "udp" => {
- {
- let s = state.borrow();
- s.borrow::<Permissions>()
- .check_net(&args.hostname, args.port)?;
- }
- let addr = resolve_addr(&args.hostname, args.port)?;
- poll_fn(move |cx| {
- let mut state = state.borrow_mut();
- let resource = state
- .resource_table
- .get_mut::<UdpSocketResource>(rid as u32)
- .ok_or_else(|| bad_resource("Socket has been closed"))?;
- resource
- .socket
- .poll_send_to(cx, &zero_copy, &addr)
- .map_ok(|byte_length| json!(byte_length))
- .map_err(AnyError::from)
- })
- .await
- }
- #[cfg(unix)]
- SendArgs {
- rid,
- transport,
- transport_args: ArgsEnum::Unix(args),
- } if transport == "unixpacket" => {
- let address_path = Path::new(&args.path);
- {
- let s = state.borrow();
- s.borrow::<Permissions>().check_write(&address_path)?;
- }
- let mut state = state.borrow_mut();
- let resource = state
- .resource_table
- .get_mut::<net_unix::UnixDatagramResource>(rid as u32)
- .ok_or_else(|| {
- custom_error("NotConnected", "Socket has been closed")
- })?;
- let socket = &mut resource.socket;
- let byte_length = socket
- .send_to(&zero_copy, &resource.local_addr.as_pathname().unwrap())
- .await?;
-
- Ok(json!(byte_length))
- }
- _ => Err(type_error("Wrong argument format!")),
- }
-}
-
-#[derive(Deserialize)]
-struct ConnectArgs {
- transport: String,
- #[serde(flatten)]
- transport_args: ArgsEnum,
-}
-
-async fn op_connect(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- match serde_json::from_value(args)? {
- ConnectArgs {
- transport,
- transport_args: ArgsEnum::Ip(args),
- } if transport == "tcp" => {
- {
- let state_ = state.borrow();
- state_
- .borrow::<Permissions>()
- .check_net(&args.hostname, args.port)?;
- }
- let addr = resolve_addr(&args.hostname, args.port)?;
- let tcp_stream = TcpStream::connect(&addr).await?;
- let local_addr = tcp_stream.local_addr()?;
- let remote_addr = tcp_stream.peer_addr()?;
-
- let mut state_ = state.borrow_mut();
- let rid = state_.resource_table.add(
- "tcpStream",
- Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some(
- tcp_stream,
- )))),
- );
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "hostname": local_addr.ip().to_string(),
- "port": local_addr.port(),
- "transport": transport,
- },
- "remoteAddr": {
- "hostname": remote_addr.ip().to_string(),
- "port": remote_addr.port(),
- "transport": transport,
- }
- }))
- }
- #[cfg(unix)]
- ConnectArgs {
- transport,
- transport_args: ArgsEnum::Unix(args),
- } if transport == "unix" => {
- let address_path = Path::new(&args.path);
- super::check_unstable2(&state, "Deno.connect");
- {
- let state_ = state.borrow();
- state_.borrow::<Permissions>().check_read(&address_path)?;
- state_.borrow::<Permissions>().check_write(&address_path)?;
- }
- let path = args.path;
- let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?;
- let local_addr = unix_stream.local_addr()?;
- let remote_addr = unix_stream.peer_addr()?;
-
- let mut state_ = state.borrow_mut();
- let rid = state_.resource_table.add(
- "unixStream",
- Box::new(StreamResourceHolder::new(StreamResource::UnixStream(
- unix_stream,
- ))),
- );
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "path": local_addr.as_pathname(),
- "transport": transport,
- },
- "remoteAddr": {
- "path": remote_addr.as_pathname(),
- "transport": transport,
- }
- }))
- }
- _ => Err(type_error("Wrong argument format!")),
- }
-}
-
-#[derive(Deserialize)]
-struct ShutdownArgs {
- rid: i32,
- how: i32,
-}
-
-fn op_shutdown(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.shutdown");
-
- let args: ShutdownArgs = serde_json::from_value(args)?;
-
- let rid = args.rid as u32;
- let how = args.how;
-
- let shutdown_mode = match how {
- 0 => Shutdown::Read,
- 1 => Shutdown::Write,
- _ => unimplemented!(),
- };
-
- let resource_holder = state
- .resource_table
- .get_mut::<StreamResourceHolder>(rid)
- .ok_or_else(bad_resource_id)?;
- match resource_holder.resource {
- StreamResource::TcpStream(Some(ref mut stream)) => {
- TcpStream::shutdown(stream, shutdown_mode)?;
- }
- #[cfg(unix)]
- StreamResource::UnixStream(ref mut stream) => {
- net_unix::UnixStream::shutdown(stream, shutdown_mode)?;
- }
- _ => return Err(bad_resource_id()),
- }
-
- Ok(json!({}))
-}
-
-#[allow(dead_code)]
-struct TcpListenerResource {
- listener: TcpListener,
- waker: Option<futures::task::AtomicWaker>,
- local_addr: SocketAddr,
-}
-
-impl Drop for TcpListenerResource {
- fn drop(&mut self) {
- self.wake_task();
- }
-}
-
-impl TcpListenerResource {
- /// Track the current task so future awaiting for connection
- /// can be notified when listener is closed.
- ///
- /// Throws an error if another task is already tracked.
- pub fn track_task(&mut self, cx: &Context) -> Result<(), AnyError> {
- // Currently, we only allow tracking a single accept task for a listener.
- // This might be changed in the future with multiple workers.
- // Caveat: TcpListener by itself also only tracks an accept task at a time.
- // See https://github.com/tokio-rs/tokio/issues/846#issuecomment-454208883
- if self.waker.is_some() {
- return Err(custom_error("Busy", "Another accept task is ongoing"));
- }
-
- let waker = futures::task::AtomicWaker::new();
- waker.register(cx.waker());
- self.waker.replace(waker);
- Ok(())
- }
-
- /// Notifies a task when listener is closed so accept future can resolve.
- pub fn wake_task(&mut self) {
- if let Some(waker) = self.waker.as_ref() {
- waker.wake();
- }
- }
-
- /// Stop tracking a task.
- /// Happens when the task is done and thus no further tracking is needed.
- pub fn untrack_task(&mut self) {
- if self.waker.is_some() {
- self.waker.take();
- }
- }
-}
-
-struct UdpSocketResource {
- socket: UdpSocket,
-}
-
-#[derive(Deserialize)]
-struct IpListenArgs {
- hostname: String,
- port: u16,
-}
-
-#[derive(Deserialize)]
-#[serde(untagged)]
-enum ArgsEnum {
- Ip(IpListenArgs),
- #[cfg(unix)]
- Unix(net_unix::UnixListenArgs),
-}
-
-#[derive(Deserialize)]
-struct ListenArgs {
- transport: String,
- #[serde(flatten)]
- transport_args: ArgsEnum,
-}
-
-fn listen_tcp(
- state: &mut OpState,
- addr: SocketAddr,
-) -> Result<(u32, SocketAddr), AnyError> {
- let std_listener = std::net::TcpListener::bind(&addr)?;
- let listener = TcpListener::from_std(std_listener)?;
- let local_addr = listener.local_addr()?;
- let listener_resource = TcpListenerResource {
- listener,
- waker: None,
- local_addr,
- };
- let rid = state
- .resource_table
- .add("tcpListener", Box::new(listener_resource));
-
- Ok((rid, local_addr))
-}
-
-fn listen_udp(
- state: &mut OpState,
- addr: SocketAddr,
-) -> Result<(u32, SocketAddr), AnyError> {
- let std_socket = std::net::UdpSocket::bind(&addr)?;
- let socket = UdpSocket::from_std(std_socket)?;
- let local_addr = socket.local_addr()?;
- let socket_resource = UdpSocketResource { socket };
- let rid = state
- .resource_table
- .add("udpSocket", Box::new(socket_resource));
-
- Ok((rid, local_addr))
-}
-
-fn op_listen(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let permissions = state.borrow::<Permissions>();
- match serde_json::from_value(args)? {
- ListenArgs {
- transport,
- transport_args: ArgsEnum::Ip(args),
- } => {
- {
- if transport == "udp" {
- super::check_unstable(state, "Deno.listenDatagram");
- }
- permissions.check_net(&args.hostname, args.port)?;
- }
- let addr = resolve_addr(&args.hostname, args.port)?;
- let (rid, local_addr) = if transport == "tcp" {
- listen_tcp(state, addr)?
- } else {
- listen_udp(state, addr)?
- };
- debug!(
- "New listener {} {}:{}",
- rid,
- local_addr.ip().to_string(),
- local_addr.port()
- );
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "hostname": local_addr.ip().to_string(),
- "port": local_addr.port(),
- "transport": transport,
- },
- }))
- }
- #[cfg(unix)]
- ListenArgs {
- transport,
- transport_args: ArgsEnum::Unix(args),
- } if transport == "unix" || transport == "unixpacket" => {
- let address_path = Path::new(&args.path);
- {
- if transport == "unix" {
- super::check_unstable(state, "Deno.listen");
- }
- if transport == "unixpacket" {
- super::check_unstable(state, "Deno.listenDatagram");
- }
- permissions.check_read(&address_path)?;
- permissions.check_write(&address_path)?;
- }
- let (rid, local_addr) = if transport == "unix" {
- net_unix::listen_unix(state, &address_path)?
- } else {
- net_unix::listen_unix_packet(state, &address_path)?
- };
- debug!(
- "New listener {} {}",
- rid,
- local_addr.as_pathname().unwrap().display(),
- );
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "path": local_addr.as_pathname(),
- "transport": transport,
- },
- }))
- }
- #[cfg(unix)]
- _ => Err(type_error("Wrong argument format!")),
- }
-}
diff --git a/cli/ops/net_unix.rs b/cli/ops/net_unix.rs
deleted file mode 100644
index 4c416a5a4..000000000
--- a/cli/ops/net_unix.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::ops::io::StreamResource;
-use crate::ops::io::StreamResourceHolder;
-use crate::ops::net::AcceptArgs;
-use crate::ops::net::ReceiveArgs;
-use deno_core::error::bad_resource;
-use deno_core::error::AnyError;
-use deno_core::futures::future::poll_fn;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::OpState;
-use serde::Deserialize;
-use std::cell::RefCell;
-use std::fs::remove_file;
-use std::os::unix;
-use std::path::Path;
-use std::rc::Rc;
-use std::task::Poll;
-use tokio::net::UnixDatagram;
-use tokio::net::UnixListener;
-pub use tokio::net::UnixStream;
-
-struct UnixListenerResource {
- listener: UnixListener,
-}
-
-pub struct UnixDatagramResource {
- pub socket: UnixDatagram,
- pub local_addr: unix::net::SocketAddr,
-}
-
-#[derive(Deserialize)]
-pub struct UnixListenArgs {
- pub path: String,
-}
-
-pub(crate) async fn accept_unix(
- state: Rc<RefCell<OpState>>,
- args: AcceptArgs,
- _bufs: BufVec,
-) -> Result<Value, AnyError> {
- let rid = args.rid as u32;
-
- let accept_fut = poll_fn(|cx| {
- let mut state = state.borrow_mut();
- let listener_resource = state
- .resource_table
- .get_mut::<UnixListenerResource>(rid)
- .ok_or_else(|| bad_resource("Listener has been closed"))?;
- let listener = &mut listener_resource.listener;
- use deno_core::futures::StreamExt;
- match listener.poll_next_unpin(cx) {
- Poll::Ready(Some(stream)) => {
- //listener_resource.untrack_task();
- Poll::Ready(stream)
- }
- Poll::Ready(None) => todo!(),
- Poll::Pending => {
- //listener_resource.track_task(cx)?;
- Poll::Pending
- }
- }
- .map_err(AnyError::from)
- });
- let unix_stream = accept_fut.await?;
-
- let local_addr = unix_stream.local_addr()?;
- let remote_addr = unix_stream.peer_addr()?;
- let mut state = state.borrow_mut();
- let rid = state.resource_table.add(
- "unixStream",
- Box::new(StreamResourceHolder::new(StreamResource::UnixStream(
- unix_stream,
- ))),
- );
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "path": local_addr.as_pathname(),
- "transport": "unix",
- },
- "remoteAddr": {
- "path": remote_addr.as_pathname(),
- "transport": "unix",
- }
- }))
-}
-
-pub(crate) async fn receive_unix_packet(
- state: Rc<RefCell<OpState>>,
- args: ReceiveArgs,
- bufs: BufVec,
-) -> Result<Value, AnyError> {
- assert_eq!(bufs.len(), 1, "Invalid number of arguments");
-
- let rid = args.rid as u32;
- let mut buf = bufs.into_iter().next().unwrap();
-
- let mut state = state.borrow_mut();
- let resource = state
- .resource_table
- .get_mut::<UnixDatagramResource>(rid)
- .ok_or_else(|| bad_resource("Socket has been closed"))?;
- let (size, remote_addr) = resource.socket.recv_from(&mut buf).await?;
- Ok(json!({
- "size": size,
- "remoteAddr": {
- "path": remote_addr.as_pathname(),
- "transport": "unixpacket",
- }
- }))
-}
-
-pub fn listen_unix(
- state: &mut OpState,
- addr: &Path,
-) -> Result<(u32, unix::net::SocketAddr), AnyError> {
- if addr.exists() {
- remove_file(&addr).unwrap();
- }
- let listener = UnixListener::bind(&addr)?;
- let local_addr = listener.local_addr()?;
- let listener_resource = UnixListenerResource { listener };
- let rid = state
- .resource_table
- .add("unixListener", Box::new(listener_resource));
-
- Ok((rid, local_addr))
-}
-
-pub fn listen_unix_packet(
- state: &mut OpState,
- addr: &Path,
-) -> Result<(u32, unix::net::SocketAddr), AnyError> {
- if addr.exists() {
- remove_file(&addr).unwrap();
- }
- let socket = UnixDatagram::bind(&addr)?;
- let local_addr = socket.local_addr()?;
- let datagram_resource = UnixDatagramResource {
- socket,
- local_addr: local_addr.clone(),
- };
- let rid = state
- .resource_table
- .add("unixDatagram", Box::new(datagram_resource));
-
- Ok((rid, local_addr))
-}
diff --git a/cli/ops/os.rs b/cli/ops/os.rs
deleted file mode 100644
index 6fd404a23..000000000
--- a/cli/ops/os.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::permissions::Permissions;
-use deno_core::error::AnyError;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::url::Url;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use serde::Deserialize;
-use std::collections::HashMap;
-use std::env;
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- super::reg_json_sync(rt, "op_exit", op_exit);
- super::reg_json_sync(rt, "op_env", op_env);
- super::reg_json_sync(rt, "op_exec_path", op_exec_path);
- super::reg_json_sync(rt, "op_set_env", op_set_env);
- super::reg_json_sync(rt, "op_get_env", op_get_env);
- super::reg_json_sync(rt, "op_delete_env", op_delete_env);
- super::reg_json_sync(rt, "op_hostname", op_hostname);
- super::reg_json_sync(rt, "op_loadavg", op_loadavg);
- super::reg_json_sync(rt, "op_os_release", op_os_release);
- super::reg_json_sync(rt, "op_system_memory_info", op_system_memory_info);
- super::reg_json_sync(rt, "op_system_cpu_info", op_system_cpu_info);
-}
-
-fn op_exec_path(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let current_exe = env::current_exe().unwrap();
- state
- .borrow::<Permissions>()
- .check_read_blind(&current_exe, "exec_path")?;
- // Now apply URL parser to current exe to get fully resolved path, otherwise
- // we might get `./` and `../` bits in `exec_path`
- let exe_url = Url::from_file_path(current_exe).unwrap();
- let path = exe_url.to_file_path().unwrap();
- Ok(json!(path))
-}
-
-#[derive(Deserialize)]
-struct SetEnv {
- key: String,
- value: String,
-}
-
-fn op_set_env(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: SetEnv = serde_json::from_value(args)?;
- state.borrow::<Permissions>().check_env()?;
- env::set_var(args.key, args.value);
- Ok(json!({}))
-}
-
-fn op_env(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- state.borrow::<Permissions>().check_env()?;
- let v = env::vars().collect::<HashMap<String, String>>();
- Ok(json!(v))
-}
-
-#[derive(Deserialize)]
-struct GetEnv {
- key: String,
-}
-
-fn op_get_env(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: GetEnv = serde_json::from_value(args)?;
- state.borrow::<Permissions>().check_env()?;
- let r = match env::var(args.key) {
- Err(env::VarError::NotPresent) => json!([]),
- v => json!([v?]),
- };
- Ok(r)
-}
-
-#[derive(Deserialize)]
-struct DeleteEnv {
- key: String,
-}
-
-fn op_delete_env(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: DeleteEnv = serde_json::from_value(args)?;
- state.borrow::<Permissions>().check_env()?;
- env::remove_var(args.key);
- Ok(json!({}))
-}
-
-#[derive(Deserialize)]
-struct Exit {
- code: i32,
-}
-
-fn op_exit(
- _state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: Exit = serde_json::from_value(args)?;
- std::process::exit(args.code)
-}
-
-fn op_loadavg(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.loadavg");
- state.borrow::<Permissions>().check_env()?;
- match sys_info::loadavg() {
- Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])),
- Err(_) => Ok(json!([0f64, 0f64, 0f64])),
- }
-}
-
-fn op_hostname(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.hostname");
- state.borrow::<Permissions>().check_env()?;
- let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string());
- Ok(json!(hostname))
-}
-
-fn op_os_release(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.osRelease");
- state.borrow::<Permissions>().check_env()?;
- let release = sys_info::os_release().unwrap_or_else(|_| "".to_string());
- Ok(json!(release))
-}
-
-fn op_system_memory_info(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.systemMemoryInfo");
- state.borrow::<Permissions>().check_env()?;
- match sys_info::mem_info() {
- Ok(info) => Ok(json!({
- "total": info.total,
- "free": info.free,
- "available": info.avail,
- "buffers": info.buffers,
- "cached": info.cached,
- "swapTotal": info.swap_total,
- "swapFree": info.swap_free
- })),
- Err(_) => Ok(json!({})),
- }
-}
-
-fn op_system_cpu_info(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.systemCpuInfo");
- state.borrow::<Permissions>().check_env()?;
-
- let cores = sys_info::cpu_num().ok();
- let speed = sys_info::cpu_speed().ok();
-
- Ok(json!({
- "cores": cores,
- "speed": speed
- }))
-}
diff --git a/cli/ops/permissions.rs b/cli/ops/permissions.rs
deleted file mode 100644
index 7474c0e37..000000000
--- a/cli/ops/permissions.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::permissions::Permissions;
-use deno_core::error::custom_error;
-use deno_core::error::AnyError;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use serde::Deserialize;
-use std::path::Path;
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- super::reg_json_sync(rt, "op_query_permission", op_query_permission);
- super::reg_json_sync(rt, "op_revoke_permission", op_revoke_permission);
- super::reg_json_sync(rt, "op_request_permission", op_request_permission);
-}
-
-#[derive(Deserialize)]
-struct PermissionArgs {
- name: String,
- url: Option<String>,
- path: Option<String>,
-}
-
-pub fn op_query_permission(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: PermissionArgs = serde_json::from_value(args)?;
- let permissions = state.borrow::<Permissions>();
- let path = args.path.as_deref();
- let perm = match args.name.as_ref() {
- "read" => permissions.query_read(&path.as_deref().map(Path::new)),
- "write" => permissions.query_write(&path.as_deref().map(Path::new)),
- "net" => permissions.query_net_url(&args.url.as_deref())?,
- "env" => permissions.query_env(),
- "run" => permissions.query_run(),
- "plugin" => permissions.query_plugin(),
- "hrtime" => permissions.query_hrtime(),
- n => {
- return Err(custom_error(
- "ReferenceError",
- format!("No such permission name: {}", n),
- ))
- }
- };
- Ok(json!({ "state": perm.to_string() }))
-}
-
-pub fn op_revoke_permission(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: PermissionArgs = serde_json::from_value(args)?;
- let permissions = state.borrow_mut::<Permissions>();
- let path = args.path.as_deref();
- let perm = match args.name.as_ref() {
- "read" => permissions.revoke_read(&path.as_deref().map(Path::new)),
- "write" => permissions.revoke_write(&path.as_deref().map(Path::new)),
- "net" => permissions.revoke_net(&args.url.as_deref())?,
- "env" => permissions.revoke_env(),
- "run" => permissions.revoke_run(),
- "plugin" => permissions.revoke_plugin(),
- "hrtime" => permissions.revoke_hrtime(),
- n => {
- return Err(custom_error(
- "ReferenceError",
- format!("No such permission name: {}", n),
- ))
- }
- };
- Ok(json!({ "state": perm.to_string() }))
-}
-
-pub fn op_request_permission(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: PermissionArgs = serde_json::from_value(args)?;
- let permissions = state.borrow_mut::<Permissions>();
- let path = args.path.as_deref();
- let perm = match args.name.as_ref() {
- "read" => permissions.request_read(&path.as_deref().map(Path::new)),
- "write" => permissions.request_write(&path.as_deref().map(Path::new)),
- "net" => permissions.request_net(&args.url.as_deref())?,
- "env" => permissions.request_env(),
- "run" => permissions.request_run(),
- "plugin" => permissions.request_plugin(),
- "hrtime" => permissions.request_hrtime(),
- n => {
- return Err(custom_error(
- "ReferenceError",
- format!("No such permission name: {}", n),
- ))
- }
- };
- Ok(json!({ "state": perm.to_string() }))
-}
diff --git a/cli/ops/plugin.rs b/cli/ops/plugin.rs
deleted file mode 100644
index 1f3669b6f..000000000
--- a/cli/ops/plugin.rs
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::metrics::metrics_op;
-use crate::permissions::Permissions;
-use deno_core::error::AnyError;
-use deno_core::futures::prelude::*;
-use deno_core::plugin_api;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::JsRuntime;
-use deno_core::Op;
-use deno_core::OpAsyncFuture;
-use deno_core::OpId;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use dlopen::symbor::Library;
-use serde::Deserialize;
-use std::cell::RefCell;
-use std::path::PathBuf;
-use std::pin::Pin;
-use std::rc::Rc;
-use std::task::Context;
-use std::task::Poll;
-
-pub fn init(rt: &mut JsRuntime) {
- super::reg_json_sync(rt, "op_open_plugin", op_open_plugin);
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct OpenPluginArgs {
- filename: String,
-}
-
-pub fn op_open_plugin(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: OpenPluginArgs = serde_json::from_value(args)?;
- let filename = PathBuf::from(&args.filename);
-
- super::check_unstable(state, "Deno.openPlugin");
- let permissions = state.borrow::<Permissions>();
- permissions.check_plugin(&filename)?;
-
- debug!("Loading Plugin: {:#?}", filename);
- let plugin_lib = Library::open(filename).map(Rc::new)?;
- let plugin_resource = PluginResource::new(&plugin_lib);
-
- let rid;
- let deno_plugin_init;
- {
- rid = state
- .resource_table
- .add("plugin", Box::new(plugin_resource));
- deno_plugin_init = *unsafe {
- state
- .resource_table
- .get::<PluginResource>(rid)
- .unwrap()
- .lib
- .symbol::<plugin_api::InitFn>("deno_plugin_init")
- .unwrap()
- };
- }
-
- let mut interface = PluginInterface::new(state, &plugin_lib);
- deno_plugin_init(&mut interface);
-
- Ok(json!(rid))
-}
-
-struct PluginResource {
- lib: Rc<Library>,
-}
-
-impl PluginResource {
- fn new(lib: &Rc<Library>) -> Self {
- Self { lib: lib.clone() }
- }
-}
-
-struct PluginInterface<'a> {
- state: &'a mut OpState,
- plugin_lib: &'a Rc<Library>,
-}
-
-impl<'a> PluginInterface<'a> {
- fn new(state: &'a mut OpState, plugin_lib: &'a Rc<Library>) -> Self {
- Self { state, plugin_lib }
- }
-}
-
-impl<'a> plugin_api::Interface for PluginInterface<'a> {
- /// Does the same as `core::Isolate::register_op()`, but additionally makes
- /// the registered op dispatcher, as well as the op futures created by it,
- /// keep reference to the plugin `Library` object, so that the plugin doesn't
- /// get unloaded before all its op registrations and the futures created by
- /// them are dropped.
- fn register_op(
- &mut self,
- name: &str,
- dispatch_op_fn: plugin_api::DispatchOpFn,
- ) -> OpId {
- let plugin_lib = self.plugin_lib.clone();
- let plugin_op_fn = move |state_rc: Rc<RefCell<OpState>>,
- mut zero_copy: BufVec| {
- let mut state = state_rc.borrow_mut();
- let mut interface = PluginInterface::new(&mut state, &plugin_lib);
- let op = dispatch_op_fn(&mut interface, &mut zero_copy);
- match op {
- sync_op @ Op::Sync(..) => sync_op,
- Op::Async(fut) => Op::Async(PluginOpAsyncFuture::new(&plugin_lib, fut)),
- Op::AsyncUnref(fut) => {
- Op::AsyncUnref(PluginOpAsyncFuture::new(&plugin_lib, fut))
- }
- _ => unreachable!(),
- }
- };
- self
- .state
- .op_table
- .register_op(name, metrics_op(Box::new(plugin_op_fn)))
- }
-}
-
-struct PluginOpAsyncFuture {
- fut: Option<OpAsyncFuture>,
- _plugin_lib: Rc<Library>,
-}
-
-impl PluginOpAsyncFuture {
- fn new(plugin_lib: &Rc<Library>, fut: OpAsyncFuture) -> Pin<Box<Self>> {
- let wrapped_fut = Self {
- fut: Some(fut),
- _plugin_lib: plugin_lib.clone(),
- };
- Box::pin(wrapped_fut)
- }
-}
-
-impl Future for PluginOpAsyncFuture {
- type Output = <OpAsyncFuture as Future>::Output;
- fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
- self.fut.as_mut().unwrap().poll_unpin(ctx)
- }
-}
-
-impl Drop for PluginOpAsyncFuture {
- fn drop(&mut self) {
- self.fut.take();
- }
-}
diff --git a/cli/ops/process.rs b/cli/ops/process.rs
deleted file mode 100644
index 60a6d5095..000000000
--- a/cli/ops/process.rs
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use super::io::{std_file_resource, StreamResource, StreamResourceHolder};
-use crate::permissions::Permissions;
-use crate::signal::kill;
-use deno_core::error::bad_resource_id;
-use deno_core::error::type_error;
-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::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use serde::Deserialize;
-use std::cell::RefCell;
-use std::rc::Rc;
-use tokio::process::Command;
-
-#[cfg(unix)]
-use std::os::unix::process::ExitStatusExt;
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- super::reg_json_sync(rt, "op_run", op_run);
- super::reg_json_async(rt, "op_run_status", op_run_status);
- super::reg_json_sync(rt, "op_kill", op_kill);
-}
-
-fn clone_file(
- state: &mut OpState,
- rid: u32,
-) -> Result<std::fs::File, AnyError> {
- std_file_resource(state, rid, move |r| match r {
- Ok(std_file) => std_file.try_clone().map_err(AnyError::from),
- Err(_) => Err(bad_resource_id()),
- })
-}
-
-fn subprocess_stdio_map(s: &str) -> Result<std::process::Stdio, AnyError> {
- match s {
- "inherit" => Ok(std::process::Stdio::inherit()),
- "piped" => Ok(std::process::Stdio::piped()),
- "null" => Ok(std::process::Stdio::null()),
- _ => Err(type_error("Invalid resource for stdio")),
- }
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct RunArgs {
- cmd: Vec<String>,
- cwd: Option<String>,
- env: Vec<(String, String)>,
- stdin: String,
- stdout: String,
- stderr: String,
- stdin_rid: u32,
- stdout_rid: u32,
- stderr_rid: u32,
-}
-
-struct ChildResource {
- child: tokio::process::Child,
-}
-
-fn op_run(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let run_args: RunArgs = serde_json::from_value(args)?;
- state.borrow::<Permissions>().check_run()?;
-
- let args = run_args.cmd;
- let env = run_args.env;
- let cwd = run_args.cwd;
-
- let mut c = Command::new(args.get(0).unwrap());
- (1..args.len()).for_each(|i| {
- let arg = args.get(i).unwrap();
- c.arg(arg);
- });
- cwd.map(|d| c.current_dir(d));
- for (key, value) in &env {
- c.env(key, value);
- }
-
- // TODO: make this work with other resources, eg. sockets
- if !run_args.stdin.is_empty() {
- c.stdin(subprocess_stdio_map(run_args.stdin.as_ref())?);
- } else {
- let file = clone_file(state, run_args.stdin_rid)?;
- c.stdin(file);
- }
-
- if !run_args.stdout.is_empty() {
- c.stdout(subprocess_stdio_map(run_args.stdout.as_ref())?);
- } else {
- let file = clone_file(state, run_args.stdout_rid)?;
- c.stdout(file);
- }
-
- if !run_args.stderr.is_empty() {
- c.stderr(subprocess_stdio_map(run_args.stderr.as_ref())?);
- } else {
- let file = clone_file(state, run_args.stderr_rid)?;
- c.stderr(file);
- }
-
- // We want to kill child when it's closed
- c.kill_on_drop(true);
-
- // Spawn the command.
- let mut child = c.spawn()?;
- let pid = child.id();
-
- let stdin_rid = match child.stdin.take() {
- Some(child_stdin) => {
- let rid = state.resource_table.add(
- "childStdin",
- Box::new(StreamResourceHolder::new(StreamResource::ChildStdin(
- child_stdin,
- ))),
- );
- Some(rid)
- }
- None => None,
- };
-
- let stdout_rid = match child.stdout.take() {
- Some(child_stdout) => {
- let rid = state.resource_table.add(
- "childStdout",
- Box::new(StreamResourceHolder::new(StreamResource::ChildStdout(
- child_stdout,
- ))),
- );
- Some(rid)
- }
- None => None,
- };
-
- let stderr_rid = match child.stderr.take() {
- Some(child_stderr) => {
- let rid = state.resource_table.add(
- "childStderr",
- Box::new(StreamResourceHolder::new(StreamResource::ChildStderr(
- child_stderr,
- ))),
- );
- Some(rid)
- }
- None => None,
- };
-
- let child_resource = ChildResource { child };
- let child_rid = state.resource_table.add("child", Box::new(child_resource));
-
- Ok(json!({
- "rid": child_rid,
- "pid": pid,
- "stdinRid": stdin_rid,
- "stdoutRid": stdout_rid,
- "stderrRid": stderr_rid,
- }))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct RunStatusArgs {
- rid: i32,
-}
-
-async fn op_run_status(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: RunStatusArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
-
- {
- let s = state.borrow();
- s.borrow::<Permissions>().check_run()?;
- }
-
- let run_status = poll_fn(|cx| {
- let mut state = state.borrow_mut();
- let child_resource = state
- .resource_table
- .get_mut::<ChildResource>(rid)
- .ok_or_else(bad_resource_id)?;
- let child = &mut child_resource.child;
- child.poll_unpin(cx).map_err(AnyError::from)
- })
- .await?;
-
- let code = run_status.code();
-
- #[cfg(unix)]
- let signal = run_status.signal();
- #[cfg(not(unix))]
- let signal = None;
-
- code
- .or(signal)
- .expect("Should have either an exit code or a signal.");
- let got_signal = signal.is_some();
-
- Ok(json!({
- "gotSignal": got_signal,
- "exitCode": code.unwrap_or(-1),
- "exitSignal": signal.unwrap_or(-1),
- }))
-}
-
-#[derive(Deserialize)]
-struct KillArgs {
- pid: i32,
- signo: i32,
-}
-
-fn op_kill(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.kill");
- state.borrow::<Permissions>().check_run()?;
-
- let args: KillArgs = serde_json::from_value(args)?;
- kill(args.pid, args.signo)?;
- Ok(json!({}))
-}
diff --git a/cli/ops/runtime.rs b/cli/ops/runtime.rs
deleted file mode 100644
index cb3b53d53..000000000
--- a/cli/ops/runtime.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::metrics::Metrics;
-use crate::permissions::Permissions;
-use deno_core::error::AnyError;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::ModuleSpecifier;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-
-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);
- }
- super::reg_json_sync(rt, "op_main_module", op_main_module);
- super::reg_json_sync(rt, "op_metrics", op_metrics);
-}
-
-fn op_main_module(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let main = state.borrow::<ModuleSpecifier>().to_string();
- let main_url = ModuleSpecifier::resolve_url_or_path(&main)?;
- if main_url.as_url().scheme() == "file" {
- let main_path = std::env::current_dir().unwrap().join(main_url.to_string());
- state
- .borrow::<Permissions>()
- .check_read_blind(&main_path, "main_module")?;
- }
- Ok(json!(&main))
-}
-
-fn op_metrics(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let m = state.borrow::<Metrics>();
-
- Ok(json!({
- "opsDispatched": m.ops_dispatched,
- "opsDispatchedSync": m.ops_dispatched_sync,
- "opsDispatchedAsync": m.ops_dispatched_async,
- "opsDispatchedAsyncUnref": m.ops_dispatched_async_unref,
- "opsCompleted": m.ops_completed,
- "opsCompletedSync": m.ops_completed_sync,
- "opsCompletedAsync": m.ops_completed_async,
- "opsCompletedAsyncUnref": m.ops_completed_async_unref,
- "bytesSentControl": m.bytes_sent_control,
- "bytesSentData": m.bytes_sent_data,
- "bytesReceived": m.bytes_received
- }))
-}
-
-pub fn ppid() -> Value {
- #[cfg(windows)]
- {
- // Adopted from rustup:
- // https://github.com/rust-lang/rustup/blob/1.21.1/src/cli/self_update.rs#L1036
- // Copyright Diggory Blake, the Mozilla Corporation, and rustup contributors.
- // Licensed under either of
- // - Apache License, Version 2.0
- // - MIT license
- use std::mem;
- use winapi::shared::minwindef::DWORD;
- use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
- use winapi::um::processthreadsapi::GetCurrentProcessId;
- use winapi::um::tlhelp32::{
- CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32,
- TH32CS_SNAPPROCESS,
- };
- unsafe {
- // Take a snapshot of system processes, one of which is ours
- // and contains our parent's pid
- let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if snapshot == INVALID_HANDLE_VALUE {
- return serde_json::to_value(-1).unwrap();
- }
-
- let mut entry: PROCESSENTRY32 = mem::zeroed();
- entry.dwSize = mem::size_of::<PROCESSENTRY32>() as DWORD;
-
- // Iterate over system processes looking for ours
- let success = Process32First(snapshot, &mut entry);
- if success == 0 {
- CloseHandle(snapshot);
- return serde_json::to_value(-1).unwrap();
- }
-
- let this_pid = GetCurrentProcessId();
- while entry.th32ProcessID != this_pid {
- let success = Process32Next(snapshot, &mut entry);
- if success == 0 {
- CloseHandle(snapshot);
- return serde_json::to_value(-1).unwrap();
- }
- }
- CloseHandle(snapshot);
-
- // FIXME: Using the process ID exposes a race condition
- // wherein the parent process already exited and the OS
- // reassigned its ID.
- let parent_id = entry.th32ParentProcessID;
- serde_json::to_value(parent_id).unwrap()
- }
- }
- #[cfg(not(windows))]
- {
- use std::os::unix::process::parent_id;
- serde_json::to_value(parent_id()).unwrap()
- }
-}
diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs
index 03ba88c76..ec9806e60 100644
--- a/cli/ops/runtime_compiler.rs
+++ b/cli/ops/runtime_compiler.rs
@@ -6,12 +6,12 @@ use crate::media_type::MediaType;
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 deno_runtime::permissions::Permissions;
use std::sync::Arc;
use deno_core::error::AnyError;
@@ -49,9 +49,9 @@ async fn op_compile(
) -> Result<Value, AnyError> {
let args: CompileArgs = serde_json::from_value(args)?;
if args.bundle {
- super::check_unstable2(&state, "Deno.bundle");
+ deno_runtime::ops::check_unstable2(&state, "Deno.bundle");
} else {
- super::check_unstable2(&state, "Deno.compile");
+ deno_runtime::ops::check_unstable2(&state, "Deno.compile");
}
let program_state = state.borrow().borrow::<Arc<ProgramState>>().clone();
let runtime_permissions = {
@@ -113,7 +113,7 @@ async fn op_transpile(
args: Value,
_data: BufVec,
) -> Result<Value, AnyError> {
- super::check_unstable2(&state, "Deno.transpileOnly");
+ deno_runtime::ops::check_unstable2(&state, "Deno.transpileOnly");
let args: TranspileArgs = serde_json::from_value(args)?;
let mut compiler_options = tsc_config::TsConfig::new(json!({
diff --git a/cli/ops/signal.rs b/cli/ops/signal.rs
deleted file mode 100644
index be6bc0a35..000000000
--- a/cli/ops/signal.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::error::AnyError;
-use deno_core::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use std::cell::RefCell;
-use std::rc::Rc;
-
-#[cfg(unix)]
-use deno_core::error::bad_resource_id;
-#[cfg(unix)]
-use deno_core::futures::future::poll_fn;
-#[cfg(unix)]
-use deno_core::serde_json;
-#[cfg(unix)]
-use deno_core::serde_json::json;
-#[cfg(unix)]
-use serde::Deserialize;
-#[cfg(unix)]
-use std::task::Waker;
-#[cfg(unix)]
-use tokio::signal::unix::{signal, Signal, SignalKind};
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- super::reg_json_sync(rt, "op_signal_bind", op_signal_bind);
- super::reg_json_sync(rt, "op_signal_unbind", op_signal_unbind);
- super::reg_json_async(rt, "op_signal_poll", op_signal_poll);
-}
-
-#[cfg(unix)]
-/// The resource for signal stream.
-/// The second element is the waker of polling future.
-pub struct SignalStreamResource(pub Signal, pub Option<Waker>);
-
-#[cfg(unix)]
-#[derive(Deserialize)]
-struct BindSignalArgs {
- signo: i32,
-}
-
-#[cfg(unix)]
-#[derive(Deserialize)]
-struct SignalArgs {
- rid: i32,
-}
-
-#[cfg(unix)]
-fn op_signal_bind(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.signal");
- let args: BindSignalArgs = serde_json::from_value(args)?;
- let rid = state.resource_table.add(
- "signal",
- Box::new(SignalStreamResource(
- signal(SignalKind::from_raw(args.signo)).expect(""),
- None,
- )),
- );
- Ok(json!({
- "rid": rid,
- }))
-}
-
-#[cfg(unix)]
-async fn op_signal_poll(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- super::check_unstable2(&state, "Deno.signal");
- let args: SignalArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
-
- let future = poll_fn(move |cx| {
- let mut state = state.borrow_mut();
- if let Some(mut signal) =
- state.resource_table.get_mut::<SignalStreamResource>(rid)
- {
- signal.1 = Some(cx.waker().clone());
- return signal.0.poll_recv(cx);
- }
- std::task::Poll::Ready(None)
- });
- let result = future.await;
- Ok(json!({ "done": result.is_none() }))
-}
-
-#[cfg(unix)]
-pub fn op_signal_unbind(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.signal");
- let args: SignalArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let resource = state.resource_table.get_mut::<SignalStreamResource>(rid);
- if let Some(signal) = resource {
- if let Some(waker) = &signal.1 {
- // Wakes up the pending poll if exists.
- // This prevents the poll future from getting stuck forever.
- waker.clone().wake();
- }
- }
- state
- .resource_table
- .close(rid)
- .ok_or_else(bad_resource_id)?;
- Ok(json!({}))
-}
-
-#[cfg(not(unix))]
-pub fn op_signal_bind(
- _state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- unimplemented!();
-}
-
-#[cfg(not(unix))]
-fn op_signal_unbind(
- _state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- unimplemented!();
-}
-
-#[cfg(not(unix))]
-async fn op_signal_poll(
- _state: Rc<RefCell<OpState>>,
- _args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- unimplemented!();
-}
diff --git a/cli/ops/timers.rs b/cli/ops/timers.rs
deleted file mode 100644
index 8037fd698..000000000
--- a/cli/ops/timers.rs
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-//! This module helps deno implement timers.
-//!
-//! As an optimization, we want to avoid an expensive calls into rust for every
-//! setTimeout in JavaScript. Thus in //js/timers.ts a data structure is
-//! implemented that calls into Rust for only the smallest timeout. Thus we
-//! only need to be able to start, cancel and await a single timer (or Delay, as Tokio
-//! calls it) for an entire Isolate. This is what is implemented here.
-
-use super::dispatch_minimal::minimal_op;
-use super::dispatch_minimal::MinimalOp;
-use crate::metrics::metrics_op;
-use crate::permissions::Permissions;
-use deno_core::error::type_error;
-use deno_core::error::AnyError;
-use deno_core::futures;
-use deno_core::futures::channel::oneshot;
-use deno_core::futures::FutureExt;
-use deno_core::futures::TryFutureExt;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use serde::Deserialize;
-use std::cell::RefCell;
-use std::future::Future;
-use std::pin::Pin;
-use std::rc::Rc;
-use std::thread::sleep;
-use std::time::Duration;
-use std::time::Instant;
-
-pub type StartTime = Instant;
-
-type TimerFuture = Pin<Box<dyn Future<Output = Result<(), ()>>>>;
-
-#[derive(Default)]
-pub struct GlobalTimer {
- tx: Option<oneshot::Sender<()>>,
- pub future: Option<TimerFuture>,
-}
-
-impl GlobalTimer {
- pub fn cancel(&mut self) {
- if let Some(tx) = self.tx.take() {
- tx.send(()).ok();
- }
- }
-
- pub fn new_timeout(&mut self, deadline: Instant) {
- if self.tx.is_some() {
- self.cancel();
- }
- assert!(self.tx.is_none());
- self.future.take();
-
- let (tx, rx) = oneshot::channel();
- self.tx = Some(tx);
-
- let delay = tokio::time::delay_until(deadline.into());
- let rx = rx
- .map_err(|err| panic!("Unexpected error in receiving channel {:?}", err));
-
- let fut = futures::future::select(delay, rx)
- .then(|_| futures::future::ok(()))
- .boxed_local();
- self.future = Some(fut);
- }
-}
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- {
- let op_state = rt.op_state();
- let mut state = op_state.borrow_mut();
- state.put::<GlobalTimer>(GlobalTimer::default());
- state.put::<StartTime>(StartTime::now());
- }
- super::reg_json_sync(rt, "op_global_timer_stop", op_global_timer_stop);
- super::reg_json_sync(rt, "op_global_timer_start", op_global_timer_start);
- super::reg_json_async(rt, "op_global_timer", op_global_timer);
- rt.register_op("op_now", metrics_op(minimal_op(op_now)));
- super::reg_json_sync(rt, "op_sleep_sync", op_sleep_sync);
-}
-
-fn op_global_timer_stop(
- state: &mut OpState,
- _args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let global_timer = state.borrow_mut::<GlobalTimer>();
- global_timer.cancel();
- Ok(json!({}))
-}
-
-#[derive(Deserialize)]
-struct GlobalTimerArgs {
- timeout: u64,
-}
-
-// Set up a timer that will be later awaited by JS promise.
-// It's a separate op, because canceling a timeout immediately
-// after setting it caused a race condition (because Tokio timeout)
-// might have been registered after next event loop tick.
-//
-// See https://github.com/denoland/deno/issues/7599 for more
-// details.
-fn op_global_timer_start(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: GlobalTimerArgs = serde_json::from_value(args)?;
- let val = args.timeout;
-
- let deadline = Instant::now() + Duration::from_millis(val);
- let global_timer = state.borrow_mut::<GlobalTimer>();
- global_timer.new_timeout(deadline);
- Ok(json!({}))
-}
-
-async fn op_global_timer(
- state: Rc<RefCell<OpState>>,
- _args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let maybe_timer_fut = {
- let mut s = state.borrow_mut();
- let global_timer = s.borrow_mut::<GlobalTimer>();
- global_timer.future.take()
- };
- if let Some(timer_fut) = maybe_timer_fut {
- let _ = timer_fut.await;
- }
- Ok(json!({}))
-}
-
-// Returns a milliseconds and nanoseconds subsec
-// since the start time of the deno runtime.
-// If the High precision flag is not set, the
-// nanoseconds are rounded on 2ms.
-fn op_now(
- state: Rc<RefCell<OpState>>,
- // Arguments are discarded
- _sync: bool,
- _x: i32,
- mut zero_copy: BufVec,
-) -> MinimalOp {
- match zero_copy.len() {
- 0 => return MinimalOp::Sync(Err(type_error("no buffer specified"))),
- 1 => {}
- _ => {
- return MinimalOp::Sync(Err(type_error("Invalid number of arguments")))
- }
- }
-
- let op_state = state.borrow();
- let start_time = op_state.borrow::<StartTime>();
- let seconds = start_time.elapsed().as_secs();
- let mut subsec_nanos = start_time.elapsed().subsec_nanos() as f64;
- let reduced_time_precision = 2_000_000.0; // 2ms in nanoseconds
-
- // If the permission is not enabled
- // Round the nano result on 2 milliseconds
- // see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision
- if op_state.borrow::<Permissions>().check_hrtime().is_err() {
- subsec_nanos -= subsec_nanos % reduced_time_precision;
- }
-
- let result = (seconds * 1_000) as f64 + (subsec_nanos / 1_000_000.0);
-
- (&mut zero_copy[0]).copy_from_slice(&result.to_be_bytes());
-
- MinimalOp::Sync(Ok(0))
-}
-
-#[derive(Deserialize)]
-struct SleepArgs {
- millis: u64,
-}
-
-fn op_sleep_sync(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.sleepSync");
- let args: SleepArgs = serde_json::from_value(args)?;
- sleep(Duration::from_millis(args.millis));
- Ok(json!({}))
-}
diff --git a/cli/ops/tls.rs b/cli/ops/tls.rs
deleted file mode 100644
index 37fd8f206..000000000
--- a/cli/ops/tls.rs
+++ /dev/null
@@ -1,431 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use super::io::{StreamResource, StreamResourceHolder};
-use crate::permissions::Permissions;
-use crate::resolve_addr::resolve_addr;
-use deno_core::error::bad_resource;
-use deno_core::error::bad_resource_id;
-use deno_core::error::custom_error;
-use deno_core::error::AnyError;
-use deno_core::futures;
-use deno_core::futures::future::poll_fn;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use serde::Deserialize;
-use std::cell::RefCell;
-use std::convert::From;
-use std::fs::File;
-use std::io::BufReader;
-use std::net::SocketAddr;
-use std::path::Path;
-use std::rc::Rc;
-use std::sync::Arc;
-use std::task::Context;
-use std::task::Poll;
-use tokio::net::TcpListener;
-use tokio::net::TcpStream;
-use tokio_rustls::{rustls::ClientConfig, TlsConnector};
-use tokio_rustls::{
- rustls::{
- internal::pemfile::{certs, pkcs8_private_keys, rsa_private_keys},
- Certificate, NoClientAuth, PrivateKey, ServerConfig,
- },
- TlsAcceptor,
-};
-use webpki::DNSNameRef;
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- super::reg_json_async(rt, "op_start_tls", op_start_tls);
- super::reg_json_async(rt, "op_connect_tls", op_connect_tls);
- super::reg_json_sync(rt, "op_listen_tls", op_listen_tls);
- super::reg_json_async(rt, "op_accept_tls", op_accept_tls);
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct ConnectTLSArgs {
- transport: String,
- hostname: String,
- port: u16,
- cert_file: Option<String>,
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct StartTLSArgs {
- rid: u32,
- cert_file: Option<String>,
- hostname: String,
-}
-
-async fn op_start_tls(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: StartTLSArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let cert_file = args.cert_file.clone();
-
- let mut domain = args.hostname;
- if domain.is_empty() {
- domain.push_str("localhost");
- }
- {
- super::check_unstable2(&state, "Deno.startTls");
- let s = state.borrow();
- let permissions = s.borrow::<Permissions>();
- permissions.check_net(&domain, 0)?;
- if let Some(path) = cert_file.clone() {
- permissions.check_read(Path::new(&path))?;
- }
- }
- let mut resource_holder = {
- let mut state_ = state.borrow_mut();
- match state_.resource_table.remove::<StreamResourceHolder>(rid) {
- Some(resource) => *resource,
- None => return Err(bad_resource_id()),
- }
- };
-
- if let StreamResource::TcpStream(ref mut tcp_stream) =
- resource_holder.resource
- {
- let tcp_stream = tcp_stream.take().unwrap();
- let local_addr = tcp_stream.local_addr()?;
- let remote_addr = tcp_stream.peer_addr()?;
- let mut config = ClientConfig::new();
- config
- .root_store
- .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
- if let Some(path) = cert_file {
- let key_file = File::open(path)?;
- let reader = &mut BufReader::new(key_file);
- config.root_store.add_pem_file(reader).unwrap();
- }
-
- let tls_connector = TlsConnector::from(Arc::new(config));
- let dnsname =
- DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup");
- let tls_stream = tls_connector.connect(dnsname, tcp_stream).await?;
-
- let rid = {
- let mut state_ = state.borrow_mut();
- state_.resource_table.add(
- "clientTlsStream",
- Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream(
- Box::new(tls_stream),
- ))),
- )
- };
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "hostname": local_addr.ip().to_string(),
- "port": local_addr.port(),
- "transport": "tcp",
- },
- "remoteAddr": {
- "hostname": remote_addr.ip().to_string(),
- "port": remote_addr.port(),
- "transport": "tcp",
- }
- }))
- } else {
- Err(bad_resource_id())
- }
-}
-
-async fn op_connect_tls(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: ConnectTLSArgs = serde_json::from_value(args)?;
- let cert_file = args.cert_file.clone();
- {
- let s = state.borrow();
- let permissions = s.borrow::<Permissions>();
- permissions.check_net(&args.hostname, args.port)?;
- if let Some(path) = cert_file.clone() {
- permissions.check_read(Path::new(&path))?;
- }
- }
- let mut domain = args.hostname.clone();
- if domain.is_empty() {
- domain.push_str("localhost");
- }
-
- let addr = resolve_addr(&args.hostname, args.port)?;
- let tcp_stream = TcpStream::connect(&addr).await?;
- let local_addr = tcp_stream.local_addr()?;
- let remote_addr = tcp_stream.peer_addr()?;
- let mut config = ClientConfig::new();
- config
- .root_store
- .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
- if let Some(path) = cert_file {
- let key_file = File::open(path)?;
- let reader = &mut BufReader::new(key_file);
- config.root_store.add_pem_file(reader).unwrap();
- }
- let tls_connector = TlsConnector::from(Arc::new(config));
- let dnsname =
- DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup");
- let tls_stream = tls_connector.connect(dnsname, tcp_stream).await?;
- let rid = {
- let mut state_ = state.borrow_mut();
- state_.resource_table.add(
- "clientTlsStream",
- Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream(
- Box::new(tls_stream),
- ))),
- )
- };
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "hostname": local_addr.ip().to_string(),
- "port": local_addr.port(),
- "transport": args.transport,
- },
- "remoteAddr": {
- "hostname": remote_addr.ip().to_string(),
- "port": remote_addr.port(),
- "transport": args.transport,
- }
- }))
-}
-
-fn load_certs(path: &str) -> Result<Vec<Certificate>, AnyError> {
- let cert_file = File::open(path)?;
- let reader = &mut BufReader::new(cert_file);
-
- let certs = certs(reader)
- .map_err(|_| custom_error("InvalidData", "Unable to decode certificate"))?;
-
- if certs.is_empty() {
- let e = custom_error("InvalidData", "No certificates found in cert file");
- return Err(e);
- }
-
- Ok(certs)
-}
-
-fn key_decode_err() -> AnyError {
- custom_error("InvalidData", "Unable to decode key")
-}
-
-fn key_not_found_err() -> AnyError {
- custom_error("InvalidData", "No keys found in key file")
-}
-
-/// Starts with -----BEGIN RSA PRIVATE KEY-----
-fn load_rsa_keys(path: &str) -> Result<Vec<PrivateKey>, AnyError> {
- let key_file = File::open(path)?;
- let reader = &mut BufReader::new(key_file);
- let keys = rsa_private_keys(reader).map_err(|_| key_decode_err())?;
- Ok(keys)
-}
-
-/// Starts with -----BEGIN PRIVATE KEY-----
-fn load_pkcs8_keys(path: &str) -> Result<Vec<PrivateKey>, AnyError> {
- let key_file = File::open(path)?;
- let reader = &mut BufReader::new(key_file);
- let keys = pkcs8_private_keys(reader).map_err(|_| key_decode_err())?;
- Ok(keys)
-}
-
-fn load_keys(path: &str) -> Result<Vec<PrivateKey>, AnyError> {
- let path = path.to_string();
- let mut keys = load_rsa_keys(&path)?;
-
- if keys.is_empty() {
- keys = load_pkcs8_keys(&path)?;
- }
-
- if keys.is_empty() {
- return Err(key_not_found_err());
- }
-
- Ok(keys)
-}
-
-#[allow(dead_code)]
-pub struct TlsListenerResource {
- listener: TcpListener,
- tls_acceptor: TlsAcceptor,
- waker: Option<futures::task::AtomicWaker>,
- local_addr: SocketAddr,
-}
-
-impl Drop for TlsListenerResource {
- fn drop(&mut self) {
- self.wake_task();
- }
-}
-
-impl TlsListenerResource {
- /// Track the current task so future awaiting for connection
- /// can be notified when listener is closed.
- ///
- /// Throws an error if another task is already tracked.
- pub fn track_task(&mut self, cx: &Context) -> Result<(), AnyError> {
- // Currently, we only allow tracking a single accept task for a listener.
- // This might be changed in the future with multiple workers.
- // Caveat: TcpListener by itself also only tracks an accept task at a time.
- // See https://github.com/tokio-rs/tokio/issues/846#issuecomment-454208883
- if self.waker.is_some() {
- return Err(custom_error("Busy", "Another accept task is ongoing"));
- }
-
- let waker = futures::task::AtomicWaker::new();
- waker.register(cx.waker());
- self.waker.replace(waker);
- Ok(())
- }
-
- /// Notifies a task when listener is closed so accept future can resolve.
- pub fn wake_task(&mut self) {
- if let Some(waker) = self.waker.as_ref() {
- waker.wake();
- }
- }
-
- /// Stop tracking a task.
- /// Happens when the task is done and thus no further tracking is needed.
- pub fn untrack_task(&mut self) {
- self.waker.take();
- }
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct ListenTlsArgs {
- transport: String,
- hostname: String,
- port: u16,
- cert_file: String,
- key_file: String,
-}
-
-fn op_listen_tls(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: ListenTlsArgs = serde_json::from_value(args)?;
- assert_eq!(args.transport, "tcp");
-
- let cert_file = args.cert_file;
- let key_file = args.key_file;
- {
- let permissions = state.borrow::<Permissions>();
- permissions.check_net(&args.hostname, args.port)?;
- permissions.check_read(Path::new(&cert_file))?;
- permissions.check_read(Path::new(&key_file))?;
- }
- let mut config = ServerConfig::new(NoClientAuth::new());
- config
- .set_single_cert(load_certs(&cert_file)?, load_keys(&key_file)?.remove(0))
- .expect("invalid key or certificate");
- let tls_acceptor = TlsAcceptor::from(Arc::new(config));
- let addr = resolve_addr(&args.hostname, args.port)?;
- let std_listener = std::net::TcpListener::bind(&addr)?;
- let listener = TcpListener::from_std(std_listener)?;
- let local_addr = listener.local_addr()?;
- let tls_listener_resource = TlsListenerResource {
- listener,
- tls_acceptor,
- waker: None,
- local_addr,
- };
-
- let rid = state
- .resource_table
- .add("tlsListener", Box::new(tls_listener_resource));
-
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "hostname": local_addr.ip().to_string(),
- "port": local_addr.port(),
- "transport": args.transport,
- },
- }))
-}
-
-#[derive(Deserialize)]
-struct AcceptTlsArgs {
- rid: i32,
-}
-
-async fn op_accept_tls(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: AcceptTlsArgs = serde_json::from_value(args)?;
- let rid = args.rid as u32;
- let accept_fut = poll_fn(|cx| {
- let mut state = state.borrow_mut();
- let listener_resource = state
- .resource_table
- .get_mut::<TlsListenerResource>(rid)
- .ok_or_else(|| bad_resource("Listener has been closed"))?;
- let listener = &mut listener_resource.listener;
- match listener.poll_accept(cx).map_err(AnyError::from) {
- Poll::Ready(Ok((stream, addr))) => {
- listener_resource.untrack_task();
- Poll::Ready(Ok((stream, addr)))
- }
- Poll::Pending => {
- listener_resource.track_task(cx)?;
- Poll::Pending
- }
- Poll::Ready(Err(e)) => {
- listener_resource.untrack_task();
- Poll::Ready(Err(e))
- }
- }
- });
- let (tcp_stream, _socket_addr) = accept_fut.await?;
- let local_addr = tcp_stream.local_addr()?;
- let remote_addr = tcp_stream.peer_addr()?;
- let tls_acceptor = {
- let state_ = state.borrow();
- let resource = state_
- .resource_table
- .get::<TlsListenerResource>(rid)
- .ok_or_else(bad_resource_id)
- .expect("Can't find tls listener");
- resource.tls_acceptor.clone()
- };
- let tls_stream = tls_acceptor.accept(tcp_stream).await?;
- let rid = {
- let mut state_ = state.borrow_mut();
- state_.resource_table.add(
- "serverTlsStream",
- Box::new(StreamResourceHolder::new(StreamResource::ServerTlsStream(
- Box::new(tls_stream),
- ))),
- )
- };
- Ok(json!({
- "rid": rid,
- "localAddr": {
- "transport": "tcp",
- "hostname": local_addr.ip().to_string(),
- "port": local_addr.port()
- },
- "remoteAddr": {
- "transport": "tcp",
- "hostname": remote_addr.ip().to_string(),
- "port": remote_addr.port()
- }
- }))
-}
diff --git a/cli/ops/tty.rs b/cli/ops/tty.rs
deleted file mode 100644
index be1d7d3e4..000000000
--- a/cli/ops/tty.rs
+++ /dev/null
@@ -1,334 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use super::io::std_file_resource;
-use super::io::StreamResource;
-use super::io::StreamResourceHolder;
-use deno_core::error::bad_resource_id;
-use deno_core::error::last_os_error;
-use deno_core::error::not_supported;
-use deno_core::error::resource_unavailable;
-use deno_core::error::AnyError;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use serde::Deserialize;
-use serde::Serialize;
-
-#[cfg(unix)]
-use nix::sys::termios;
-
-#[cfg(windows)]
-use deno_core::error::custom_error;
-#[cfg(windows)]
-use winapi::shared::minwindef::DWORD;
-#[cfg(windows)]
-use winapi::um::wincon;
-#[cfg(windows)]
-const RAW_MODE_MASK: DWORD = wincon::ENABLE_LINE_INPUT
- | wincon::ENABLE_ECHO_INPUT
- | wincon::ENABLE_PROCESSED_INPUT;
-
-#[cfg(windows)]
-fn get_windows_handle(
- f: &std::fs::File,
-) -> Result<std::os::windows::io::RawHandle, AnyError> {
- use std::os::windows::io::AsRawHandle;
- use winapi::um::handleapi;
-
- let handle = f.as_raw_handle();
- if handle == handleapi::INVALID_HANDLE_VALUE {
- return Err(last_os_error());
- } else if handle.is_null() {
- return Err(custom_error("ReferenceError", "null handle"));
- }
- Ok(handle)
-}
-
-pub fn init(rt: &mut deno_core::JsRuntime) {
- super::reg_json_sync(rt, "op_set_raw", op_set_raw);
- super::reg_json_sync(rt, "op_isatty", op_isatty);
- super::reg_json_sync(rt, "op_console_size", op_console_size);
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct SetRawOptions {
- cbreak: bool,
-}
-
-#[derive(Deserialize)]
-struct SetRawArgs {
- rid: u32,
- mode: bool,
- options: SetRawOptions,
-}
-
-fn op_set_raw(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.setRaw");
-
- let args: SetRawArgs = serde_json::from_value(args)?;
- let rid = args.rid;
- let is_raw = args.mode;
- let cbreak = args.options.cbreak;
-
- // From https://github.com/kkawakam/rustyline/blob/master/src/tty/windows.rs
- // and https://github.com/kkawakam/rustyline/blob/master/src/tty/unix.rs
- // and https://github.com/crossterm-rs/crossterm/blob/e35d4d2c1cc4c919e36d242e014af75f6127ab50/src/terminal/sys/windows.rs
- // Copyright (c) 2015 Katsu Kawakami & Rustyline authors. MIT license.
- // Copyright (c) 2019 Timon. MIT license.
- #[cfg(windows)]
- {
- use std::os::windows::io::AsRawHandle;
- use winapi::shared::minwindef::FALSE;
- use winapi::um::{consoleapi, handleapi};
-
- let resource_holder =
- state.resource_table.get_mut::<StreamResourceHolder>(rid);
- if resource_holder.is_none() {
- return Err(bad_resource_id());
- }
- if cbreak {
- return Err(not_supported());
- }
- let resource_holder = resource_holder.unwrap();
-
- // For now, only stdin.
- let handle = match &mut resource_holder.resource {
- StreamResource::FsFile(ref mut option_file_metadata) => {
- if let Some((tokio_file, metadata)) = option_file_metadata.take() {
- match tokio_file.try_into_std() {
- Ok(std_file) => {
- let raw_handle = std_file.as_raw_handle();
- // Turn the std_file handle back into a tokio file, put it back
- // in the resource table.
- let tokio_file = tokio::fs::File::from_std(std_file);
- resource_holder.resource =
- StreamResource::FsFile(Some((tokio_file, metadata)));
- // return the result.
- raw_handle
- }
- Err(tokio_file) => {
- // This function will return an error containing the file if
- // some operation is in-flight.
- resource_holder.resource =
- StreamResource::FsFile(Some((tokio_file, metadata)));
- return Err(resource_unavailable());
- }
- }
- } else {
- return Err(resource_unavailable());
- }
- }
- _ => {
- return Err(bad_resource_id());
- }
- };
-
- if handle == handleapi::INVALID_HANDLE_VALUE {
- return Err(last_os_error());
- } else if handle.is_null() {
- return Err(custom_error("ReferenceError", "null handle"));
- }
- let mut original_mode: DWORD = 0;
- if unsafe { consoleapi::GetConsoleMode(handle, &mut original_mode) }
- == FALSE
- {
- return Err(last_os_error());
- }
- let new_mode = if is_raw {
- original_mode & !RAW_MODE_MASK
- } else {
- original_mode | RAW_MODE_MASK
- };
- if unsafe { consoleapi::SetConsoleMode(handle, new_mode) } == FALSE {
- return Err(last_os_error());
- }
-
- Ok(json!({}))
- }
- #[cfg(unix)]
- {
- use std::os::unix::io::AsRawFd;
-
- let resource_holder =
- state.resource_table.get_mut::<StreamResourceHolder>(rid);
- if resource_holder.is_none() {
- return Err(bad_resource_id());
- }
-
- if is_raw {
- let (raw_fd, maybe_tty_mode) =
- match &mut resource_holder.unwrap().resource {
- StreamResource::FsFile(Some((f, ref mut metadata))) => {
- (f.as_raw_fd(), &mut metadata.tty.mode)
- }
- StreamResource::FsFile(None) => return Err(resource_unavailable()),
- _ => {
- return Err(not_supported());
- }
- };
-
- if maybe_tty_mode.is_none() {
- // Save original mode.
- let original_mode = termios::tcgetattr(raw_fd)?;
- maybe_tty_mode.replace(original_mode);
- }
-
- let mut raw = maybe_tty_mode.clone().unwrap();
-
- raw.input_flags &= !(termios::InputFlags::BRKINT
- | termios::InputFlags::ICRNL
- | termios::InputFlags::INPCK
- | termios::InputFlags::ISTRIP
- | termios::InputFlags::IXON);
-
- raw.control_flags |= termios::ControlFlags::CS8;
-
- raw.local_flags &= !(termios::LocalFlags::ECHO
- | termios::LocalFlags::ICANON
- | termios::LocalFlags::IEXTEN);
- if !cbreak {
- raw.local_flags &= !(termios::LocalFlags::ISIG);
- }
- raw.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1;
- raw.control_chars[termios::SpecialCharacterIndices::VTIME as usize] = 0;
- termios::tcsetattr(raw_fd, termios::SetArg::TCSADRAIN, &raw)?;
- Ok(json!({}))
- } else {
- // Try restore saved mode.
- let (raw_fd, maybe_tty_mode) =
- match &mut resource_holder.unwrap().resource {
- StreamResource::FsFile(Some((f, ref mut metadata))) => {
- (f.as_raw_fd(), &mut metadata.tty.mode)
- }
- StreamResource::FsFile(None) => {
- return Err(resource_unavailable());
- }
- _ => {
- return Err(bad_resource_id());
- }
- };
-
- if let Some(mode) = maybe_tty_mode.take() {
- termios::tcsetattr(raw_fd, termios::SetArg::TCSADRAIN, &mode)?;
- }
-
- Ok(json!({}))
- }
- }
-}
-
-#[derive(Deserialize)]
-struct IsattyArgs {
- rid: u32,
-}
-
-fn op_isatty(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: IsattyArgs = serde_json::from_value(args)?;
- let rid = args.rid;
-
- let isatty: bool = std_file_resource(state, rid as u32, move |r| match r {
- Ok(std_file) => {
- #[cfg(windows)]
- {
- use winapi::um::consoleapi;
-
- let handle = get_windows_handle(&std_file)?;
- let mut test_mode: DWORD = 0;
- // If I cannot get mode out of console, it is not a console.
- Ok(unsafe { consoleapi::GetConsoleMode(handle, &mut test_mode) != 0 })
- }
- #[cfg(unix)]
- {
- use std::os::unix::io::AsRawFd;
- let raw_fd = std_file.as_raw_fd();
- Ok(unsafe { libc::isatty(raw_fd as libc::c_int) == 1 })
- }
- }
- Err(StreamResource::FsFile(_)) => unreachable!(),
- _ => Ok(false),
- })?;
- Ok(json!(isatty))
-}
-
-#[derive(Deserialize)]
-struct ConsoleSizeArgs {
- rid: u32,
-}
-
-#[derive(Serialize)]
-struct ConsoleSize {
- columns: u32,
- rows: u32,
-}
-
-fn op_console_size(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- super::check_unstable(state, "Deno.consoleSize");
-
- let args: ConsoleSizeArgs = serde_json::from_value(args)?;
- let rid = args.rid;
-
- let size = std_file_resource(state, rid as u32, move |r| match r {
- Ok(std_file) => {
- #[cfg(windows)]
- {
- use std::os::windows::io::AsRawHandle;
- let handle = std_file.as_raw_handle();
-
- unsafe {
- let mut bufinfo: winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO =
- std::mem::zeroed();
-
- if winapi::um::wincon::GetConsoleScreenBufferInfo(
- handle,
- &mut bufinfo,
- ) == 0
- {
- return Err(last_os_error());
- }
-
- Ok(ConsoleSize {
- columns: bufinfo.dwSize.X as u32,
- rows: bufinfo.dwSize.Y as u32,
- })
- }
- }
-
- #[cfg(unix)]
- {
- use std::os::unix::io::AsRawFd;
-
- let fd = std_file.as_raw_fd();
- unsafe {
- let mut size: libc::winsize = std::mem::zeroed();
- if libc::ioctl(fd, libc::TIOCGWINSZ, &mut size as *mut _) != 0 {
- return Err(last_os_error());
- }
-
- // TODO (caspervonb) return a tuple instead
- Ok(ConsoleSize {
- columns: size.ws_col as u32,
- rows: size.ws_row as u32,
- })
- }
- }
- }
- Err(_) => Err(bad_resource_id()),
- })?;
-
- Ok(json!(size))
-}
diff --git a/cli/ops/web_worker.rs b/cli/ops/web_worker.rs
deleted file mode 100644
index d88330a04..000000000
--- a/cli/ops/web_worker.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::web_worker::WebWorkerHandle;
-use crate::web_worker::WorkerEvent;
-use deno_core::futures::channel::mpsc;
-use deno_core::serde_json::json;
-
-pub fn init(
- rt: &mut deno_core::JsRuntime,
- sender: mpsc::Sender<WorkerEvent>,
- handle: WebWorkerHandle,
-) {
- // Post message to host as guest worker.
- let sender_ = sender.clone();
- super::reg_json_sync(
- rt,
- "op_worker_post_message",
- move |_state, _args, bufs| {
- assert_eq!(bufs.len(), 1, "Invalid number of arguments");
- let msg_buf: Box<[u8]> = (*bufs[0]).into();
- sender_
- .clone()
- .try_send(WorkerEvent::Message(msg_buf))
- .expect("Failed to post message to host");
- Ok(json!({}))
- },
- );
-
- // Notify host that guest worker closes.
- super::reg_json_sync(rt, "op_worker_close", move |_state, _args, _bufs| {
- // Notify parent that we're finished
- sender.clone().close_channel();
- // Terminate execution of current worker
- handle.terminate();
- Ok(json!({}))
- });
-}
diff --git a/cli/ops/websocket.rs b/cli/ops/websocket.rs
deleted file mode 100644
index a8c591a33..000000000
--- a/cli/ops/websocket.rs
+++ /dev/null
@@ -1,326 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::permissions::Permissions;
-use core::task::Poll;
-use deno_core::error::bad_resource_id;
-use deno_core::error::type_error;
-use deno_core::error::AnyError;
-use deno_core::futures::future::poll_fn;
-use deno_core::futures::StreamExt;
-use deno_core::futures::{ready, SinkExt};
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::url;
-use deno_core::BufVec;
-use deno_core::OpState;
-use deno_core::{serde_json, ZeroCopyBuf};
-use http::{Method, Request, Uri};
-use serde::Deserialize;
-use std::borrow::Cow;
-use std::cell::RefCell;
-use std::fs::File;
-use std::io::BufReader;
-use std::rc::Rc;
-use std::sync::Arc;
-use tokio::net::TcpStream;
-use tokio_rustls::{rustls::ClientConfig, TlsConnector};
-use tokio_tungstenite::stream::Stream as StreamSwitcher;
-use tokio_tungstenite::tungstenite::Error as TungsteniteError;
-use tokio_tungstenite::tungstenite::{
- handshake::client::Response, protocol::frame::coding::CloseCode,
- protocol::CloseFrame, Message,
-};
-use tokio_tungstenite::{client_async, WebSocketStream};
-use webpki::DNSNameRef;
-
-#[derive(Clone)]
-struct WsCaFile(String);
-#[derive(Clone)]
-struct WsUserAgent(String);
-
-pub fn init(
- rt: &mut deno_core::JsRuntime,
- maybe_ca_file: Option<&str>,
- user_agent: String,
-) {
- {
- 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()));
- }
- state.put::<WsUserAgent>(WsUserAgent(user_agent));
- }
- 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);
- super::reg_json_async(rt, "op_ws_close", op_ws_close);
- super::reg_json_async(rt, "op_ws_next_event", op_ws_next_event);
-}
-
-type MaybeTlsStream =
- StreamSwitcher<TcpStream, tokio_rustls::client::TlsStream<TcpStream>>;
-
-type WsStream = WebSocketStream<MaybeTlsStream>;
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct CheckPermissionArgs {
- url: String,
-}
-
-// This op is needed because creating a WS instance in JavaScript is a sync
-// operation and should throw error when permissions are not fullfiled,
-// but actual op that connects WS is async.
-pub fn op_ws_check_permission(
- state: &mut OpState,
- args: Value,
- _zero_copy: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: CheckPermissionArgs = serde_json::from_value(args)?;
-
- state
- .borrow::<Permissions>()
- .check_net_url(&url::Url::parse(&args.url)?)?;
-
- Ok(json!({}))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct CreateArgs {
- url: String,
- protocols: String,
-}
-
-pub async fn op_ws_create(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _bufs: BufVec,
-) -> Result<Value, AnyError> {
- let args: CreateArgs = serde_json::from_value(args)?;
-
- {
- let s = state.borrow();
- s.borrow::<Permissions>()
- .check_net_url(&url::Url::parse(&args.url)?)
- .expect(
- "Permission check should have been done in op_ws_check_permission",
- );
- }
-
- let maybe_ca_file = state.borrow().try_borrow::<WsCaFile>().cloned();
- let user_agent = state.borrow().borrow::<WsUserAgent>().0.clone();
- let uri: Uri = args.url.parse()?;
- let mut request = Request::builder().method(Method::GET).uri(&uri);
-
- request = request.header("User-Agent", user_agent);
-
- if !args.protocols.is_empty() {
- request = request.header("Sec-WebSocket-Protocol", args.protocols);
- }
-
- let request = request.body(())?;
- let domain = &uri.host().unwrap().to_string();
- let port = &uri.port_u16().unwrap_or(match uri.scheme_str() {
- Some("wss") => 443,
- Some("ws") => 80,
- _ => unreachable!(),
- });
- let addr = format!("{}:{}", domain, port);
- let try_socket = TcpStream::connect(addr).await;
- let tcp_socket = match try_socket.map_err(TungsteniteError::Io) {
- Ok(socket) => socket,
- Err(_) => return Ok(json!({"success": false})),
- };
-
- let socket: MaybeTlsStream = match uri.scheme_str() {
- Some("ws") => StreamSwitcher::Plain(tcp_socket),
- Some("wss") => {
- let mut config = ClientConfig::new();
- config
- .root_store
- .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
-
- 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();
- }
-
- let tls_connector = TlsConnector::from(Arc::new(config));
- let dnsname =
- DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup");
- let tls_socket = tls_connector.connect(dnsname, tcp_socket).await?;
- StreamSwitcher::Tls(tls_socket)
- }
- _ => unreachable!(),
- };
-
- let (stream, response): (WsStream, Response) =
- client_async(request, socket).await.map_err(|err| {
- type_error(format!(
- "failed to connect to WebSocket: {}",
- err.to_string()
- ))
- })?;
-
- let mut state = state.borrow_mut();
- let rid = state
- .resource_table
- .add("webSocketStream", Box::new(stream));
-
- let protocol = match response.headers().get("Sec-WebSocket-Protocol") {
- Some(header) => header.to_str().unwrap(),
- None => "",
- };
- let extensions = response
- .headers()
- .get_all("Sec-WebSocket-Extensions")
- .iter()
- .map(|header| header.to_str().unwrap())
- .collect::<String>();
- Ok(json!({
- "success": true,
- "rid": rid,
- "protocol": protocol,
- "extensions": extensions
- }))
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct SendArgs {
- rid: u32,
- text: Option<String>,
-}
-
-pub async fn op_ws_send(
- state: Rc<RefCell<OpState>>,
- args: Value,
- bufs: BufVec,
-) -> Result<Value, AnyError> {
- let args: SendArgs = serde_json::from_value(args)?;
-
- let mut maybe_msg = Some(match args.text {
- Some(text) => Message::Text(text),
- None => Message::Binary(bufs[0].to_vec()),
- });
- let rid = args.rid;
-
- poll_fn(move |cx| {
- let mut state = state.borrow_mut();
- let stream = state
- .resource_table
- .get_mut::<WsStream>(rid)
- .ok_or_else(bad_resource_id)?;
-
- // TODO(ry) Handle errors below instead of unwrap.
- // Need to map `TungsteniteError` to `AnyError`.
- ready!(stream.poll_ready_unpin(cx)).unwrap();
- if let Some(msg) = maybe_msg.take() {
- stream.start_send_unpin(msg).unwrap();
- }
- ready!(stream.poll_flush_unpin(cx)).unwrap();
-
- Poll::Ready(Ok(json!({})))
- })
- .await
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct CloseArgs {
- rid: u32,
- code: Option<u16>,
- reason: Option<String>,
-}
-
-pub async fn op_ws_close(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _bufs: BufVec,
-) -> Result<Value, AnyError> {
- let args: CloseArgs = serde_json::from_value(args)?;
- let rid = args.rid;
- let mut maybe_msg = Some(Message::Close(args.code.map(|c| CloseFrame {
- code: CloseCode::from(c),
- reason: match args.reason {
- Some(reason) => Cow::from(reason),
- None => Default::default(),
- },
- })));
-
- poll_fn(move |cx| {
- let mut state = state.borrow_mut();
- let stream = state
- .resource_table
- .get_mut::<WsStream>(rid)
- .ok_or_else(bad_resource_id)?;
-
- // TODO(ry) Handle errors below instead of unwrap.
- // Need to map `TungsteniteError` to `AnyError`.
- ready!(stream.poll_ready_unpin(cx)).unwrap();
- if let Some(msg) = maybe_msg.take() {
- stream.start_send_unpin(msg).unwrap();
- }
- ready!(stream.poll_flush_unpin(cx)).unwrap();
- ready!(stream.poll_close_unpin(cx)).unwrap();
-
- Poll::Ready(Ok(json!({})))
- })
- .await
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct NextEventArgs {
- rid: u32,
-}
-
-pub async fn op_ws_next_event(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _bufs: BufVec,
-) -> Result<Value, AnyError> {
- let args: NextEventArgs = serde_json::from_value(args)?;
- poll_fn(move |cx| {
- let mut state = state.borrow_mut();
- let stream = state
- .resource_table
- .get_mut::<WsStream>(args.rid)
- .ok_or_else(bad_resource_id)?;
- stream
- .poll_next_unpin(cx)
- .map(|val| {
- match val {
- Some(Ok(Message::Text(text))) => json!({
- "type": "string",
- "data": text
- }),
- Some(Ok(Message::Binary(data))) => {
- // TODO(ry): don't use json to send binary data.
- json!({
- "type": "binary",
- "data": data
- })
- }
- Some(Ok(Message::Close(Some(frame)))) => json!({
- "type": "close",
- "code": u16::from(frame.code),
- "reason": frame.reason.as_ref()
- }),
- Some(Ok(Message::Close(None))) => json!({ "type": "close" }),
- Some(Ok(Message::Ping(_))) => json!({"type": "ping"}),
- Some(Ok(Message::Pong(_))) => json!({"type": "pong"}),
- Some(Err(_)) => json!({"type": "error"}),
- None => {
- state.resource_table.close(args.rid).unwrap();
- json!({"type": "closed"})
- }
- }
- })
- .map(Ok)
- })
- .await
-}
diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs
deleted file mode 100644
index 871e4b9fe..000000000
--- a/cli/ops/worker_host.rs
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::permissions::Permissions;
-use crate::web_worker::run_web_worker;
-use crate::web_worker::WebWorker;
-use crate::web_worker::WebWorkerHandle;
-use crate::web_worker::WorkerEvent;
-use deno_core::error::generic_error;
-use deno_core::error::AnyError;
-use deno_core::error::JsError;
-use deno_core::futures::channel::mpsc;
-use deno_core::serde_json;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::BufVec;
-use deno_core::ModuleSpecifier;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use serde::Deserialize;
-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,
-}
-
-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(
- rt,
- "op_host_terminate_worker",
- op_host_terminate_worker,
- );
- super::reg_json_sync(rt, "op_host_post_message", op_host_post_message);
- super::reg_json_async(rt, "op_host_get_message", op_host_get_message);
- super::reg_json_sync(
- rt,
- "op_host_unhandled_error",
- move |_state, args, _zero_copy| {
- if let Some(mut sender) = sender.clone() {
- let args: HostUnhandledErrorArgs = serde_json::from_value(args)?;
- sender
- .try_send(WorkerEvent::Error(generic_error(args.message)))
- .expect("Failed to propagate error event to parent worker");
- Ok(json!(true))
- } else {
- Err(generic_error("Cannot be called from main worker."))
- }
- },
- );
-}
-
-pub struct WorkerThread {
- join_handle: JoinHandle<Result<(), AnyError>>,
- worker_handle: WebWorkerHandle,
-}
-
-pub type WorkersTable = HashMap<u32, WorkerThread>;
-pub type WorkerId = u32;
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct CreateWorkerArgs {
- name: Option<String>,
- specifier: String,
- has_source_code: bool,
- source_code: String,
- use_deno_namespace: bool,
-}
-
-/// Create worker as the host
-fn op_create_worker(
- state: &mut OpState,
- args: Value,
- _data: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: CreateWorkerArgs = serde_json::from_value(args)?;
-
- let specifier = args.specifier.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;
- if use_deno_namespace {
- super::check_unstable(state, "Worker.deno");
- }
- 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 (handle_sender, handle_receiver) =
- std::sync::mpsc::sync_channel::<Result<WebWorkerHandle, AnyError>>(1);
-
- // Setup new thread
- let thread_builder =
- std::thread::Builder::new().name(format!("deno-worker-{}", worker_id));
-
- // Spawn it
- let join_handle = thread_builder.spawn(move || {
- // Any error inside this block is terminal:
- // - 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 = (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();
- drop(handle_sender);
-
- // At this point the only method of communication with host
- // is using `worker.internal_channels`.
- //
- // Host can already push messages and interact with worker.
- run_web_worker(worker, module_specifier, maybe_source_code)
- })?;
-
- let worker_handle = handle_receiver.recv().unwrap()?;
-
- let worker_thread = WorkerThread {
- join_handle,
- worker_handle,
- };
-
- // At this point all interactions with worker happen using thread
- // safe handler returned from previous function calls
- state
- .borrow_mut::<WorkersTable>()
- .insert(worker_id, worker_thread);
-
- Ok(json!({ "id": worker_id }))
-}
-
-#[derive(Deserialize)]
-struct WorkerArgs {
- id: i32,
-}
-
-fn op_host_terminate_worker(
- state: &mut OpState,
- args: Value,
- _data: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let args: WorkerArgs = serde_json::from_value(args)?;
- let id = args.id as u32;
- let worker_thread = state
- .borrow_mut::<WorkersTable>()
- .remove(&id)
- .expect("No worker handle found");
- worker_thread.worker_handle.terminate();
- worker_thread
- .join_handle
- .join()
- .expect("Panic in worker thread")
- .expect("Panic in worker event loop");
- Ok(json!({}))
-}
-
-fn serialize_worker_event(event: WorkerEvent) -> Value {
- match event {
- WorkerEvent::Message(buf) => json!({ "type": "msg", "data": buf }),
- WorkerEvent::TerminalError(error) => match error.downcast::<JsError>() {
- Ok(js_error) => json!({
- "type": "terminalError",
- "error": {
- "message": js_error.message,
- "fileName": js_error.script_resource_name,
- "lineNumber": js_error.line_number,
- "columnNumber": js_error.start_column,
- }
- }),
- Err(error) => json!({
- "type": "terminalError",
- "error": {
- "message": error.to_string(),
- }
- }),
- },
- WorkerEvent::Error(error) => match error.downcast::<JsError>() {
- Ok(js_error) => json!({
- "type": "error",
- "error": {
- "message": js_error.message,
- "fileName": js_error.script_resource_name,
- "lineNumber": js_error.line_number,
- "columnNumber": js_error.start_column,
- }
- }),
- Err(error) => json!({
- "type": "error",
- "error": {
- "message": error.to_string(),
- }
- }),
- },
- }
-}
-
-/// Try to remove worker from workers table - NOTE: `Worker.terminate()`
-/// might have been called already meaning that we won't find worker in
-/// table - in that case ignore.
-fn try_remove_and_close(state: Rc<RefCell<OpState>>, id: u32) {
- let mut s = state.borrow_mut();
- let workers = s.borrow_mut::<WorkersTable>();
- if let Some(mut worker_thread) = workers.remove(&id) {
- worker_thread.worker_handle.sender.close_channel();
- worker_thread
- .join_handle
- .join()
- .expect("Worker thread panicked")
- .expect("Panic in worker event loop");
- }
-}
-
-/// Get message from guest worker as host
-async fn op_host_get_message(
- state: Rc<RefCell<OpState>>,
- args: Value,
- _zero_copy: BufVec,
-) -> Result<Value, AnyError> {
- let args: WorkerArgs = serde_json::from_value(args)?;
- let id = args.id as u32;
-
- let worker_handle = {
- let s = state.borrow();
- let workers_table = s.borrow::<WorkersTable>();
- let maybe_handle = workers_table.get(&id);
- if let Some(handle) = maybe_handle {
- handle.worker_handle.clone()
- } else {
- // If handle was not found it means worker has already shutdown
- return Ok(json!({ "type": "close" }));
- }
- };
-
- let maybe_event = worker_handle.get_event().await?;
- if let Some(event) = maybe_event {
- // Terminal error means that worker should be removed from worker table.
- if let WorkerEvent::TerminalError(_) = &event {
- try_remove_and_close(state, id);
- }
- return Ok(serialize_worker_event(event));
- }
-
- // If there was no event from worker it means it has already been closed.
- try_remove_and_close(state, id);
- Ok(json!({ "type": "close" }))
-}
-
-/// Post message to guest worker as host
-fn op_host_post_message(
- state: &mut OpState,
- args: Value,
- data: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- assert_eq!(data.len(), 1, "Invalid number of arguments");
- let args: WorkerArgs = serde_json::from_value(args)?;
- let id = args.id as u32;
- let msg = Vec::from(&*data[0]).into_boxed_slice();
-
- debug!("post message to worker {}", id);
- let worker_thread = state
- .borrow::<WorkersTable>()
- .get(&id)
- .expect("No worker handle found");
- worker_thread.worker_handle.post_message(msg)?;
- Ok(json!({}))
-}
diff --git a/cli/permissions.rs b/cli/permissions.rs
deleted file mode 100644
index cc3ce8242..000000000
--- a/cli/permissions.rs
+++ /dev/null
@@ -1,1095 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::colors;
-use crate::flags::Flags;
-use crate::fs_util::resolve_from_cwd;
-use deno_core::error::custom_error;
-use deno_core::error::uri_error;
-use deno_core::error::AnyError;
-use deno_core::url;
-use deno_core::ModuleSpecifier;
-use serde::Deserialize;
-use std::collections::HashSet;
-use std::env::current_dir;
-use std::fmt;
-use std::hash::Hash;
-#[cfg(not(test))]
-use std::io;
-use std::path::{Path, PathBuf};
-#[cfg(test)]
-use std::sync::atomic::AtomicBool;
-#[cfg(test)]
-use std::sync::atomic::Ordering;
-#[cfg(test)]
-use std::sync::Mutex;
-
-const PERMISSION_EMOJI: &str = "⚠";
-
-/// Tri-state value for storing permission state
-#[derive(PartialEq, Debug, Clone, Copy, Deserialize)]
-pub enum PermissionState {
- Granted = 0,
- Prompt = 1,
- Denied = 2,
-}
-
-impl PermissionState {
- /// Check the permission state.
- fn check(self, msg: &str, flag_name: &str) -> Result<(), AnyError> {
- if self == PermissionState::Granted {
- log_perm_access(msg);
- return Ok(());
- }
- let message = format!("{}, run again with the {} flag", msg, flag_name);
- Err(custom_error("PermissionDenied", message))
- }
-}
-
-impl fmt::Display for PermissionState {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- PermissionState::Granted => f.pad("granted"),
- PermissionState::Prompt => f.pad("prompt"),
- PermissionState::Denied => f.pad("denied"),
- }
- }
-}
-
-impl Default for PermissionState {
- fn default() -> Self {
- PermissionState::Prompt
- }
-}
-
-#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
-pub struct UnaryPermission<T: Eq + Hash> {
- pub global_state: PermissionState,
- pub granted_list: HashSet<T>,
- pub denied_list: HashSet<T>,
-}
-
-#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
-pub struct Permissions {
- pub read: UnaryPermission<PathBuf>,
- pub write: UnaryPermission<PathBuf>,
- pub net: UnaryPermission<String>,
- pub env: PermissionState,
- pub run: PermissionState,
- pub plugin: PermissionState,
- pub hrtime: PermissionState,
-}
-
-fn resolve_fs_allowlist(allowlist: &[PathBuf]) -> HashSet<PathBuf> {
- allowlist
- .iter()
- .map(|raw_path| resolve_from_cwd(Path::new(&raw_path)).unwrap())
- .collect()
-}
-
-impl Permissions {
- pub fn from_flags(flags: &Flags) -> Self {
- fn state_from_flag_bool(flag: bool) -> PermissionState {
- if flag {
- PermissionState::Granted
- } else {
- PermissionState::Prompt
- }
- }
- Self {
- read: UnaryPermission::<PathBuf> {
- global_state: state_from_flag_bool(flags.allow_read),
- granted_list: resolve_fs_allowlist(&flags.read_allowlist),
- ..Default::default()
- },
- write: UnaryPermission::<PathBuf> {
- global_state: state_from_flag_bool(flags.allow_write),
- granted_list: resolve_fs_allowlist(&flags.write_allowlist),
- ..Default::default()
- },
- net: UnaryPermission::<String> {
- global_state: state_from_flag_bool(flags.allow_net),
- granted_list: flags.net_allowlist.iter().cloned().collect(),
- ..Default::default()
- },
- env: state_from_flag_bool(flags.allow_env),
- run: state_from_flag_bool(flags.allow_run),
- plugin: state_from_flag_bool(flags.allow_plugin),
- hrtime: state_from_flag_bool(flags.allow_hrtime),
- }
- }
-
- /// Arbitrary helper. Resolves the path from CWD, and also gets a path that
- /// can be displayed without leaking the CWD when not allowed.
- fn resolved_and_display_path(&self, path: &Path) -> (PathBuf, PathBuf) {
- let resolved_path = resolve_from_cwd(path).unwrap();
- let display_path = if path.is_absolute() {
- path.to_path_buf()
- } else {
- match self
- .query_read(&Some(&current_dir().unwrap()))
- .check("", "")
- {
- Ok(_) => resolved_path.clone(),
- Err(_) => path.to_path_buf(),
- }
- };
- (resolved_path, display_path)
- }
-
- pub fn allow_all() -> Self {
- Self {
- read: UnaryPermission {
- global_state: PermissionState::Granted,
- ..Default::default()
- },
- write: UnaryPermission {
- global_state: PermissionState::Granted,
- ..Default::default()
- },
- net: UnaryPermission {
- global_state: PermissionState::Granted,
- ..Default::default()
- },
- env: PermissionState::Granted,
- run: PermissionState::Granted,
- plugin: PermissionState::Granted,
- hrtime: PermissionState::Granted,
- }
- }
-
- pub fn query_read(&self, path: &Option<&Path>) -> PermissionState {
- let path = path.map(|p| resolve_from_cwd(p).unwrap());
- if self.read.global_state == PermissionState::Denied
- && match path.as_ref() {
- None => true,
- Some(path) => check_path_blocklist(path, &self.read.denied_list),
- }
- {
- return PermissionState::Denied;
- }
- if self.read.global_state == PermissionState::Granted
- || match path.as_ref() {
- None => false,
- Some(path) => check_path_allowlist(path, &self.read.granted_list),
- }
- {
- return PermissionState::Granted;
- }
- PermissionState::Prompt
- }
-
- pub fn query_write(&self, path: &Option<&Path>) -> PermissionState {
- let path = path.map(|p| resolve_from_cwd(p).unwrap());
- if self.write.global_state == PermissionState::Denied
- && match path.as_ref() {
- None => true,
- Some(path) => check_path_blocklist(path, &self.write.denied_list),
- }
- {
- return PermissionState::Denied;
- }
- if self.write.global_state == PermissionState::Granted
- || match path.as_ref() {
- None => false,
- Some(path) => check_path_allowlist(path, &self.write.granted_list),
- }
- {
- return PermissionState::Granted;
- }
- PermissionState::Prompt
- }
-
- pub fn query_net(&self, host: &str, port: Option<u16>) -> PermissionState {
- if self.net.global_state == PermissionState::Denied
- || check_host_and_port_list(host, port, &self.net.denied_list)
- {
- return PermissionState::Denied;
- }
- if self.net.global_state == PermissionState::Granted
- || check_host_and_port_list(host, port, &self.net.granted_list)
- {
- return PermissionState::Granted;
- }
- PermissionState::Prompt
- }
-
- pub fn query_net_url(
- &self,
- url: &Option<&str>,
- ) -> Result<PermissionState, AnyError> {
- if url.is_none() {
- return Ok(self.net.global_state);
- }
- let url: &str = url.unwrap();
- // If url is invalid, then throw a TypeError.
- let parsed = url::Url::parse(url)?;
- // The url may be parsed correctly but still lack a host, i.e. "localhost:235" or "mailto:someone@somewhere.com" or "file:/1.txt"
- // Note that host:port combos are parsed as scheme:path
- if parsed.host().is_none() {
- return Err(custom_error(
- "URIError",
- "invalid urlormat: <scheme>://<host>[:port][/subpath]",
- ));
- }
- Ok(self.query_net(
- &parsed.host().unwrap().to_string(),
- parsed.port_or_known_default(),
- ))
- }
-
- pub fn query_env(&self) -> PermissionState {
- self.env
- }
-
- pub fn query_run(&self) -> PermissionState {
- self.run
- }
-
- pub fn query_plugin(&self) -> PermissionState {
- self.plugin
- }
-
- pub fn query_hrtime(&self) -> PermissionState {
- self.hrtime
- }
-
- pub fn request_read(&mut self, path: &Option<&Path>) -> PermissionState {
- if let Some(path) = path {
- let (resolved_path, display_path) = self.resolved_and_display_path(path);
- let state = self.query_read(&Some(&resolved_path));
- if state == PermissionState::Prompt {
- if permission_prompt(&format!(
- "Deno requests read access to \"{}\"",
- display_path.display()
- )) {
- self
- .read
- .granted_list
- .retain(|path| !path.starts_with(&resolved_path));
- self.read.granted_list.insert(resolved_path);
- return PermissionState::Granted;
- } else {
- self
- .read
- .denied_list
- .retain(|path| !resolved_path.starts_with(path));
- self.read.denied_list.insert(resolved_path);
- self.read.global_state = PermissionState::Denied;
- return PermissionState::Denied;
- }
- }
- state
- } else {
- let state = self.query_read(&None);
- if state == PermissionState::Prompt {
- if permission_prompt("Deno requests read access") {
- self.read.granted_list.clear();
- self.read.global_state = PermissionState::Granted;
- return PermissionState::Granted;
- } else {
- self.read.global_state = PermissionState::Denied;
- return PermissionState::Denied;
- }
- }
- state
- }
- }
-
- pub fn request_write(&mut self, path: &Option<&Path>) -> PermissionState {
- if let Some(path) = path {
- let (resolved_path, display_path) = self.resolved_and_display_path(path);
- let state = self.query_write(&Some(&resolved_path));
- if state == PermissionState::Prompt {
- if permission_prompt(&format!(
- "Deno requests write access to \"{}\"",
- display_path.display()
- )) {
- self
- .write
- .granted_list
- .retain(|path| !path.starts_with(&resolved_path));
- self.write.granted_list.insert(resolved_path);
- return PermissionState::Granted;
- } else {
- self
- .write
- .denied_list
- .retain(|path| !resolved_path.starts_with(path));
- self.write.denied_list.insert(resolved_path);
- self.write.global_state = PermissionState::Denied;
- return PermissionState::Denied;
- }
- }
- state
- } else {
- let state = self.query_write(&None);
- if state == PermissionState::Prompt {
- if permission_prompt("Deno requests write access") {
- self.write.granted_list.clear();
- self.write.global_state = PermissionState::Granted;
- return PermissionState::Granted;
- } else {
- self.write.global_state = PermissionState::Denied;
- return PermissionState::Denied;
- }
- }
- state
- }
- }
-
- pub fn request_net(
- &mut self,
- url: &Option<&str>,
- ) -> Result<PermissionState, AnyError> {
- if let Some(url) = url {
- let state = self.query_net_url(&Some(url))?;
- if state == PermissionState::Prompt {
- if permission_prompt(&format!(
- "Deno requests network access to \"{}\"",
- url
- )) {
- self.net.granted_list.insert(url.to_string());
- return Ok(PermissionState::Granted);
- } else {
- self.net.denied_list.insert(url.to_string());
- self.net.global_state = PermissionState::Denied;
- return Ok(PermissionState::Denied);
- }
- }
- Ok(state)
- } else {
- let state = self.query_net_url(&None)?;
- if state == PermissionState::Prompt {
- if permission_prompt("Deno requests network access") {
- self.net.granted_list.clear();
- self.net.global_state = PermissionState::Granted;
- return Ok(PermissionState::Granted);
- } else {
- self.net.global_state = PermissionState::Denied;
- return Ok(PermissionState::Denied);
- }
- }
- Ok(state)
- }
- }
-
- pub fn request_env(&mut self) -> PermissionState {
- if self.env == PermissionState::Prompt {
- if permission_prompt("Deno requests access to environment variables") {
- self.env = PermissionState::Granted;
- } else {
- self.env = PermissionState::Denied;
- }
- }
- self.env
- }
-
- pub fn request_run(&mut self) -> PermissionState {
- if self.run == PermissionState::Prompt {
- if permission_prompt("Deno requests to access to run a subprocess") {
- self.run = PermissionState::Granted;
- } else {
- self.run = PermissionState::Denied;
- }
- }
- self.run
- }
-
- pub fn request_plugin(&mut self) -> PermissionState {
- if self.plugin == PermissionState::Prompt {
- if permission_prompt("Deno requests to open plugins") {
- self.plugin = PermissionState::Granted;
- } else {
- self.plugin = PermissionState::Denied;
- }
- }
- self.plugin
- }
-
- pub fn request_hrtime(&mut self) -> PermissionState {
- if self.hrtime == PermissionState::Prompt {
- if permission_prompt("Deno requests access to high precision time") {
- self.hrtime = PermissionState::Granted;
- } else {
- self.hrtime = PermissionState::Denied;
- }
- }
- self.hrtime
- }
-
- pub fn revoke_read(&mut self, path: &Option<&Path>) -> PermissionState {
- if let Some(path) = path {
- let path = resolve_from_cwd(path).unwrap();
- self
- .read
- .granted_list
- .retain(|path_| !path_.starts_with(&path));
- } else {
- self.read.granted_list.clear();
- if self.read.global_state == PermissionState::Granted {
- self.read.global_state = PermissionState::Prompt;
- }
- }
- self.query_read(path)
- }
-
- pub fn revoke_write(&mut self, path: &Option<&Path>) -> PermissionState {
- if let Some(path) = path {
- let path = resolve_from_cwd(path).unwrap();
- self
- .write
- .granted_list
- .retain(|path_| !path_.starts_with(&path));
- } else {
- self.write.granted_list.clear();
- if self.write.global_state == PermissionState::Granted {
- self.write.global_state = PermissionState::Prompt;
- }
- }
- self.query_write(path)
- }
-
- pub fn revoke_net(
- &mut self,
- url: &Option<&str>,
- ) -> Result<PermissionState, AnyError> {
- if let Some(url) = url {
- self.net.granted_list.remove(*url);
- } else {
- self.net.granted_list.clear();
- if self.net.global_state == PermissionState::Granted {
- self.net.global_state = PermissionState::Prompt;
- }
- }
- self.query_net_url(url)
- }
-
- pub fn revoke_env(&mut self) -> PermissionState {
- if self.env == PermissionState::Granted {
- self.env = PermissionState::Prompt;
- }
- self.env
- }
-
- pub fn revoke_run(&mut self) -> PermissionState {
- if self.run == PermissionState::Granted {
- self.run = PermissionState::Prompt;
- }
- self.run
- }
-
- pub fn revoke_plugin(&mut self) -> PermissionState {
- if self.plugin == PermissionState::Granted {
- self.plugin = PermissionState::Prompt;
- }
- self.plugin
- }
-
- pub fn revoke_hrtime(&mut self) -> PermissionState {
- if self.hrtime == PermissionState::Granted {
- self.hrtime = PermissionState::Prompt;
- }
- self.hrtime
- }
-
- pub fn check_read(&self, path: &Path) -> Result<(), AnyError> {
- let (resolved_path, display_path) = self.resolved_and_display_path(path);
- self.query_read(&Some(&resolved_path)).check(
- &format!("read access to \"{}\"", display_path.display()),
- "--allow-read",
- )
- }
-
- /// As `check_read()`, but permission error messages will anonymize the path
- /// by replacing it with the given `display`.
- pub fn check_read_blind(
- &self,
- path: &Path,
- display: &str,
- ) -> Result<(), AnyError> {
- let resolved_path = resolve_from_cwd(path).unwrap();
- self
- .query_read(&Some(&resolved_path))
- .check(&format!("read access to <{}>", display), "--allow-read")
- }
-
- pub fn check_write(&self, path: &Path) -> Result<(), AnyError> {
- let (resolved_path, display_path) = self.resolved_and_display_path(path);
- self.query_write(&Some(&resolved_path)).check(
- &format!("write access to \"{}\"", display_path.display()),
- "--allow-write",
- )
- }
-
- pub fn check_net(&self, hostname: &str, port: u16) -> Result<(), AnyError> {
- self.query_net(hostname, Some(port)).check(
- &format!("network access to \"{}:{}\"", hostname, port),
- "--allow-net",
- )
- }
-
- pub fn check_net_url(&self, url: &url::Url) -> Result<(), AnyError> {
- let host = url.host_str().ok_or_else(|| uri_error("missing host"))?;
- self
- .query_net(host, url.port_or_known_default())
- .check(&format!("network access to \"{}\"", url), "--allow-net")
- }
-
- /// A helper function that determines if the module specifier is a local or
- /// remote, and performs a read or net check for the specifier.
- pub fn check_specifier(
- &self,
- specifier: &ModuleSpecifier,
- ) -> Result<(), AnyError> {
- let url = specifier.as_url();
- if url.scheme() == "file" {
- let path = url.to_file_path().unwrap();
- self.check_read(&path)
- } else {
- self.check_net_url(url)
- }
- }
-
- pub fn check_env(&self) -> Result<(), AnyError> {
- self
- .env
- .check("access to environment variables", "--allow-env")
- }
-
- pub fn check_run(&self) -> Result<(), AnyError> {
- self.run.check("access to run a subprocess", "--allow-run")
- }
-
- pub fn check_plugin(&self, path: &Path) -> Result<(), AnyError> {
- let (_, display_path) = self.resolved_and_display_path(path);
- self.plugin.check(
- &format!("access to open a plugin: {}", display_path.display()),
- "--allow-plugin",
- )
- }
-
- pub fn check_hrtime(&self) -> Result<(), AnyError> {
- self
- .hrtime
- .check("access to high precision time", "--allow-hrtime")
- }
-}
-
-impl deno_fetch::FetchPermissions for Permissions {
- fn check_net_url(&self, url: &url::Url) -> Result<(), AnyError> {
- Permissions::check_net_url(self, url)
- }
-
- fn check_read(&self, p: &PathBuf) -> Result<(), AnyError> {
- Permissions::check_read(self, p)
- }
-}
-
-/// Shows the permission prompt and returns the answer according to the user input.
-/// This loops until the user gives the proper input.
-#[cfg(not(test))]
-fn permission_prompt(message: &str) -> bool {
- if !atty::is(atty::Stream::Stdin) || !atty::is(atty::Stream::Stderr) {
- return false;
- };
- let msg = format!(
- "{} {}. Grant? [g/d (g = grant, d = deny)] ",
- PERMISSION_EMOJI, message
- );
- // print to stderr so that if deno is > to a file this is still displayed.
- eprint!("{}", colors::bold(&msg));
- loop {
- let mut input = String::new();
- let stdin = io::stdin();
- let result = stdin.read_line(&mut input);
- if result.is_err() {
- return false;
- };
- let ch = input.chars().next().unwrap();
- match ch.to_ascii_lowercase() {
- 'g' => return true,
- 'd' => return false,
- _ => {
- // If we don't get a recognized option try again.
- let msg_again =
- format!("Unrecognized option '{}' [g/d (g = grant, d = deny)] ", ch);
- eprint!("{}", colors::bold(&msg_again));
- }
- };
- }
-}
-
-#[cfg(test)]
-lazy_static! {
- /// Lock this when you use `set_prompt_result` in a test case.
- static ref PERMISSION_PROMPT_GUARD: Mutex<()> = Mutex::new(());
-}
-
-#[cfg(test)]
-static STUB_PROMPT_VALUE: AtomicBool = AtomicBool::new(true);
-
-#[cfg(test)]
-fn set_prompt_result(value: bool) {
- STUB_PROMPT_VALUE.store(value, Ordering::SeqCst);
-}
-
-// When testing, permission prompt returns the value of STUB_PROMPT_VALUE
-// which we set from the test functions.
-#[cfg(test)]
-fn permission_prompt(_message: &str) -> bool {
- STUB_PROMPT_VALUE.load(Ordering::SeqCst)
-}
-
-fn log_perm_access(message: &str) {
- debug!(
- "{}",
- colors::bold(&format!("{} Granted {}", PERMISSION_EMOJI, message))
- );
-}
-
-fn check_path_allowlist(path: &Path, allowlist: &HashSet<PathBuf>) -> bool {
- for path_ in allowlist {
- if path.starts_with(path_) {
- return true;
- }
- }
- false
-}
-
-fn check_path_blocklist(path: &Path, blocklist: &HashSet<PathBuf>) -> bool {
- for path_ in blocklist {
- if path_.starts_with(path) {
- return true;
- }
- }
- false
-}
-
-fn check_host_and_port_list(
- host: &str,
- port: Option<u16>,
- allowlist: &HashSet<String>,
-) -> bool {
- allowlist.contains(host)
- || (port.is_some()
- && allowlist.contains(&format!("{}:{}", host, port.unwrap())))
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use deno_core::serde_json;
-
- // Creates vector of strings, Vec<String>
- macro_rules! svec {
- ($($x:expr),*) => (vec![$($x.to_string()),*]);
- }
-
- #[test]
- fn check_paths() {
- let allowlist = vec![
- PathBuf::from("/a/specific/dir/name"),
- PathBuf::from("/a/specific"),
- PathBuf::from("/b/c"),
- ];
-
- let perms = Permissions::from_flags(&Flags {
- read_allowlist: allowlist.clone(),
- write_allowlist: allowlist,
- ..Default::default()
- });
-
- // Inside of /a/specific and /a/specific/dir/name
- assert!(perms.check_read(Path::new("/a/specific/dir/name")).is_ok());
- assert!(perms.check_write(Path::new("/a/specific/dir/name")).is_ok());
-
- // Inside of /a/specific but outside of /a/specific/dir/name
- assert!(perms.check_read(Path::new("/a/specific/dir")).is_ok());
- assert!(perms.check_write(Path::new("/a/specific/dir")).is_ok());
-
- // Inside of /a/specific and /a/specific/dir/name
- assert!(perms
- .check_read(Path::new("/a/specific/dir/name/inner"))
- .is_ok());
- assert!(perms
- .check_write(Path::new("/a/specific/dir/name/inner"))
- .is_ok());
-
- // Inside of /a/specific but outside of /a/specific/dir/name
- assert!(perms.check_read(Path::new("/a/specific/other/dir")).is_ok());
- assert!(perms
- .check_write(Path::new("/a/specific/other/dir"))
- .is_ok());
-
- // Exact match with /b/c
- assert!(perms.check_read(Path::new("/b/c")).is_ok());
- assert!(perms.check_write(Path::new("/b/c")).is_ok());
-
- // Sub path within /b/c
- assert!(perms.check_read(Path::new("/b/c/sub/path")).is_ok());
- assert!(perms.check_write(Path::new("/b/c/sub/path")).is_ok());
-
- // Sub path within /b/c, needs normalizing
- assert!(perms
- .check_read(Path::new("/b/c/sub/path/../path/."))
- .is_ok());
- assert!(perms
- .check_write(Path::new("/b/c/sub/path/../path/."))
- .is_ok());
-
- // Inside of /b but outside of /b/c
- assert!(perms.check_read(Path::new("/b/e")).is_err());
- assert!(perms.check_write(Path::new("/b/e")).is_err());
-
- // Inside of /a but outside of /a/specific
- assert!(perms.check_read(Path::new("/a/b")).is_err());
- assert!(perms.check_write(Path::new("/a/b")).is_err());
- }
-
- #[test]
- fn test_check_net() {
- let perms = Permissions::from_flags(&Flags {
- net_allowlist: svec![
- "localhost",
- "deno.land",
- "github.com:3000",
- "127.0.0.1",
- "172.16.0.2:8000",
- "www.github.com:443"
- ],
- ..Default::default()
- });
-
- let domain_tests = vec![
- ("localhost", 1234, true),
- ("deno.land", 0, true),
- ("deno.land", 3000, true),
- ("deno.lands", 0, false),
- ("deno.lands", 3000, false),
- ("github.com", 3000, true),
- ("github.com", 0, false),
- ("github.com", 2000, false),
- ("github.net", 3000, false),
- ("127.0.0.1", 0, true),
- ("127.0.0.1", 3000, true),
- ("127.0.0.2", 0, false),
- ("127.0.0.2", 3000, false),
- ("172.16.0.2", 8000, true),
- ("172.16.0.2", 0, false),
- ("172.16.0.2", 6000, false),
- ("172.16.0.1", 8000, false),
- // Just some random hosts that should err
- ("somedomain", 0, false),
- ("192.168.0.1", 0, false),
- ];
-
- let url_tests = vec![
- // Any protocol + port for localhost should be ok, since we don't specify
- ("http://localhost", true),
- ("https://localhost", true),
- ("https://localhost:4443", true),
- ("tcp://localhost:5000", true),
- ("udp://localhost:6000", true),
- // Correct domain + any port and protocol should be ok incorrect shouldn't
- ("https://deno.land/std/example/welcome.ts", true),
- ("https://deno.land:3000/std/example/welcome.ts", true),
- ("https://deno.lands/std/example/welcome.ts", false),
- ("https://deno.lands:3000/std/example/welcome.ts", false),
- // Correct domain + port should be ok all other combinations should err
- ("https://github.com:3000/denoland/deno", true),
- ("https://github.com/denoland/deno", false),
- ("https://github.com:2000/denoland/deno", false),
- ("https://github.net:3000/denoland/deno", false),
- // Correct ipv4 address + any port should be ok others should err
- ("tcp://127.0.0.1", true),
- ("https://127.0.0.1", true),
- ("tcp://127.0.0.1:3000", true),
- ("https://127.0.0.1:3000", true),
- ("tcp://127.0.0.2", false),
- ("https://127.0.0.2", false),
- ("tcp://127.0.0.2:3000", false),
- ("https://127.0.0.2:3000", false),
- // Correct address + port should be ok all other combinations should err
- ("tcp://172.16.0.2:8000", true),
- ("https://172.16.0.2:8000", true),
- ("tcp://172.16.0.2", false),
- ("https://172.16.0.2", false),
- ("tcp://172.16.0.2:6000", false),
- ("https://172.16.0.2:6000", false),
- ("tcp://172.16.0.1:8000", false),
- ("https://172.16.0.1:8000", false),
- // Testing issue #6531 (Network permissions check doesn't account for well-known default ports) so we dont regress
- ("https://www.github.com:443/robots.txt", true),
- ];
-
- for (url_str, is_ok) in url_tests.iter() {
- let u = url::Url::parse(url_str).unwrap();
- assert_eq!(*is_ok, perms.check_net_url(&u).is_ok());
- }
-
- for (host, port, is_ok) in domain_tests.iter() {
- assert_eq!(*is_ok, perms.check_net(host, *port).is_ok());
- }
- }
-
- #[test]
- fn check_specifiers() {
- let read_allowlist = if cfg!(target_os = "windows") {
- vec![PathBuf::from("C:\\a")]
- } else {
- vec![PathBuf::from("/a")]
- };
- let perms = Permissions::from_flags(&Flags {
- read_allowlist,
- net_allowlist: svec!["localhost"],
- ..Default::default()
- });
-
- let mut fixtures = vec![
- (
- ModuleSpecifier::resolve_url_or_path("http://localhost:4545/mod.ts")
- .unwrap(),
- true,
- ),
- (
- ModuleSpecifier::resolve_url_or_path("http://deno.land/x/mod.ts")
- .unwrap(),
- false,
- ),
- ];
-
- if cfg!(target_os = "windows") {
- fixtures.push((
- ModuleSpecifier::resolve_url_or_path("file:///C:/a/mod.ts").unwrap(),
- true,
- ));
- fixtures.push((
- ModuleSpecifier::resolve_url_or_path("file:///C:/b/mod.ts").unwrap(),
- false,
- ));
- } else {
- fixtures.push((
- ModuleSpecifier::resolve_url_or_path("file:///a/mod.ts").unwrap(),
- true,
- ));
- fixtures.push((
- ModuleSpecifier::resolve_url_or_path("file:///b/mod.ts").unwrap(),
- false,
- ));
- }
-
- for (specifier, expected) in fixtures {
- assert_eq!(perms.check_specifier(&specifier).is_ok(), expected);
- }
- }
-
- #[test]
- fn test_deserialize_perms() {
- let json_perms = r#"
- {
- "read": {
- "global_state": "Granted",
- "granted_list": [],
- "denied_list": []
- },
- "write": {
- "global_state": "Granted",
- "granted_list": [],
- "denied_list": []
- },
- "net": {
- "global_state": "Granted",
- "granted_list": [],
- "denied_list": []
- },
- "env": "Granted",
- "run": "Granted",
- "plugin": "Granted",
- "hrtime": "Granted"
- }
- "#;
- let perms0 = Permissions {
- read: UnaryPermission {
- global_state: PermissionState::Granted,
- ..Default::default()
- },
- write: UnaryPermission {
- global_state: PermissionState::Granted,
- ..Default::default()
- },
- net: UnaryPermission {
- global_state: PermissionState::Granted,
- ..Default::default()
- },
- env: PermissionState::Granted,
- run: PermissionState::Granted,
- hrtime: PermissionState::Granted,
- plugin: PermissionState::Granted,
- };
- let deserialized_perms: Permissions =
- serde_json::from_str(json_perms).unwrap();
- assert_eq!(perms0, deserialized_perms);
- }
-
- #[test]
- fn test_query() {
- let perms1 = Permissions {
- read: UnaryPermission {
- global_state: PermissionState::Granted,
- ..Default::default()
- },
- write: UnaryPermission {
- global_state: PermissionState::Granted,
- ..Default::default()
- },
- net: UnaryPermission {
- global_state: PermissionState::Granted,
- ..Default::default()
- },
- env: PermissionState::Granted,
- run: PermissionState::Granted,
- plugin: PermissionState::Granted,
- hrtime: PermissionState::Granted,
- };
- let perms2 = Permissions {
- read: UnaryPermission {
- global_state: PermissionState::Prompt,
- granted_list: resolve_fs_allowlist(&[PathBuf::from("/foo")]),
- ..Default::default()
- },
- write: UnaryPermission {
- global_state: PermissionState::Prompt,
- granted_list: resolve_fs_allowlist(&[PathBuf::from("/foo")]),
- ..Default::default()
- },
- net: UnaryPermission {
- global_state: PermissionState::Prompt,
- granted_list: ["127.0.0.1:8000".to_string()].iter().cloned().collect(),
- ..Default::default()
- },
- env: PermissionState::Prompt,
- run: PermissionState::Prompt,
- plugin: PermissionState::Prompt,
- hrtime: PermissionState::Prompt,
- };
- #[rustfmt::skip]
- {
- assert_eq!(perms1.query_read(&None), PermissionState::Granted);
- assert_eq!(perms1.query_read(&Some(&Path::new("/foo"))), PermissionState::Granted);
- assert_eq!(perms2.query_read(&None), PermissionState::Prompt);
- assert_eq!(perms2.query_read(&Some(&Path::new("/foo"))), PermissionState::Granted);
- assert_eq!(perms2.query_read(&Some(&Path::new("/foo/bar"))), PermissionState::Granted);
- assert_eq!(perms1.query_write(&None), PermissionState::Granted);
- assert_eq!(perms1.query_write(&Some(&Path::new("/foo"))), PermissionState::Granted);
- assert_eq!(perms2.query_write(&None), PermissionState::Prompt);
- assert_eq!(perms2.query_write(&Some(&Path::new("/foo"))), PermissionState::Granted);
- assert_eq!(perms2.query_write(&Some(&Path::new("/foo/bar"))), PermissionState::Granted);
- assert_eq!(perms1.query_net_url(&None).unwrap(), PermissionState::Granted);
- assert_eq!(perms1.query_net_url(&Some("http://127.0.0.1:8000")).unwrap(), PermissionState::Granted);
- assert_eq!(perms2.query_net_url(&None).unwrap(), PermissionState::Prompt);
- assert_eq!(perms2.query_net_url(&Some("http://127.0.0.1:8000")).unwrap(), PermissionState::Granted);
- assert_eq!(perms1.query_env(), PermissionState::Granted);
- assert_eq!(perms2.query_env(), PermissionState::Prompt);
- assert_eq!(perms1.query_run(), PermissionState::Granted);
- assert_eq!(perms2.query_run(), PermissionState::Prompt);
- assert_eq!(perms1.query_plugin(), PermissionState::Granted);
- assert_eq!(perms2.query_plugin(), PermissionState::Prompt);
- assert_eq!(perms1.query_hrtime(), PermissionState::Granted);
- assert_eq!(perms2.query_hrtime(), PermissionState::Prompt);
- };
- }
-
- #[test]
- fn test_request() {
- let mut perms = Permissions {
- read: UnaryPermission {
- global_state: PermissionState::Prompt,
- ..Default::default()
- },
- write: UnaryPermission {
- global_state: PermissionState::Prompt,
- ..Default::default()
- },
- net: UnaryPermission {
- global_state: PermissionState::Prompt,
- ..Default::default()
- },
- env: PermissionState::Prompt,
- run: PermissionState::Prompt,
- plugin: PermissionState::Prompt,
- hrtime: PermissionState::Prompt,
- };
- #[rustfmt::skip]
- {
- let _guard = PERMISSION_PROMPT_GUARD.lock().unwrap();
- set_prompt_result(true);
- assert_eq!(perms.request_read(&Some(&Path::new("/foo"))), PermissionState::Granted);
- assert_eq!(perms.query_read(&None), PermissionState::Prompt);
- set_prompt_result(false);
- assert_eq!(perms.request_read(&Some(&Path::new("/foo/bar"))), PermissionState::Granted);
- set_prompt_result(false);
- assert_eq!(perms.request_write(&Some(&Path::new("/foo"))), PermissionState::Denied);
- assert_eq!(perms.query_write(&Some(&Path::new("/foo/bar"))), PermissionState::Prompt);
- set_prompt_result(true);
- assert_eq!(perms.request_write(&None), PermissionState::Denied);
- set_prompt_result(true);
- assert_eq!(perms.request_net(&None).unwrap(), PermissionState::Granted);
- set_prompt_result(false);
- assert_eq!(perms.request_net(&Some("http://127.0.0.1:8000")).unwrap(), PermissionState::Granted);
- set_prompt_result(true);
- assert_eq!(perms.request_env(), PermissionState::Granted);
- set_prompt_result(false);
- assert_eq!(perms.request_env(), PermissionState::Granted);
- set_prompt_result(false);
- assert_eq!(perms.request_run(), PermissionState::Denied);
- set_prompt_result(true);
- assert_eq!(perms.request_run(), PermissionState::Denied);
- set_prompt_result(true);
- assert_eq!(perms.request_plugin(), PermissionState::Granted);
- set_prompt_result(false);
- assert_eq!(perms.request_plugin(), PermissionState::Granted);
- set_prompt_result(false);
- assert_eq!(perms.request_hrtime(), PermissionState::Denied);
- set_prompt_result(true);
- assert_eq!(perms.request_hrtime(), PermissionState::Denied);
- };
- }
-
- #[test]
- fn test_revoke() {
- let mut perms = Permissions {
- read: UnaryPermission {
- global_state: PermissionState::Prompt,
- granted_list: resolve_fs_allowlist(&[PathBuf::from("/foo")]),
- ..Default::default()
- },
- write: UnaryPermission {
- global_state: PermissionState::Prompt,
- granted_list: resolve_fs_allowlist(&[PathBuf::from("/foo")]),
- ..Default::default()
- },
- net: UnaryPermission {
- global_state: PermissionState::Denied,
- ..Default::default()
- },
- env: PermissionState::Granted,
- run: PermissionState::Granted,
- plugin: PermissionState::Prompt,
- hrtime: PermissionState::Denied,
- };
- #[rustfmt::skip]
- {
- assert_eq!(perms.revoke_read(&Some(&Path::new("/foo/bar"))), PermissionState::Granted);
- assert_eq!(perms.revoke_read(&Some(&Path::new("/foo"))), PermissionState::Prompt);
- assert_eq!(perms.query_read(&Some(&Path::new("/foo/bar"))), PermissionState::Prompt);
- assert_eq!(perms.revoke_write(&Some(&Path::new("/foo/bar"))), PermissionState::Granted);
- assert_eq!(perms.revoke_write(&None), PermissionState::Prompt);
- assert_eq!(perms.query_write(&Some(&Path::new("/foo/bar"))), PermissionState::Prompt);
- assert_eq!(perms.revoke_net(&None).unwrap(), PermissionState::Denied);
- assert_eq!(perms.revoke_env(), PermissionState::Prompt);
- assert_eq!(perms.revoke_run(), PermissionState::Prompt);
- assert_eq!(perms.revoke_plugin(), PermissionState::Prompt);
- assert_eq!(perms.revoke_hrtime(), PermissionState::Denied);
- };
- }
-}
diff --git a/cli/program_state.rs b/cli/program_state.rs
index 7b86b7de5..223d043ba 100644
--- a/cli/program_state.rs
+++ b/cli/program_state.rs
@@ -7,16 +7,16 @@ use crate::flags;
use crate::http_cache;
use crate::http_util;
use crate::import_map::ImportMap;
-use crate::inspector::InspectorServer;
use crate::lockfile::Lockfile;
use crate::media_type::MediaType;
use crate::module_graph::CheckOptions;
use crate::module_graph::GraphBuilder;
use crate::module_graph::TranspileOptions;
use crate::module_graph::TypeLib;
-use crate::permissions::Permissions;
use crate::source_maps::SourceMapGetter;
use crate::specifier_handler::FetchHandler;
+use deno_runtime::inspector::InspectorServer;
+use deno_runtime::permissions::Permissions;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
diff --git a/cli/resolve_addr.rs b/cli/resolve_addr.rs
deleted file mode 100644
index c3dc52f8f..000000000
--- a/cli/resolve_addr.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::error::AnyError;
-use std::net::SocketAddr;
-use std::net::ToSocketAddrs;
-
-/// Resolve network address. Returns a future.
-pub fn resolve_addr(hostname: &str, port: u16) -> Result<SocketAddr, AnyError> {
- // Default to localhost if given just the port. Example: ":80"
- let addr: &str = if !hostname.is_empty() {
- &hostname
- } else {
- "0.0.0.0"
- };
-
- // If this looks like an ipv6 IP address. Example: "[2001:db8::1]"
- // Then we remove the brackets.
- let addr = if addr.starts_with('[') && addr.ends_with(']') {
- let l = addr.len() - 1;
- addr.get(1..l).unwrap()
- } else {
- addr
- };
- let addr_port_pair = (addr, port);
- let mut iter = addr_port_pair.to_socket_addrs()?;
- Ok(iter.next().unwrap())
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use std::net::Ipv4Addr;
- use std::net::Ipv6Addr;
- use std::net::SocketAddrV4;
- use std::net::SocketAddrV6;
-
- #[test]
- fn resolve_addr1() {
- let expected =
- SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80));
- let actual = resolve_addr("127.0.0.1", 80).unwrap();
- assert_eq!(actual, expected);
- }
-
- #[test]
- fn resolve_addr2() {
- let expected =
- SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 80));
- let actual = resolve_addr("", 80).unwrap();
- assert_eq!(actual, expected);
- }
-
- #[test]
- fn resolve_addr3() {
- let expected =
- SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 1), 25));
- let actual = resolve_addr("192.0.2.1", 25).unwrap();
- assert_eq!(actual, expected);
- }
-
- #[test]
- fn resolve_addr_ipv6() {
- let expected = SocketAddr::V6(SocketAddrV6::new(
- Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1),
- 8080,
- 0,
- 0,
- ));
- let actual = resolve_addr("[2001:db8::1]", 8080).unwrap();
- assert_eq!(actual, expected);
- }
-}
diff --git a/cli/rt/00_bootstrap_namespace.js b/cli/rt/00_bootstrap_namespace.js
deleted file mode 100644
index 514cbe3f0..000000000
--- a/cli/rt/00_bootstrap_namespace.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-// The only purpose of this file is to set up "globalThis.__bootstrap" namespace,
-// that is used by scripts in this directory to reference exports between
-// the files.
-
-// This namespace is removed during runtime bootstrapping process.
-
-globalThis.__bootstrap = globalThis.__bootstrap || {};
diff --git a/cli/rt/01_build.js b/cli/rt/01_build.js
deleted file mode 100644
index 7c1dc817e..000000000
--- a/cli/rt/01_build.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const build = {
- target: "unknown",
- arch: "unknown",
- os: "unknown",
- vendor: "unknown",
- env: undefined,
- };
-
- function setBuildInfo(target) {
- const [arch, vendor, os, env] = target.split("-", 4);
- build.target = target;
- build.arch = arch;
- build.vendor = vendor;
- build.os = os;
- build.env = env;
- Object.freeze(build);
- }
-
- window.__bootstrap.build = {
- build,
- setBuildInfo,
- };
-})(this);
diff --git a/cli/rt/01_colors.js b/cli/rt/01_colors.js
deleted file mode 100644
index 39e4a7a18..000000000
--- a/cli/rt/01_colors.js
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- function code(open, close) {
- return {
- open: `\x1b[${open}m`,
- close: `\x1b[${close}m`,
- regexp: new RegExp(`\\x1b\\[${close}m`, "g"),
- };
- }
-
- function run(str, code) {
- return `${code.open}${str.replace(code.regexp, code.open)}${code.close}`;
- }
-
- function bold(str) {
- return run(str, code(1, 22));
- }
-
- function italic(str) {
- return run(str, code(3, 23));
- }
-
- function yellow(str) {
- return run(str, code(33, 39));
- }
-
- function cyan(str) {
- return run(str, code(36, 39));
- }
-
- function red(str) {
- return run(str, code(31, 39));
- }
-
- function green(str) {
- return run(str, code(32, 39));
- }
-
- function bgRed(str) {
- return run(str, code(41, 49));
- }
-
- function white(str) {
- return run(str, code(37, 39));
- }
-
- function gray(str) {
- return run(str, code(90, 39));
- }
-
- function magenta(str) {
- return run(str, code(35, 39));
- }
-
- function dim(str) {
- return run(str, code(2, 22));
- }
-
- // https://github.com/chalk/ansi-regex/blob/2b56fb0c7a07108e5b54241e8faec160d393aedb/index.js
- const ANSI_PATTERN = new RegExp(
- [
- "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
- "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
- ].join("|"),
- "g",
- );
-
- function stripColor(string) {
- return string.replace(ANSI_PATTERN, "");
- }
-
- function maybeColor(fn) {
- return !(globalThis.Deno?.noColor ?? false) ? fn : (s) => s;
- }
-
- window.__bootstrap.colors = {
- bold,
- italic,
- yellow,
- cyan,
- red,
- green,
- bgRed,
- white,
- gray,
- magenta,
- dim,
- stripColor,
- maybeColor,
- };
-})(this);
diff --git a/cli/rt/01_errors.js b/cli/rt/01_errors.js
deleted file mode 100644
index d5933069b..000000000
--- a/cli/rt/01_errors.js
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- class NotFound extends Error {
- constructor(msg) {
- super(msg);
- this.name = "NotFound";
- }
- }
-
- class PermissionDenied extends Error {
- constructor(msg) {
- super(msg);
- this.name = "PermissionDenied";
- }
- }
-
- class ConnectionRefused extends Error {
- constructor(msg) {
- super(msg);
- this.name = "ConnectionRefused";
- }
- }
-
- class ConnectionReset extends Error {
- constructor(msg) {
- super(msg);
- this.name = "ConnectionReset";
- }
- }
-
- class ConnectionAborted extends Error {
- constructor(msg) {
- super(msg);
- this.name = "ConnectionAborted";
- }
- }
-
- class NotConnected extends Error {
- constructor(msg) {
- super(msg);
- this.name = "NotConnected";
- }
- }
-
- class AddrInUse extends Error {
- constructor(msg) {
- super(msg);
- this.name = "AddrInUse";
- }
- }
-
- class AddrNotAvailable extends Error {
- constructor(msg) {
- super(msg);
- this.name = "AddrNotAvailable";
- }
- }
-
- class BrokenPipe extends Error {
- constructor(msg) {
- super(msg);
- this.name = "BrokenPipe";
- }
- }
-
- class AlreadyExists extends Error {
- constructor(msg) {
- super(msg);
- this.name = "AlreadyExists";
- }
- }
-
- class InvalidData extends Error {
- constructor(msg) {
- super(msg);
- this.name = "InvalidData";
- }
- }
-
- class TimedOut extends Error {
- constructor(msg) {
- super(msg);
- this.name = "TimedOut";
- }
- }
-
- class Interrupted extends Error {
- constructor(msg) {
- super(msg);
- this.name = "Interrupted";
- }
- }
-
- class WriteZero extends Error {
- constructor(msg) {
- super(msg);
- this.name = "WriteZero";
- }
- }
-
- class UnexpectedEof extends Error {
- constructor(msg) {
- super(msg);
- this.name = "UnexpectedEof";
- }
- }
-
- class BadResource extends Error {
- constructor(msg) {
- super(msg);
- this.name = "BadResource";
- }
- }
-
- class Http extends Error {
- constructor(msg) {
- super(msg);
- this.name = "Http";
- }
- }
-
- class Busy extends Error {
- constructor(msg) {
- super(msg);
- this.name = "Busy";
- }
- }
-
- class NotSupported extends Error {
- constructor(msg) {
- super(msg);
- this.name = "NotSupported";
- }
- }
-
- const errors = {
- NotFound,
- PermissionDenied,
- ConnectionRefused,
- ConnectionReset,
- ConnectionAborted,
- NotConnected,
- AddrInUse,
- AddrNotAvailable,
- BrokenPipe,
- AlreadyExists,
- InvalidData,
- TimedOut,
- Interrupted,
- WriteZero,
- UnexpectedEof,
- BadResource,
- Http,
- Busy,
- NotSupported,
- };
-
- window.__bootstrap.errors = {
- errors,
- };
-})(this);
diff --git a/cli/rt/01_internals.js b/cli/rt/01_internals.js
deleted file mode 100644
index eee9eeaf7..000000000
--- a/cli/rt/01_internals.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const internalSymbol = Symbol("Deno.internal");
-
- // The object where all the internal fields for testing will be living.
- const internalObject = {};
-
- // Register a field to internalObject for test access,
- // through Deno[Deno.internal][name].
- function exposeForTest(name, value) {
- Object.defineProperty(internalObject, name, {
- value,
- enumerable: false,
- });
- }
-
- window.__bootstrap.internals = {
- internalSymbol,
- internalObject,
- exposeForTest,
- };
-})(this);
diff --git a/cli/rt/01_version.js b/cli/rt/01_version.js
deleted file mode 100644
index 325e1156f..000000000
--- a/cli/rt/01_version.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const version = {
- deno: "",
- v8: "",
- typescript: "",
- };
-
- function setVersions(
- denoVersion,
- v8Version,
- tsVersion,
- ) {
- version.deno = denoVersion;
- version.v8 = v8Version;
- version.typescript = tsVersion;
-
- Object.freeze(version);
- }
-
- window.__bootstrap.version = {
- version,
- setVersions,
- };
-})(this);
diff --git a/cli/rt/01_web_util.js b/cli/rt/01_web_util.js
deleted file mode 100644
index a9573a71d..000000000
--- a/cli/rt/01_web_util.js
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const illegalConstructorKey = Symbol("illegalConstructorKey");
-
- function requiredArguments(
- name,
- length,
- required,
- ) {
- if (length < required) {
- const errMsg = `${name} requires at least ${required} argument${
- required === 1 ? "" : "s"
- }, but only ${length} present`;
- throw new TypeError(errMsg);
- }
- }
-
- const objectCloneMemo = new WeakMap();
-
- function cloneArrayBuffer(
- srcBuffer,
- srcByteOffset,
- srcLength,
- _cloneConstructor,
- ) {
- // this function fudges the return type but SharedArrayBuffer is disabled for a while anyway
- return srcBuffer.slice(
- srcByteOffset,
- srcByteOffset + srcLength,
- );
- }
-
- /** Clone a value in a similar way to structured cloning. It is similar to a
- * StructureDeserialize(StructuredSerialize(...)). */
- function cloneValue(value) {
- switch (typeof value) {
- case "number":
- case "string":
- case "boolean":
- case "undefined":
- case "bigint":
- return value;
- case "object": {
- if (objectCloneMemo.has(value)) {
- return objectCloneMemo.get(value);
- }
- if (value === null) {
- return value;
- }
- if (value instanceof Date) {
- return new Date(value.valueOf());
- }
- if (value instanceof RegExp) {
- return new RegExp(value);
- }
- if (value instanceof SharedArrayBuffer) {
- return value;
- }
- if (value instanceof ArrayBuffer) {
- const cloned = cloneArrayBuffer(
- value,
- 0,
- value.byteLength,
- ArrayBuffer,
- );
- objectCloneMemo.set(value, cloned);
- return cloned;
- }
- if (ArrayBuffer.isView(value)) {
- const clonedBuffer = cloneValue(value.buffer);
- // Use DataViewConstructor type purely for type-checking, can be a
- // DataView or TypedArray. They use the same constructor signature,
- // only DataView has a length in bytes and TypedArrays use a length in
- // terms of elements, so we adjust for that.
- let length;
- if (value instanceof DataView) {
- length = value.byteLength;
- } else {
- length = value.length;
- }
- return new (value.constructor)(
- clonedBuffer,
- value.byteOffset,
- length,
- );
- }
- if (value instanceof Map) {
- const clonedMap = new Map();
- objectCloneMemo.set(value, clonedMap);
- value.forEach((v, k) => {
- clonedMap.set(cloneValue(k), cloneValue(v));
- });
- return clonedMap;
- }
- if (value instanceof Set) {
- // assumes that cloneValue still takes only one argument
- const clonedSet = new Set([...value].map(cloneValue));
- objectCloneMemo.set(value, clonedSet);
- return clonedSet;
- }
-
- // default for objects
- const clonedObj = {};
- objectCloneMemo.set(value, clonedObj);
- const sourceKeys = Object.getOwnPropertyNames(value);
- for (const key of sourceKeys) {
- clonedObj[key] = cloneValue(value[key]);
- }
- Reflect.setPrototypeOf(clonedObj, Reflect.getPrototypeOf(value));
- return clonedObj;
- }
- case "symbol":
- case "function":
- default:
- throw new DOMException("Uncloneable value in stream", "DataCloneError");
- }
- }
-
- const handlerSymbol = Symbol("eventHandlers");
- function makeWrappedHandler(handler) {
- function wrappedHandler(...args) {
- if (typeof wrappedHandler.handler !== "function") {
- return;
- }
- return wrappedHandler.handler.call(this, ...args);
- }
- wrappedHandler.handler = handler;
- return wrappedHandler;
- }
- function defineEventHandler(emitter, name, defaultValue = undefined) {
- // HTML specification section 8.1.5.1
- Object.defineProperty(emitter, `on${name}`, {
- get() {
- return this[handlerSymbol]?.get(name)?.handler ?? defaultValue;
- },
- set(value) {
- if (!this[handlerSymbol]) {
- this[handlerSymbol] = new Map();
- }
- let handlerWrapper = this[handlerSymbol]?.get(name);
- if (handlerWrapper) {
- handlerWrapper.handler = value;
- } else {
- handlerWrapper = makeWrappedHandler(value);
- this.addEventListener(name, handlerWrapper);
- }
- this[handlerSymbol].set(name, handlerWrapper);
- },
- configurable: true,
- enumerable: true,
- });
- }
- window.__bootstrap.webUtil = {
- illegalConstructorKey,
- requiredArguments,
- defineEventHandler,
- cloneValue,
- };
-})(this);
diff --git a/cli/rt/02_console.js b/cli/rt/02_console.js
deleted file mode 100644
index 971837bd6..000000000
--- a/cli/rt/02_console.js
+++ /dev/null
@@ -1,1732 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const exposeForTest = window.__bootstrap.internals.exposeForTest;
- const colors = window.__bootstrap.colors;
-
- function isInvalidDate(x) {
- return isNaN(x.getTime());
- }
-
- function hasOwnProperty(obj, v) {
- if (obj == null) {
- return false;
- }
- return Object.prototype.hasOwnProperty.call(obj, v);
- }
-
- // Copyright Joyent, Inc. and other Node contributors. MIT license.
- // Forked from Node's lib/internal/cli_table.js
-
- function isTypedArray(x) {
- return ArrayBuffer.isView(x) && !(x instanceof DataView);
- }
-
- const tableChars = {
- middleMiddle: "─",
- rowMiddle: "┌",
- topRight: "┐",
- topLeft: "┌",
- leftMiddle: "├",
- topMiddle: "┬",
- bottomRight: "┘",
- bottomLeft: "└",
- bottomMiddle: "┮",
- rightMiddle: "─",
- left: "│ ",
- right: " │",
- middle: " │ ",
- };
-
- function isFullWidthCodePoint(code) {
- // Code points are partially derived from:
- // http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt
- return (
- code >= 0x1100 &&
- (code <= 0x115f || // Hangul Jamo
- code === 0x2329 || // LEFT-POINTING ANGLE BRACKET
- code === 0x232a || // RIGHT-POINTING ANGLE BRACKET
- // CJK Radicals Supplement .. Enclosed CJK Letters and Months
- (code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) ||
- // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
- (code >= 0x3250 && code <= 0x4dbf) ||
- // CJK Unified Ideographs .. Yi Radicals
- (code >= 0x4e00 && code <= 0xa4c6) ||
- // Hangul Jamo Extended-A
- (code >= 0xa960 && code <= 0xa97c) ||
- // Hangul Syllables
- (code >= 0xac00 && code <= 0xd7a3) ||
- // CJK Compatibility Ideographs
- (code >= 0xf900 && code <= 0xfaff) ||
- // Vertical Forms
- (code >= 0xfe10 && code <= 0xfe19) ||
- // CJK Compatibility Forms .. Small Form Variants
- (code >= 0xfe30 && code <= 0xfe6b) ||
- // Halfwidth and Fullwidth Forms
- (code >= 0xff01 && code <= 0xff60) ||
- (code >= 0xffe0 && code <= 0xffe6) ||
- // Kana Supplement
- (code >= 0x1b000 && code <= 0x1b001) ||
- // Enclosed Ideographic Supplement
- (code >= 0x1f200 && code <= 0x1f251) ||
- // Miscellaneous Symbols and Pictographs 0x1f300 - 0x1f5ff
- // Emoticons 0x1f600 - 0x1f64f
- (code >= 0x1f300 && code <= 0x1f64f) ||
- // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
- (code >= 0x20000 && code <= 0x3fffd))
- );
- }
-
- function getStringWidth(str) {
- str = colors.stripColor(str).normalize("NFC");
- let width = 0;
-
- for (const ch of str) {
- width += isFullWidthCodePoint(ch.codePointAt(0)) ? 2 : 1;
- }
-
- return width;
- }
-
- function renderRow(row, columnWidths) {
- let out = tableChars.left;
- for (let i = 0; i < row.length; i++) {
- const cell = row[i];
- const len = getStringWidth(cell);
- const needed = (columnWidths[i] - len) / 2;
- // round(needed) + ceil(needed) will always add up to the amount
- // of spaces we need while also left justifying the output.
- out += `${" ".repeat(needed)}${cell}${" ".repeat(Math.ceil(needed))}`;
- if (i !== row.length - 1) {
- out += tableChars.middle;
- }
- }
- out += tableChars.right;
- return out;
- }
-
- function cliTable(head, columns) {
- const rows = [];
- const columnWidths = head.map((h) => getStringWidth(h));
- const longestColumn = columns.reduce(
- (n, a) => Math.max(n, a.length),
- 0,
- );
-
- for (let i = 0; i < head.length; i++) {
- const column = columns[i];
- for (let j = 0; j < longestColumn; j++) {
- if (rows[j] === undefined) {
- rows[j] = [];
- }
- const value = (rows[j][i] = hasOwnProperty(column, j) ? column[j] : "");
- const width = columnWidths[i] || 0;
- const counted = getStringWidth(value);
- columnWidths[i] = Math.max(width, counted);
- }
- }
-
- const divider = columnWidths.map((i) =>
- tableChars.middleMiddle.repeat(i + 2)
- );
-
- let result = `${tableChars.topLeft}${divider.join(tableChars.topMiddle)}` +
- `${tableChars.topRight}\n${renderRow(head, columnWidths)}\n` +
- `${tableChars.leftMiddle}${divider.join(tableChars.rowMiddle)}` +
- `${tableChars.rightMiddle}\n`;
-
- for (const row of rows) {
- result += `${renderRow(row, columnWidths)}\n`;
- }
-
- result +=
- `${tableChars.bottomLeft}${divider.join(tableChars.bottomMiddle)}` +
- tableChars.bottomRight;
-
- return result;
- }
- /* End of forked part */
-
- const DEFAULT_INSPECT_OPTIONS = {
- depth: 4,
- indentLevel: 0,
- sorted: false,
- trailingComma: false,
- compact: true,
- iterableLimit: 100,
- showProxy: false,
- colors: false,
- getters: false,
- };
-
- const DEFAULT_INDENT = " "; // Default indent string
-
- const LINE_BREAKING_LENGTH = 80;
- const MIN_GROUP_LENGTH = 6;
- const STR_ABBREVIATE_SIZE = 100;
-
- const PROMISE_STRING_BASE_LENGTH = 12;
-
- class CSI {
- static kClear = "\x1b[1;1H";
- static kClearScreenDown = "\x1b[0J";
- }
-
- function getClassInstanceName(instance) {
- if (typeof instance != "object") {
- return "";
- }
- const constructor = instance?.constructor;
- if (typeof constructor == "function") {
- return constructor.name ?? "";
- }
- return "";
- }
-
- function maybeColor(fn, inspectOptions) {
- return inspectOptions.colors ? fn : (s) => s;
- }
-
- function inspectFunction(value, _ctx) {
- if (customInspect in value && typeof value[customInspect] === "function") {
- try {
- return String(value[customInspect]());
- } catch {
- // pass
- }
- }
- // Might be Function/AsyncFunction/GeneratorFunction/AsyncGeneratorFunction
- let cstrName = Object.getPrototypeOf(value)?.constructor?.name;
- if (!cstrName) {
- // If prototype is removed or broken,
- // use generic 'Function' instead.
- cstrName = "Function";
- }
- if (value.name && value.name !== "anonymous") {
- // from MDN spec
- return `[${cstrName}: ${value.name}]`;
- }
- return `[${cstrName}]`;
- }
-
- function inspectIterable(
- value,
- ctx,
- level,
- options,
- inspectOptions,
- ) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- if (level >= inspectOptions.depth) {
- return cyan(`[${options.typeName}]`);
- }
- ctx.add(value);
-
- const entries = [];
-
- const iter = value.entries();
- let entriesLength = 0;
- const next = () => {
- return iter.next();
- };
- for (const el of iter) {
- if (entriesLength < inspectOptions.iterableLimit) {
- entries.push(
- options.entryHandler(
- el,
- ctx,
- level + 1,
- inspectOptions,
- next.bind(iter),
- ),
- );
- }
- entriesLength++;
- }
- ctx.delete(value);
-
- if (options.sort) {
- entries.sort();
- }
-
- if (entriesLength > inspectOptions.iterableLimit) {
- const nmore = entriesLength - inspectOptions.iterableLimit;
- entries.push(`... ${nmore} more items`);
- }
-
- const iPrefix = `${options.displayName ? options.displayName + " " : ""}`;
-
- const initIndentation = `\n${DEFAULT_INDENT.repeat(level + 1)}`;
- const entryIndentation = `,\n${DEFAULT_INDENT.repeat(level + 1)}`;
- const closingIndentation = `${inspectOptions.trailingComma ? "," : ""}\n${
- DEFAULT_INDENT.repeat(level)
- }`;
-
- let iContent;
- if (options.group && entries.length > MIN_GROUP_LENGTH) {
- const groups = groupEntries(entries, level, value);
- iContent = `${initIndentation}${
- groups.join(entryIndentation)
- }${closingIndentation}`;
- } else {
- iContent = entries.length === 0 ? "" : ` ${entries.join(", ")} `;
- if (
- colors.stripColor(iContent).length > LINE_BREAKING_LENGTH ||
- !inspectOptions.compact
- ) {
- iContent = `${initIndentation}${
- entries.join(entryIndentation)
- }${closingIndentation}`;
- }
- }
-
- return `${iPrefix}${options.delims[0]}${iContent}${options.delims[1]}`;
- }
-
- // Ported from Node.js
- // Copyright Node.js contributors. All rights reserved.
- function groupEntries(
- entries,
- level,
- value,
- iterableLimit = 100,
- ) {
- let totalLength = 0;
- let maxLength = 0;
- let entriesLength = entries.length;
- if (iterableLimit < entriesLength) {
- // This makes sure the "... n more items" part is not taken into account.
- entriesLength--;
- }
- const separatorSpace = 2; // Add 1 for the space and 1 for the separator.
- const dataLen = new Array(entriesLength);
- // Calculate the total length of all output entries and the individual max
- // entries length of all output entries.
- // IN PROGRESS: Colors are being taken into account.
- for (let i = 0; i < entriesLength; i++) {
- // Taking colors into account: removing the ANSI color
- // codes from the string before measuring its length
- const len = colors.stripColor(entries[i]).length;
- dataLen[i] = len;
- totalLength += len + separatorSpace;
- if (maxLength < len) maxLength = len;
- }
- // Add two to `maxLength` as we add a single whitespace character plus a comma
- // in-between two entries.
- const actualMax = maxLength + separatorSpace;
- // Check if at least three entries fit next to each other and prevent grouping
- // of arrays that contains entries of very different length (i.e., if a single
- // entry is longer than 1/5 of all other entries combined). Otherwise the
- // space in-between small entries would be enormous.
- if (
- actualMax * 3 + (level + 1) < LINE_BREAKING_LENGTH &&
- (totalLength / actualMax > 5 || maxLength <= 6)
- ) {
- const approxCharHeights = 2.5;
- const averageBias = Math.sqrt(actualMax - totalLength / entries.length);
- const biasedMax = Math.max(actualMax - 3 - averageBias, 1);
- // Dynamically check how many columns seem possible.
- const columns = Math.min(
- // Ideally a square should be drawn. We expect a character to be about 2.5
- // times as high as wide. This is the area formula to calculate a square
- // which contains n rectangles of size `actualMax * approxCharHeights`.
- // Divide that by `actualMax` to receive the correct number of columns.
- // The added bias increases the columns for short entries.
- Math.round(
- Math.sqrt(approxCharHeights * biasedMax * entriesLength) / biasedMax,
- ),
- // Do not exceed the breakLength.
- Math.floor((LINE_BREAKING_LENGTH - (level + 1)) / actualMax),
- // Limit the columns to a maximum of fifteen.
- 15,
- );
- // Return with the original output if no grouping should happen.
- if (columns <= 1) {
- return entries;
- }
- const tmp = [];
- const maxLineLength = [];
- for (let i = 0; i < columns; i++) {
- let lineMaxLength = 0;
- for (let j = i; j < entries.length; j += columns) {
- if (dataLen[j] > lineMaxLength) lineMaxLength = dataLen[j];
- }
- lineMaxLength += separatorSpace;
- maxLineLength[i] = lineMaxLength;
- }
- let order = "padStart";
- if (value !== undefined) {
- for (let i = 0; i < entries.length; i++) {
- if (
- typeof value[i] !== "number" &&
- typeof value[i] !== "bigint"
- ) {
- order = "padEnd";
- break;
- }
- }
- }
- // Each iteration creates a single line of grouped entries.
- for (let i = 0; i < entriesLength; i += columns) {
- // The last lines may contain less entries than columns.
- const max = Math.min(i + columns, entriesLength);
- let str = "";
- let j = i;
- for (; j < max - 1; j++) {
- const lengthOfColorCodes = entries[j].length - dataLen[j];
- const padding = maxLineLength[j - i] + lengthOfColorCodes;
- str += `${entries[j]}, `[order](padding, " ");
- }
- if (order === "padStart") {
- const lengthOfColorCodes = entries[j].length - dataLen[j];
- const padding = maxLineLength[j - i] +
- lengthOfColorCodes -
- separatorSpace;
- str += entries[j].padStart(padding, " ");
- } else {
- str += entries[j];
- }
- tmp.push(str);
- }
- if (iterableLimit < entries.length) {
- tmp.push(entries[entriesLength]);
- }
- entries = tmp;
- }
- return entries;
- }
-
- function inspectValue(
- value,
- ctx,
- level,
- inspectOptions,
- ) {
- const proxyDetails = core.getProxyDetails(value);
- if (proxyDetails != null) {
- return inspectOptions.showProxy
- ? inspectProxy(proxyDetails, ctx, level, inspectOptions)
- : inspectValue(proxyDetails[0], ctx, level, inspectOptions);
- }
-
- const green = maybeColor(colors.green, inspectOptions);
- const yellow = maybeColor(colors.yellow, inspectOptions);
- const dim = maybeColor(colors.dim, inspectOptions);
- const cyan = maybeColor(colors.cyan, inspectOptions);
- const bold = maybeColor(colors.bold, inspectOptions);
- const red = maybeColor(colors.red, inspectOptions);
-
- switch (typeof value) {
- case "string":
- return green(quoteString(value));
- case "number": // Numbers are yellow
- // Special handling of -0
- return yellow(Object.is(value, -0) ? "-0" : `${value}`);
- case "boolean": // booleans are yellow
- return yellow(String(value));
- case "undefined": // undefined is dim
- return dim(String(value));
- case "symbol": // Symbols are green
- return green(maybeQuoteSymbol(value));
- case "bigint": // Bigints are yellow
- return yellow(`${value}n`);
- case "function": // Function string is cyan
- return cyan(inspectFunction(value, ctx));
- case "object": // null is bold
- if (value === null) {
- return bold("null");
- }
-
- if (ctx.has(value)) {
- // Circular string is cyan
- return cyan("[Circular]");
- }
-
- return inspectObject(value, ctx, level, inspectOptions);
- default:
- // Not implemented is red
- return red("[Not Implemented]");
- }
- }
-
- // We can match Node's quoting behavior exactly by swapping the double quote and
- // single quote in this array. That would give preference to single quotes.
- // However, we prefer double quotes as the default.
- const QUOTES = ['"', "'", "`"];
-
- /** Surround the string in quotes.
- *
- * The quote symbol is chosen by taking the first of the `QUOTES` array which
- * does not occur in the string. If they all occur, settle with `QUOTES[0]`.
- *
- * Insert a backslash before any occurrence of the chosen quote symbol and
- * before any backslash.
- */
- function quoteString(string) {
- const quote = QUOTES.find((c) => !string.includes(c)) ?? QUOTES[0];
- const escapePattern = new RegExp(`(?=[${quote}\\\\])`, "g");
- string = string.replace(escapePattern, "\\");
- string = replaceEscapeSequences(string);
- return `${quote}${string}${quote}`;
- }
-
- // Replace escape sequences that can modify output.
- function replaceEscapeSequences(string) {
- return string
- .replace(/[\b]/g, "\\b")
- .replace(/\f/g, "\\f")
- .replace(/\n/g, "\\n")
- .replace(/\r/g, "\\r")
- .replace(/\t/g, "\\t")
- .replace(/\v/g, "\\v")
- .replace(
- // deno-lint-ignore no-control-regex
- /[\x00-\x1f\x7f-\x9f]/g,
- (c) => "\\x" + c.charCodeAt(0).toString(16).padStart(2, "0"),
- );
- }
-
- // Surround a string with quotes when it is required (e.g the string not a valid identifier).
- function maybeQuoteString(string) {
- if (/^[a-zA-Z_][a-zA-Z_0-9]*$/.test(string)) {
- return replaceEscapeSequences(string);
- }
-
- return quoteString(string);
- }
-
- // Surround a symbol's description in quotes when it is required (e.g the description has non printable characters).
- function maybeQuoteSymbol(symbol) {
- if (symbol.description === undefined) {
- return symbol.toString();
- }
-
- if (/^[a-zA-Z_][a-zA-Z_.0-9]*$/.test(symbol.description)) {
- return symbol.toString();
- }
-
- return `Symbol(${quoteString(symbol.description)})`;
- }
-
- // Print strings when they are inside of arrays or objects with quotes
- function inspectValueWithQuotes(
- value,
- ctx,
- level,
- inspectOptions,
- ) {
- const green = maybeColor(colors.green, inspectOptions);
- switch (typeof value) {
- case "string": {
- const trunc = value.length > STR_ABBREVIATE_SIZE
- ? value.slice(0, STR_ABBREVIATE_SIZE) + "..."
- : value;
- return green(quoteString(trunc)); // Quoted strings are green
- }
- default:
- return inspectValue(value, ctx, level, inspectOptions);
- }
- }
-
- function inspectArray(
- value,
- ctx,
- level,
- inspectOptions,
- ) {
- const dim = maybeColor(colors.dim, inspectOptions);
- const options = {
- typeName: "Array",
- displayName: "",
- delims: ["[", "]"],
- entryHandler: (entry, ctx, level, inspectOptions, next) => {
- const [index, val] = entry;
- let i = index;
- if (!value.hasOwnProperty(i)) {
- i++;
- while (!value.hasOwnProperty(i) && i < value.length) {
- next();
- i++;
- }
- const emptyItems = i - index;
- const ending = emptyItems > 1 ? "s" : "";
- return dim(`<${emptyItems} empty item${ending}>`);
- } else {
- return inspectValueWithQuotes(val, ctx, level, inspectOptions);
- }
- },
- group: inspectOptions.compact,
- sort: false,
- };
- return inspectIterable(value, ctx, level, options, inspectOptions);
- }
-
- function inspectTypedArray(
- typedArrayName,
- value,
- ctx,
- level,
- inspectOptions,
- ) {
- const valueLength = value.length;
- const options = {
- typeName: typedArrayName,
- displayName: `${typedArrayName}(${valueLength})`,
- delims: ["[", "]"],
- entryHandler: (entry, ctx, level, inspectOptions) => {
- const val = entry[1];
- return inspectValueWithQuotes(val, ctx, level + 1, inspectOptions);
- },
- group: inspectOptions.compact,
- sort: false,
- };
- return inspectIterable(value, ctx, level, options, inspectOptions);
- }
-
- function inspectSet(
- value,
- ctx,
- level,
- inspectOptions,
- ) {
- const options = {
- typeName: "Set",
- displayName: "Set",
- delims: ["{", "}"],
- entryHandler: (entry, ctx, level, inspectOptions) => {
- const val = entry[1];
- return inspectValueWithQuotes(val, ctx, level + 1, inspectOptions);
- },
- group: false,
- sort: inspectOptions.sorted,
- };
- return inspectIterable(value, ctx, level, options, inspectOptions);
- }
-
- function inspectMap(
- value,
- ctx,
- level,
- inspectOptions,
- ) {
- const options = {
- typeName: "Map",
- displayName: "Map",
- delims: ["{", "}"],
- entryHandler: (entry, ctx, level, inspectOptions) => {
- const [key, val] = entry;
- return `${
- inspectValueWithQuotes(
- key,
- ctx,
- level + 1,
- inspectOptions,
- )
- } => ${inspectValueWithQuotes(val, ctx, level + 1, inspectOptions)}`;
- },
- group: false,
- sort: inspectOptions.sorted,
- };
- return inspectIterable(
- value,
- ctx,
- level,
- options,
- inspectOptions,
- );
- }
-
- function inspectWeakSet(inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return `WeakSet { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color
- }
-
- function inspectWeakMap(inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return `WeakMap { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color
- }
-
- function inspectDate(value, inspectOptions) {
- // without quotes, ISO format, in magenta like before
- const magenta = maybeColor(colors.magenta, inspectOptions);
- return magenta(isInvalidDate(value) ? "Invalid Date" : value.toISOString());
- }
-
- function inspectRegExp(value, inspectOptions) {
- const red = maybeColor(colors.red, inspectOptions);
- return red(value.toString()); // RegExps are red
- }
-
- function inspectStringObject(value, inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return cyan(`[String: "${value.toString()}"]`); // wrappers are in cyan
- }
-
- function inspectBooleanObject(value, inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return cyan(`[Boolean: ${value.toString()}]`); // wrappers are in cyan
- }
-
- function inspectNumberObject(value, inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return cyan(`[Number: ${value.toString()}]`); // wrappers are in cyan
- }
-
- const PromiseState = {
- Pending: 0,
- Fulfilled: 1,
- Rejected: 2,
- };
-
- function inspectPromise(
- value,
- ctx,
- level,
- inspectOptions,
- ) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- const red = maybeColor(colors.red, inspectOptions);
-
- const [state, result] = core.getPromiseDetails(value);
-
- if (state === PromiseState.Pending) {
- return `Promise { ${cyan("<pending>")} }`;
- }
-
- const prefix = state === PromiseState.Fulfilled
- ? ""
- : `${red("<rejected>")} `;
-
- const str = `${prefix}${
- inspectValueWithQuotes(
- result,
- ctx,
- level + 1,
- inspectOptions,
- )
- }`;
-
- if (str.length + PROMISE_STRING_BASE_LENGTH > LINE_BREAKING_LENGTH) {
- return `Promise {\n${DEFAULT_INDENT.repeat(level + 1)}${str}\n}`;
- }
-
- return `Promise { ${str} }`;
- }
-
- function inspectProxy(
- targetAndHandler,
- ctx,
- level,
- inspectOptions,
- ) {
- return `Proxy ${
- inspectArray(targetAndHandler, ctx, level, inspectOptions)
- }`;
- }
-
- function inspectRawObject(
- value,
- ctx,
- level,
- inspectOptions,
- ) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
-
- if (level >= inspectOptions.depth) {
- return cyan("[Object]"); // wrappers are in cyan
- }
- ctx.add(value);
-
- let baseString;
-
- let shouldShowDisplayName = false;
- let displayName = value[
- Symbol.toStringTag
- ];
- if (!displayName) {
- displayName = getClassInstanceName(value);
- }
- if (
- displayName && displayName !== "Object" && displayName !== "anonymous"
- ) {
- shouldShowDisplayName = true;
- }
-
- const entries = [];
- const stringKeys = Object.keys(value);
- const symbolKeys = Object.getOwnPropertySymbols(value);
- if (inspectOptions.sorted) {
- stringKeys.sort();
- symbolKeys.sort((s1, s2) =>
- (s1.description ?? "").localeCompare(s2.description ?? "")
- );
- }
-
- const red = maybeColor(colors.red, inspectOptions);
-
- for (const key of stringKeys) {
- if (inspectOptions.getters) {
- let propertyValue;
- let error = null;
- try {
- propertyValue = value[key];
- } catch (error_) {
- error = error_;
- }
- const inspectedValue = error == null
- ? inspectValueWithQuotes(
- propertyValue,
- ctx,
- level + 1,
- inspectOptions,
- )
- : red(`[Thrown ${error.name}: ${error.message}]`);
- entries.push(`${maybeQuoteString(key)}: ${inspectedValue}`);
- } else {
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
- if (descriptor.get !== undefined && descriptor.set !== undefined) {
- entries.push(`${maybeQuoteString(key)}: [Getter/Setter]`);
- } else if (descriptor.get !== undefined) {
- entries.push(`${maybeQuoteString(key)}: [Getter]`);
- } else {
- entries.push(
- `${maybeQuoteString(key)}: ${
- inspectValueWithQuotes(value[key], ctx, level + 1, inspectOptions)
- }`,
- );
- }
- }
- }
-
- for (const key of symbolKeys) {
- if (inspectOptions.getters) {
- let propertyValue;
- let error;
- try {
- propertyValue = value[key];
- } catch (error_) {
- error = error_;
- }
- const inspectedValue = error == null
- ? inspectValueWithQuotes(
- propertyValue,
- ctx,
- level + 1,
- inspectOptions,
- )
- : red(`Thrown ${error.name}: ${error.message}`);
- entries.push(`[${maybeQuoteSymbol(key)}]: ${inspectedValue}`);
- } else {
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
- if (descriptor.get !== undefined && descriptor.set !== undefined) {
- entries.push(`[${maybeQuoteSymbol(key)}]: [Getter/Setter]`);
- } else if (descriptor.get !== undefined) {
- entries.push(`[${maybeQuoteSymbol(key)}]: [Getter]`);
- } else {
- entries.push(
- `[${maybeQuoteSymbol(key)}]: ${
- inspectValueWithQuotes(value[key], ctx, level + 1, inspectOptions)
- }`,
- );
- }
- }
- }
-
- // Making sure color codes are ignored when calculating the total length
- const totalLength = entries.length + level +
- colors.stripColor(entries.join("")).length;
-
- ctx.delete(value);
-
- if (entries.length === 0) {
- baseString = "{}";
- } else if (totalLength > LINE_BREAKING_LENGTH || !inspectOptions.compact) {
- const entryIndent = DEFAULT_INDENT.repeat(level + 1);
- const closingIndent = DEFAULT_INDENT.repeat(level);
- baseString = `{\n${entryIndent}${entries.join(`,\n${entryIndent}`)}${
- inspectOptions.trailingComma ? "," : ""
- }\n${closingIndent}}`;
- } else {
- baseString = `{ ${entries.join(", ")} }`;
- }
-
- if (shouldShowDisplayName) {
- baseString = `${displayName} ${baseString}`;
- }
-
- return baseString;
- }
-
- function inspectObject(
- value,
- consoleContext,
- level,
- inspectOptions,
- ) {
- if (customInspect in value && typeof value[customInspect] === "function") {
- try {
- return String(value[customInspect]());
- } catch {
- // pass
- }
- }
- // This non-unique symbol is used to support op_crates, ie.
- // in op_crates/web we don't want to depend on unique "Deno.customInspect"
- // symbol defined in the public API. Internal only, shouldn't be used
- // by users.
- const nonUniqueCustomInspect = Symbol.for("Deno.customInspect");
- if (
- nonUniqueCustomInspect in value &&
- typeof value[nonUniqueCustomInspect] === "function"
- ) {
- try {
- return String(value[nonUniqueCustomInspect]());
- } catch {
- // pass
- }
- }
- if (value instanceof Error) {
- return String(value.stack);
- } else if (Array.isArray(value)) {
- return inspectArray(value, consoleContext, level, inspectOptions);
- } else if (value instanceof Number) {
- return inspectNumberObject(value, inspectOptions);
- } else if (value instanceof Boolean) {
- return inspectBooleanObject(value, inspectOptions);
- } else if (value instanceof String) {
- return inspectStringObject(value, inspectOptions);
- } else if (value instanceof Promise) {
- return inspectPromise(value, consoleContext, level, inspectOptions);
- } else if (value instanceof RegExp) {
- return inspectRegExp(value, inspectOptions);
- } else if (value instanceof Date) {
- return inspectDate(value, inspectOptions);
- } else if (value instanceof Set) {
- return inspectSet(value, consoleContext, level, inspectOptions);
- } else if (value instanceof Map) {
- return inspectMap(value, consoleContext, level, inspectOptions);
- } else if (value instanceof WeakSet) {
- return inspectWeakSet(inspectOptions);
- } else if (value instanceof WeakMap) {
- return inspectWeakMap(inspectOptions);
- } else if (isTypedArray(value)) {
- return inspectTypedArray(
- Object.getPrototypeOf(value).constructor.name,
- value,
- consoleContext,
- level,
- inspectOptions,
- );
- } else {
- // Otherwise, default object formatting
- return inspectRawObject(value, consoleContext, level, inspectOptions);
- }
- }
-
- const colorKeywords = new Map([
- ["black", "#000000"],
- ["silver", "#c0c0c0"],
- ["gray", "#808080"],
- ["white", "#ffffff"],
- ["maroon", "#800000"],
- ["red", "#ff0000"],
- ["purple", "#800080"],
- ["fuchsia", "#ff00ff"],
- ["green", "#008000"],
- ["lime", "#00ff00"],
- ["olive", "#808000"],
- ["yellow", "#ffff00"],
- ["navy", "#000080"],
- ["blue", "#0000ff"],
- ["teal", "#008080"],
- ["aqua", "#00ffff"],
- ["orange", "#ffa500"],
- ["aliceblue", "#f0f8ff"],
- ["antiquewhite", "#faebd7"],
- ["aquamarine", "#7fffd4"],
- ["azure", "#f0ffff"],
- ["beige", "#f5f5dc"],
- ["bisque", "#ffe4c4"],
- ["blanchedalmond", "#ffebcd"],
- ["blueviolet", "#8a2be2"],
- ["brown", "#a52a2a"],
- ["burlywood", "#deb887"],
- ["cadetblue", "#5f9ea0"],
- ["chartreuse", "#7fff00"],
- ["chocolate", "#d2691e"],
- ["coral", "#ff7f50"],
- ["cornflowerblue", "#6495ed"],
- ["cornsilk", "#fff8dc"],
- ["crimson", "#dc143c"],
- ["cyan", "#00ffff"],
- ["darkblue", "#00008b"],
- ["darkcyan", "#008b8b"],
- ["darkgoldenrod", "#b8860b"],
- ["darkgray", "#a9a9a9"],
- ["darkgreen", "#006400"],
- ["darkgrey", "#a9a9a9"],
- ["darkkhaki", "#bdb76b"],
- ["darkmagenta", "#8b008b"],
- ["darkolivegreen", "#556b2f"],
- ["darkorange", "#ff8c00"],
- ["darkorchid", "#9932cc"],
- ["darkred", "#8b0000"],
- ["darksalmon", "#e9967a"],
- ["darkseagreen", "#8fbc8f"],
- ["darkslateblue", "#483d8b"],
- ["darkslategray", "#2f4f4f"],
- ["darkslategrey", "#2f4f4f"],
- ["darkturquoise", "#00ced1"],
- ["darkviolet", "#9400d3"],
- ["deeppink", "#ff1493"],
- ["deepskyblue", "#00bfff"],
- ["dimgray", "#696969"],
- ["dimgrey", "#696969"],
- ["dodgerblue", "#1e90ff"],
- ["firebrick", "#b22222"],
- ["floralwhite", "#fffaf0"],
- ["forestgreen", "#228b22"],
- ["gainsboro", "#dcdcdc"],
- ["ghostwhite", "#f8f8ff"],
- ["gold", "#ffd700"],
- ["goldenrod", "#daa520"],
- ["greenyellow", "#adff2f"],
- ["grey", "#808080"],
- ["honeydew", "#f0fff0"],
- ["hotpink", "#ff69b4"],
- ["indianred", "#cd5c5c"],
- ["indigo", "#4b0082"],
- ["ivory", "#fffff0"],
- ["khaki", "#f0e68c"],
- ["lavender", "#e6e6fa"],
- ["lavenderblush", "#fff0f5"],
- ["lawngreen", "#7cfc00"],
- ["lemonchiffon", "#fffacd"],
- ["lightblue", "#add8e6"],
- ["lightcoral", "#f08080"],
- ["lightcyan", "#e0ffff"],
- ["lightgoldenrodyellow", "#fafad2"],
- ["lightgray", "#d3d3d3"],
- ["lightgreen", "#90ee90"],
- ["lightgrey", "#d3d3d3"],
- ["lightpink", "#ffb6c1"],
- ["lightsalmon", "#ffa07a"],
- ["lightseagreen", "#20b2aa"],
- ["lightskyblue", "#87cefa"],
- ["lightslategray", "#778899"],
- ["lightslategrey", "#778899"],
- ["lightsteelblue", "#b0c4de"],
- ["lightyellow", "#ffffe0"],
- ["limegreen", "#32cd32"],
- ["linen", "#faf0e6"],
- ["magenta", "#ff00ff"],
- ["mediumaquamarine", "#66cdaa"],
- ["mediumblue", "#0000cd"],
- ["mediumorchid", "#ba55d3"],
- ["mediumpurple", "#9370db"],
- ["mediumseagreen", "#3cb371"],
- ["mediumslateblue", "#7b68ee"],
- ["mediumspringgreen", "#00fa9a"],
- ["mediumturquoise", "#48d1cc"],
- ["mediumvioletred", "#c71585"],
- ["midnightblue", "#191970"],
- ["mintcream", "#f5fffa"],
- ["mistyrose", "#ffe4e1"],
- ["moccasin", "#ffe4b5"],
- ["navajowhite", "#ffdead"],
- ["oldlace", "#fdf5e6"],
- ["olivedrab", "#6b8e23"],
- ["orangered", "#ff4500"],
- ["orchid", "#da70d6"],
- ["palegoldenrod", "#eee8aa"],
- ["palegreen", "#98fb98"],
- ["paleturquoise", "#afeeee"],
- ["palevioletred", "#db7093"],
- ["papayawhip", "#ffefd5"],
- ["peachpuff", "#ffdab9"],
- ["peru", "#cd853f"],
- ["pink", "#ffc0cb"],
- ["plum", "#dda0dd"],
- ["powderblue", "#b0e0e6"],
- ["rosybrown", "#bc8f8f"],
- ["royalblue", "#4169e1"],
- ["saddlebrown", "#8b4513"],
- ["salmon", "#fa8072"],
- ["sandybrown", "#f4a460"],
- ["seagreen", "#2e8b57"],
- ["seashell", "#fff5ee"],
- ["sienna", "#a0522d"],
- ["skyblue", "#87ceeb"],
- ["slateblue", "#6a5acd"],
- ["slategray", "#708090"],
- ["slategrey", "#708090"],
- ["snow", "#fffafa"],
- ["springgreen", "#00ff7f"],
- ["steelblue", "#4682b4"],
- ["tan", "#d2b48c"],
- ["thistle", "#d8bfd8"],
- ["tomato", "#ff6347"],
- ["turquoise", "#40e0d0"],
- ["violet", "#ee82ee"],
- ["wheat", "#f5deb3"],
- ["whitesmoke", "#f5f5f5"],
- ["yellowgreen", "#9acd32"],
- ["rebeccapurple", "#663399"],
- ]);
-
- function parseCssColor(colorString) {
- if (colorKeywords.has(colorString)) {
- colorString = colorKeywords.get(colorString);
- }
- // deno-fmt-ignore
- const hashMatch = colorString.match(/^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})?$/);
- if (hashMatch != null) {
- return [
- Number(`0x${hashMatch[1]}`),
- Number(`0x${hashMatch[2]}`),
- Number(`0x${hashMatch[3]}`),
- ];
- }
- // deno-fmt-ignore
- const smallHashMatch = colorString.match(/^#([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])?$/);
- if (smallHashMatch != null) {
- return [
- Number(`0x${smallHashMatch[1]}0`),
- Number(`0x${smallHashMatch[2]}0`),
- Number(`0x${smallHashMatch[3]}0`),
- ];
- }
- // deno-fmt-ignore
- const rgbMatch = colorString.match(/^rgba?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
- if (rgbMatch != null) {
- return [
- Math.round(Math.max(0, Math.min(255, Number(rgbMatch[1])))),
- Math.round(Math.max(0, Math.min(255, Number(rgbMatch[2])))),
- Math.round(Math.max(0, Math.min(255, Number(rgbMatch[3])))),
- ];
- }
- // deno-fmt-ignore
- const hslMatch = colorString.match(/^hsla?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)%\s*,\s*([+\-]?\d*\.?\d+)%\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
- if (hslMatch != null) {
- // https://www.rapidtables.com/convert/color/hsl-to-rgb.html
- let h = Number(hslMatch[1]) % 360;
- if (h < 0) {
- h += 360;
- }
- const s = Math.max(0, Math.min(100, Number(hslMatch[2]))) / 100;
- const l = Math.max(0, Math.min(100, Number(hslMatch[3]))) / 100;
- const c = (1 - Math.abs(2 * l - 1)) * s;
- const x = c * (1 - Math.abs((h / 60) % 2 - 1));
- const m = l - c / 2;
- let r_;
- let g_;
- let b_;
- if (h < 60) {
- [r_, g_, b_] = [c, x, 0];
- } else if (h < 120) {
- [r_, g_, b_] = [x, c, 0];
- } else if (h < 180) {
- [r_, g_, b_] = [0, c, x];
- } else if (h < 240) {
- [r_, g_, b_] = [0, x, c];
- } else if (h < 300) {
- [r_, g_, b_] = [x, 0, c];
- } else {
- [r_, g_, b_] = [c, 0, x];
- }
- return [
- Math.round((r_ + m) * 255),
- Math.round((g_ + m) * 255),
- Math.round((b_ + m) * 255),
- ];
- }
- return null;
- }
-
- function getDefaultCss() {
- return {
- backgroundColor: null,
- color: null,
- fontWeight: null,
- fontStyle: null,
- textDecorationColor: null,
- textDecorationLine: [],
- };
- }
-
- function parseCss(cssString) {
- const css = getDefaultCss();
-
- const rawEntries = [];
- let inValue = false;
- let currentKey = null;
- let parenthesesDepth = 0;
- let currentPart = "";
- for (let i = 0; i < cssString.length; i++) {
- const c = cssString[i];
- if (c == "(") {
- parenthesesDepth++;
- } else if (parenthesesDepth > 0) {
- if (c == ")") {
- parenthesesDepth--;
- }
- } else if (inValue) {
- if (c == ";") {
- const value = currentPart.trim();
- if (value != "") {
- rawEntries.push([currentKey, value]);
- }
- currentKey = null;
- currentPart = "";
- inValue = false;
- continue;
- }
- } else if (c == ":") {
- currentKey = currentPart.trim();
- currentPart = "";
- inValue = true;
- continue;
- }
- currentPart += c;
- }
- if (inValue && parenthesesDepth == 0) {
- const value = currentPart.trim();
- if (value != "") {
- rawEntries.push([currentKey, value]);
- }
- currentKey = null;
- currentPart = "";
- }
-
- for (const [key, value] of rawEntries) {
- if (key == "background-color") {
- const color = parseCssColor(value);
- if (color != null) {
- css.backgroundColor = color;
- }
- } else if (key == "color") {
- const color = parseCssColor(value);
- if (color != null) {
- css.color = color;
- }
- } else if (key == "font-weight") {
- if (value == "bold") {
- css.fontWeight = value;
- }
- } else if (key == "font-style") {
- if (["italic", "oblique", "oblique 14deg"].includes(value)) {
- css.fontStyle = "italic";
- }
- } else if (key == "text-decoration-line") {
- css.textDecorationLine = [];
- for (const lineType of value.split(/\s+/g)) {
- if (["line-through", "overline", "underline"].includes(lineType)) {
- css.textDecorationLine.push(lineType);
- }
- }
- } else if (key == "text-decoration-color") {
- const color = parseCssColor(value);
- if (color != null) {
- css.textDecorationColor = color;
- }
- } else if (key == "text-decoration") {
- css.textDecorationColor = null;
- css.textDecorationLine = [];
- for (const arg of value.split(/\s+/g)) {
- const maybeColor = parseCssColor(arg);
- if (maybeColor != null) {
- css.textDecorationColor = maybeColor;
- } else if (["line-through", "overline", "underline"].includes(arg)) {
- css.textDecorationLine.push(arg);
- }
- }
- }
- }
-
- return css;
- }
-
- function colorEquals(color1, color2) {
- return color1?.[0] == color2?.[0] && color1?.[1] == color2?.[1] &&
- color1?.[2] == color2?.[2];
- }
-
- function cssToAnsi(css, prevCss = null) {
- prevCss = prevCss ?? getDefaultCss();
- let ansi = "";
- if (!colorEquals(css.backgroundColor, prevCss.backgroundColor)) {
- if (css.backgroundColor != null) {
- const [r, g, b] = css.backgroundColor;
- ansi += `\x1b[48;2;${r};${g};${b}m`;
- } else {
- ansi += "\x1b[49m";
- }
- }
- if (!colorEquals(css.color, prevCss.color)) {
- if (css.color != null) {
- const [r, g, b] = css.color;
- ansi += `\x1b[38;2;${r};${g};${b}m`;
- } else {
- ansi += "\x1b[39m";
- }
- }
- if (css.fontWeight != prevCss.fontWeight) {
- if (css.fontWeight == "bold") {
- ansi += `\x1b[1m`;
- } else {
- ansi += "\x1b[22m";
- }
- }
- if (css.fontStyle != prevCss.fontStyle) {
- if (css.fontStyle == "italic") {
- ansi += `\x1b[3m`;
- } else {
- ansi += "\x1b[23m";
- }
- }
- if (!colorEquals(css.textDecorationColor, prevCss.textDecorationColor)) {
- if (css.textDecorationColor != null) {
- const [r, g, b] = css.textDecorationColor;
- ansi += `\x1b[58;2;${r};${g};${b}m`;
- } else {
- ansi += "\x1b[59m";
- }
- }
- if (
- css.textDecorationLine.includes("line-through") !=
- prevCss.textDecorationLine.includes("line-through")
- ) {
- if (css.textDecorationLine.includes("line-through")) {
- ansi += "\x1b[9m";
- } else {
- ansi += "\x1b[29m";
- }
- }
- if (
- css.textDecorationLine.includes("overline") !=
- prevCss.textDecorationLine.includes("overline")
- ) {
- if (css.textDecorationLine.includes("overline")) {
- ansi += "\x1b[53m";
- } else {
- ansi += "\x1b[55m";
- }
- }
- if (
- css.textDecorationLine.includes("underline") !=
- prevCss.textDecorationLine.includes("underline")
- ) {
- if (css.textDecorationLine.includes("underline")) {
- ansi += "\x1b[4m";
- } else {
- ansi += "\x1b[24m";
- }
- }
- return ansi;
- }
-
- function inspectArgs(args, inspectOptions = {}) {
- const noColor = globalThis.Deno?.noColor ?? true;
- const rInspectOptions = { ...DEFAULT_INSPECT_OPTIONS, ...inspectOptions };
- const first = args[0];
- let a = 0;
- let string = "";
-
- if (typeof first == "string" && args.length > 1) {
- a++;
- // Index of the first not-yet-appended character. Use this so we only
- // have to append to `string` when a substitution occurs / at the end.
- let appendedChars = 0;
- let usedStyle = false;
- let prevCss = null;
- for (let i = 0; i < first.length - 1; i++) {
- if (first[i] == "%") {
- const char = first[++i];
- if (a < args.length) {
- let formattedArg = null;
- if (char == "s") {
- // Format as a string.
- formattedArg = String(args[a++]);
- } else if (["d", "i"].includes(char)) {
- // Format as an integer.
- const value = args[a++];
- if (typeof value == "bigint") {
- formattedArg = `${value}n`;
- } else if (typeof value == "number") {
- formattedArg = `${parseInt(String(value))}`;
- } else {
- formattedArg = "NaN";
- }
- } else if (char == "f") {
- // Format as a floating point value.
- const value = args[a++];
- if (typeof value == "number") {
- formattedArg = `${value}`;
- } else {
- formattedArg = "NaN";
- }
- } else if (["O", "o"].includes(char)) {
- // Format as an object.
- formattedArg = inspectValue(
- args[a++],
- new Set(),
- 0,
- rInspectOptions,
- );
- } else if (char == "c") {
- const value = args[a++];
- if (!noColor) {
- const css = parseCss(value);
- formattedArg = cssToAnsi(css, prevCss);
- if (formattedArg != "") {
- usedStyle = true;
- prevCss = css;
- }
- } else {
- formattedArg = "";
- }
- }
-
- if (formattedArg != null) {
- string += first.slice(appendedChars, i - 1) + formattedArg;
- appendedChars = i + 1;
- }
- }
- if (char == "%") {
- string += first.slice(appendedChars, i - 1) + "%";
- appendedChars = i + 1;
- }
- }
- }
- string += first.slice(appendedChars);
- if (usedStyle) {
- string += "\x1b[0m";
- }
- }
-
- for (; a < args.length; a++) {
- if (a > 0) {
- string += " ";
- }
- if (typeof args[a] == "string") {
- string += args[a];
- } else {
- // Use default maximum depth for null or undefined arguments.
- string += inspectValue(args[a], new Set(), 0, rInspectOptions);
- }
- }
-
- if (rInspectOptions.indentLevel > 0) {
- const groupIndent = DEFAULT_INDENT.repeat(rInspectOptions.indentLevel);
- string = groupIndent + string.replaceAll("\n", `\n${groupIndent}`);
- }
-
- return string;
- }
-
- const countMap = new Map();
- const timerMap = new Map();
- const isConsoleInstance = Symbol("isConsoleInstance");
-
- function getConsoleInspectOptions() {
- return {
- ...DEFAULT_INSPECT_OPTIONS,
- colors: !(globalThis.Deno?.noColor ?? false),
- };
- }
-
- class Console {
- #printFunc = null;
- [isConsoleInstance] = false;
-
- constructor(printFunc) {
- this.#printFunc = printFunc;
- this.indentLevel = 0;
- this[isConsoleInstance] = true;
-
- // ref https://console.spec.whatwg.org/#console-namespace
- // For historical web-compatibility reasons, the namespace object for
- // console must have as its [[Prototype]] an empty object, created as if
- // by ObjectCreate(%ObjectPrototype%), instead of %ObjectPrototype%.
- const console = Object.create({});
- Object.assign(console, this);
- return console;
- }
-
- log = (...args) => {
- this.#printFunc(
- inspectArgs(args, {
- ...getConsoleInspectOptions(),
- indentLevel: this.indentLevel,
- }) + "\n",
- false,
- );
- };
-
- debug = this.log;
- info = this.log;
-
- dir = (obj, options = {}) => {
- this.#printFunc(
- inspectArgs([obj], { ...getConsoleInspectOptions(), ...options }) +
- "\n",
- false,
- );
- };
-
- dirxml = this.dir;
-
- warn = (...args) => {
- this.#printFunc(
- inspectArgs(args, {
- ...getConsoleInspectOptions(),
- indentLevel: this.indentLevel,
- }) + "\n",
- true,
- );
- };
-
- error = this.warn;
-
- assert = (condition = false, ...args) => {
- if (condition) {
- return;
- }
-
- if (args.length === 0) {
- this.error("Assertion failed");
- return;
- }
-
- const [first, ...rest] = args;
-
- if (typeof first === "string") {
- this.error(`Assertion failed: ${first}`, ...rest);
- return;
- }
-
- this.error(`Assertion failed:`, ...args);
- };
-
- count = (label = "default") => {
- label = String(label);
-
- if (countMap.has(label)) {
- const current = countMap.get(label) || 0;
- countMap.set(label, current + 1);
- } else {
- countMap.set(label, 1);
- }
-
- this.info(`${label}: ${countMap.get(label)}`);
- };
-
- countReset = (label = "default") => {
- label = String(label);
-
- if (countMap.has(label)) {
- countMap.set(label, 0);
- } else {
- this.warn(`Count for '${label}' does not exist`);
- }
- };
-
- table = (data, properties) => {
- if (properties !== undefined && !Array.isArray(properties)) {
- throw new Error(
- "The 'properties' argument must be of type Array. " +
- "Received type string",
- );
- }
-
- if (data === null || typeof data !== "object") {
- return this.log(data);
- }
-
- const objectValues = {};
- const indexKeys = [];
- const values = [];
-
- const stringifyValue = (value) =>
- inspectValueWithQuotes(value, new Set(), 0, {
- ...DEFAULT_INSPECT_OPTIONS,
- depth: 1,
- });
- const toTable = (header, body) => this.log(cliTable(header, body));
- const createColumn = (value, shift) => [
- ...(shift ? [...new Array(shift)].map(() => "") : []),
- stringifyValue(value),
- ];
-
- let resultData;
- const isSet = data instanceof Set;
- const isMap = data instanceof Map;
- const valuesKey = "Values";
- const indexKey = isSet || isMap ? "(iter idx)" : "(idx)";
-
- if (data instanceof Set) {
- resultData = [...data];
- } else if (data instanceof Map) {
- let idx = 0;
- resultData = {};
-
- data.forEach((v, k) => {
- resultData[idx] = { Key: k, Values: v };
- idx++;
- });
- } else {
- resultData = data;
- }
-
- let hasPrimitives = false;
- Object.keys(resultData).forEach((k, idx) => {
- const value = resultData[k];
- const primitive = value === null ||
- (typeof value !== "function" && typeof value !== "object");
- if (properties === undefined && primitive) {
- hasPrimitives = true;
- values.push(stringifyValue(value));
- } else {
- const valueObj = value || {};
- const keys = properties || Object.keys(valueObj);
- for (const k of keys) {
- if (primitive || !valueObj.hasOwnProperty(k)) {
- if (objectValues[k]) {
- // fill with blanks for idx to avoid misplacing from later values
- objectValues[k].push("");
- }
- } else {
- if (objectValues[k]) {
- objectValues[k].push(stringifyValue(valueObj[k]));
- } else {
- objectValues[k] = createColumn(valueObj[k], idx);
- }
- }
- }
- values.push("");
- }
-
- indexKeys.push(k);
- });
-
- const headerKeys = Object.keys(objectValues);
- const bodyValues = Object.values(objectValues);
- const header = [
- indexKey,
- ...(properties ||
- [...headerKeys, !isMap && hasPrimitives && valuesKey]),
- ].filter(Boolean);
- const body = [indexKeys, ...bodyValues, values];
-
- toTable(header, body);
- };
-
- time = (label = "default") => {
- label = String(label);
-
- if (timerMap.has(label)) {
- this.warn(`Timer '${label}' already exists`);
- return;
- }
-
- timerMap.set(label, Date.now());
- };
-
- timeLog = (label = "default", ...args) => {
- label = String(label);
-
- if (!timerMap.has(label)) {
- this.warn(`Timer '${label}' does not exists`);
- return;
- }
-
- const startTime = timerMap.get(label);
- const duration = Date.now() - startTime;
-
- this.info(`${label}: ${duration}ms`, ...args);
- };
-
- timeEnd = (label = "default") => {
- label = String(label);
-
- if (!timerMap.has(label)) {
- this.warn(`Timer '${label}' does not exists`);
- return;
- }
-
- const startTime = timerMap.get(label);
- timerMap.delete(label);
- const duration = Date.now() - startTime;
-
- this.info(`${label}: ${duration}ms`);
- };
-
- group = (...label) => {
- if (label.length > 0) {
- this.log(...label);
- }
- this.indentLevel += 2;
- };
-
- groupCollapsed = this.group;
-
- groupEnd = () => {
- if (this.indentLevel > 0) {
- this.indentLevel -= 2;
- }
- };
-
- clear = () => {
- this.indentLevel = 0;
- this.#printFunc(CSI.kClear, false);
- this.#printFunc(CSI.kClearScreenDown, false);
- };
-
- trace = (...args) => {
- const message = inspectArgs(
- args,
- { ...getConsoleInspectOptions(), indentLevel: 0 },
- );
- const err = {
- name: "Trace",
- message,
- };
- Error.captureStackTrace(err, this.trace);
- this.error(err.stack);
- };
-
- static [Symbol.hasInstance](instance) {
- return instance[isConsoleInstance];
- }
- }
-
- const customInspect = Symbol("Deno.customInspect");
-
- function inspect(
- value,
- inspectOptions = {},
- ) {
- return inspectValue(value, new Set(), 0, {
- ...DEFAULT_INSPECT_OPTIONS,
- ...inspectOptions,
- // TODO(nayeemrmn): Indent level is not supported.
- indentLevel: 0,
- });
- }
-
- // Expose these fields to internalObject for tests.
- exposeForTest("Console", Console);
- exposeForTest("cssToAnsi", cssToAnsi);
- exposeForTest("inspectArgs", inspectArgs);
- exposeForTest("parseCss", parseCss);
- exposeForTest("parseCssColor", parseCssColor);
-
- window.__bootstrap.console = {
- CSI,
- inspectArgs,
- Console,
- customInspect,
- inspect,
- };
-})(this);
diff --git a/cli/rt/06_util.js b/cli/rt/06_util.js
deleted file mode 100644
index f4804c519..000000000
--- a/cli/rt/06_util.js
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const { build } = window.__bootstrap.build;
- const internals = window.__bootstrap.internals;
- let logDebug = false;
- let logSource = "JS";
-
- function setLogDebug(debug, source) {
- logDebug = debug;
- if (source) {
- logSource = source;
- }
- }
-
- function log(...args) {
- if (logDebug) {
- // if we destructure `console` off `globalThis` too early, we don't bind to
- // the right console, therefore we don't log anything out.
- globalThis.console.log(`DEBUG ${logSource} -`, ...args);
- }
- }
-
- class AssertionError extends Error {
- constructor(msg) {
- super(msg);
- this.name = "AssertionError";
- }
- }
-
- function assert(cond, msg = "Assertion failed.") {
- if (!cond) {
- throw new AssertionError(msg);
- }
- }
-
- function createResolvable() {
- let resolve;
- let reject;
- const promise = new Promise((res, rej) => {
- resolve = res;
- reject = rej;
- });
- promise.resolve = resolve;
- promise.reject = reject;
- return promise;
- }
-
- function immutableDefine(
- o,
- p,
- value,
- ) {
- Object.defineProperty(o, p, {
- value,
- configurable: false,
- writable: false,
- });
- }
-
- // Keep in sync with `fromFileUrl()` in `std/path/win32.ts`.
- function pathFromURLWin32(url) {
- let path = decodeURIComponent(
- url.pathname
- .replace(/^\/*([A-Za-z]:)(\/|$)/, "$1/")
- .replace(/\//g, "\\")
- .replace(/%(?![0-9A-Fa-f]{2})/g, "%25"),
- );
- if (url.hostname != "") {
- // Note: The `URL` implementation guarantees that the drive letter and
- // hostname are mutually exclusive. Otherwise it would not have been valid
- // to append the hostname and path like this.
- path = `\\\\${url.hostname}${path}`;
- }
- return path;
- }
-
- // Keep in sync with `fromFileUrl()` in `std/path/posix.ts`.
- function pathFromURLPosix(url) {
- if (url.hostname !== "") {
- throw new TypeError(`Host must be empty.`);
- }
-
- return decodeURIComponent(
- url.pathname.replace(/%(?![0-9A-Fa-f]{2})/g, "%25"),
- );
- }
-
- function pathFromURL(pathOrUrl) {
- if (pathOrUrl instanceof URL) {
- if (pathOrUrl.protocol != "file:") {
- throw new TypeError("Must be a file URL.");
- }
-
- return build.os == "windows"
- ? pathFromURLWin32(pathOrUrl)
- : pathFromURLPosix(pathOrUrl);
- }
- return pathOrUrl;
- }
-
- internals.exposeForTest("pathFromURL", pathFromURL);
-
- function writable(value) {
- return {
- value,
- writable: true,
- enumerable: true,
- configurable: true,
- };
- }
-
- function nonEnumerable(value) {
- return {
- value,
- writable: true,
- configurable: true,
- };
- }
-
- function readOnly(value) {
- return {
- value,
- enumerable: true,
- };
- }
-
- function getterOnly(getter) {
- return {
- get: getter,
- enumerable: true,
- };
- }
-
- window.__bootstrap.util = {
- log,
- setLogDebug,
- createResolvable,
- assert,
- AssertionError,
- immutableDefine,
- pathFromURL,
- writable,
- nonEnumerable,
- readOnly,
- getterOnly,
- };
-})(this);
diff --git a/cli/rt/10_dispatch_minimal.js b/cli/rt/10_dispatch_minimal.js
deleted file mode 100644
index dceb23e5f..000000000
--- a/cli/rt/10_dispatch_minimal.js
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const util = window.__bootstrap.util;
-
- // Using an object without a prototype because `Map` was causing GC problems.
- const promiseTableMin = Object.create(null);
-
- const decoder = new TextDecoder();
-
- // Note it's important that promiseId starts at 1 instead of 0, because sync
- // messages are indicated with promiseId 0. If we ever add wrap around logic for
- // overflows, this should be taken into account.
- let _nextPromiseId = 1;
-
- function nextPromiseId() {
- return _nextPromiseId++;
- }
-
- function recordFromBufMinimal(ui8) {
- const headerLen = 12;
- const header = ui8.subarray(0, headerLen);
- const buf32 = new Int32Array(
- header.buffer,
- header.byteOffset,
- header.byteLength / 4,
- );
- const promiseId = buf32[0];
- const arg = buf32[1];
- const result = buf32[2];
- let err;
-
- if (arg < 0) {
- err = {
- className: decoder.decode(ui8.subarray(headerLen, headerLen + result)),
- message: decoder.decode(ui8.subarray(headerLen + result)),
- };
- } else if (ui8.length != 12) {
- throw new TypeError("Malformed response message");
- }
-
- return {
- promiseId,
- arg,
- result,
- err,
- };
- }
-
- function unwrapResponse(res) {
- if (res.err != null) {
- const ErrorClass = core.getErrorClass(res.err.className);
- if (!ErrorClass) {
- throw new Error(
- `Unregistered error class: "${res.err.className}"\n ${res.err.message}\n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
- );
- }
- throw new ErrorClass(res.err.message);
- }
- return res.result;
- }
-
- const scratch32 = new Int32Array(3);
- const scratchBytes = new Uint8Array(
- scratch32.buffer,
- scratch32.byteOffset,
- scratch32.byteLength,
- );
- util.assert(scratchBytes.byteLength === scratch32.length * 4);
-
- function asyncMsgFromRust(ui8) {
- const record = recordFromBufMinimal(ui8);
- const { promiseId } = record;
- const promise = promiseTableMin[promiseId];
- delete promiseTableMin[promiseId];
- util.assert(promise);
- promise.resolve(record);
- }
-
- async function sendAsync(opName, arg, zeroCopy) {
- const promiseId = nextPromiseId(); // AKA cmdId
- scratch32[0] = promiseId;
- scratch32[1] = arg;
- scratch32[2] = 0; // result
- const promise = util.createResolvable();
- const buf = core.dispatchByName(opName, scratchBytes, zeroCopy);
- if (buf != null) {
- const record = recordFromBufMinimal(buf);
- // Sync result.
- promise.resolve(record);
- } else {
- // Async result.
- promiseTableMin[promiseId] = promise;
- }
-
- const res = await promise;
- return unwrapResponse(res);
- }
-
- function sendSync(opName, arg, zeroCopy) {
- scratch32[0] = 0; // promiseId 0 indicates sync
- scratch32[1] = arg;
- const res = core.dispatchByName(opName, scratchBytes, zeroCopy);
- const resRecord = recordFromBufMinimal(res);
- return unwrapResponse(resRecord);
- }
-
- window.__bootstrap.dispatchMinimal = {
- asyncMsgFromRust,
- sendSync,
- sendAsync,
- };
-})(this);
diff --git a/cli/rt/11_timers.js b/cli/rt/11_timers.js
deleted file mode 100644
index 5a59844a3..000000000
--- a/cli/rt/11_timers.js
+++ /dev/null
@@ -1,557 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const assert = window.__bootstrap.util.assert;
- const core = window.Deno.core;
- const { sendSync } = window.__bootstrap.dispatchMinimal;
-
- function opStopGlobalTimer() {
- core.jsonOpSync("op_global_timer_stop");
- }
-
- function opStartGlobalTimer(timeout) {
- return core.jsonOpSync("op_global_timer_start", { timeout });
- }
-
- async function opWaitGlobalTimer() {
- await core.jsonOpAsync("op_global_timer");
- }
-
- const nowBytes = new Uint8Array(8);
- function opNow() {
- sendSync("op_now", 0, nowBytes);
- return new DataView(nowBytes.buffer).getFloat64();
- }
-
- function sleepSync(millis = 0) {
- return core.jsonOpSync("op_sleep_sync", { millis });
- }
-
- // Derived from https://github.com/vadimg/js_bintrees. MIT Licensed.
-
- class RBNode {
- constructor(data) {
- this.data = data;
- this.left = null;
- this.right = null;
- this.red = true;
- }
-
- getChild(dir) {
- return dir ? this.right : this.left;
- }
-
- setChild(dir, val) {
- if (dir) {
- this.right = val;
- } else {
- this.left = val;
- }
- }
- }
-
- class RBTree {
- #comparator = null;
- #root = null;
-
- constructor(comparator) {
- this.#comparator = comparator;
- this.#root = null;
- }
-
- /** Returns `null` if tree is empty. */
- min() {
- let res = this.#root;
- if (res === null) {
- return null;
- }
- while (res.left !== null) {
- res = res.left;
- }
- return res.data;
- }
-
- /** Returns node `data` if found, `null` otherwise. */
- find(data) {
- let res = this.#root;
- while (res !== null) {
- const c = this.#comparator(data, res.data);
- if (c === 0) {
- return res.data;
- } else {
- res = res.getChild(c > 0);
- }
- }
- return null;
- }
-
- /** returns `true` if inserted, `false` if duplicate. */
- insert(data) {
- let ret = false;
-
- if (this.#root === null) {
- // empty tree
- this.#root = new RBNode(data);
- ret = true;
- } else {
- const head = new RBNode(null); // fake tree root
-
- let dir = 0;
- let last = 0;
-
- // setup
- let gp = null; // grandparent
- let ggp = head; // grand-grand-parent
- let p = null; // parent
- let node = this.#root;
- ggp.right = this.#root;
-
- // search down
- while (true) {
- if (node === null) {
- // insert new node at the bottom
- node = new RBNode(data);
- p.setChild(dir, node);
- ret = true;
- } else if (isRed(node.left) && isRed(node.right)) {
- // color flip
- node.red = true;
- node.left.red = false;
- node.right.red = false;
- }
-
- // fix red violation
- if (isRed(node) && isRed(p)) {
- const dir2 = ggp.right === gp;
-
- assert(gp);
- if (node === p.getChild(last)) {
- ggp.setChild(dir2, singleRotate(gp, !last));
- } else {
- ggp.setChild(dir2, doubleRotate(gp, !last));
- }
- }
-
- const cmp = this.#comparator(node.data, data);
-
- // stop if found
- if (cmp === 0) {
- break;
- }
-
- last = dir;
- dir = Number(cmp < 0); // Fix type
-
- // update helpers
- if (gp !== null) {
- ggp = gp;
- }
- gp = p;
- p = node;
- node = node.getChild(dir);
- }
-
- // update root
- this.#root = head.right;
- }
-
- // make root black
- this.#root.red = false;
-
- return ret;
- }
-
- /** Returns `true` if removed, `false` if not found. */
- remove(data) {
- if (this.#root === null) {
- return false;
- }
-
- const head = new RBNode(null); // fake tree root
- let node = head;
- node.right = this.#root;
- let p = null; // parent
- let gp = null; // grand parent
- let found = null; // found item
- let dir = 1;
-
- while (node.getChild(dir) !== null) {
- const last = dir;
-
- // update helpers
- gp = p;
- p = node;
- node = node.getChild(dir);
-
- const cmp = this.#comparator(data, node.data);
-
- dir = cmp > 0;
-
- // save found node
- if (cmp === 0) {
- found = node;
- }
-
- // push the red node down
- if (!isRed(node) && !isRed(node.getChild(dir))) {
- if (isRed(node.getChild(!dir))) {
- const sr = singleRotate(node, dir);
- p.setChild(last, sr);
- p = sr;
- } else if (!isRed(node.getChild(!dir))) {
- const sibling = p.getChild(!last);
- if (sibling !== null) {
- if (
- !isRed(sibling.getChild(!last)) &&
- !isRed(sibling.getChild(last))
- ) {
- // color flip
- p.red = false;
- sibling.red = true;
- node.red = true;
- } else {
- assert(gp);
- const dir2 = gp.right === p;
-
- if (isRed(sibling.getChild(last))) {
- gp.setChild(dir2, doubleRotate(p, last));
- } else if (isRed(sibling.getChild(!last))) {
- gp.setChild(dir2, singleRotate(p, last));
- }
-
- // ensure correct coloring
- const gpc = gp.getChild(dir2);
- assert(gpc);
- gpc.red = true;
- node.red = true;
- assert(gpc.left);
- gpc.left.red = false;
- assert(gpc.right);
- gpc.right.red = false;
- }
- }
- }
- }
- }
-
- // replace and remove if found
- if (found !== null) {
- found.data = node.data;
- assert(p);
- p.setChild(p.right === node, node.getChild(node.left === null));
- }
-
- // update root and make it black
- this.#root = head.right;
- if (this.#root !== null) {
- this.#root.red = false;
- }
-
- return found !== null;
- }
- }
-
- function isRed(node) {
- return node !== null && node.red;
- }
-
- function singleRotate(root, dir) {
- const save = root.getChild(!dir);
- assert(save);
-
- root.setChild(!dir, save.getChild(dir));
- save.setChild(dir, root);
-
- root.red = true;
- save.red = false;
-
- return save;
- }
-
- function doubleRotate(root, dir) {
- root.setChild(!dir, singleRotate(root.getChild(!dir), !dir));
- return singleRotate(root, dir);
- }
-
- const { console } = globalThis;
- const OriginalDate = Date;
-
- // Timeout values > TIMEOUT_MAX are set to 1.
- const TIMEOUT_MAX = 2 ** 31 - 1;
-
- let globalTimeoutDue = null;
-
- let nextTimerId = 1;
- const idMap = new Map();
- const dueTree = new RBTree((a, b) => a.due - b.due);
-
- function clearGlobalTimeout() {
- globalTimeoutDue = null;
- opStopGlobalTimer();
- }
-
- let pendingEvents = 0;
- const pendingFireTimers = [];
-
- /** Process and run a single ready timer macrotask.
- * This function should be registered through Deno.core.setMacrotaskCallback.
- * Returns true when all ready macrotasks have been processed, false if more
- * ready ones are available. The Isolate future would rely on the return value
- * to repeatedly invoke this function until depletion. Multiple invocations
- * of this function one at a time ensures newly ready microtasks are processed
- * before next macrotask timer callback is invoked. */
- function handleTimerMacrotask() {
- if (pendingFireTimers.length > 0) {
- fire(pendingFireTimers.shift());
- return pendingFireTimers.length === 0;
- }
- return true;
- }
-
- async function setGlobalTimeout(due, now) {
- // Since JS and Rust don't use the same clock, pass the time to rust as a
- // relative time value. On the Rust side we'll turn that into an absolute
- // value again.
- const timeout = due - now;
- assert(timeout >= 0);
- // Send message to the backend.
- globalTimeoutDue = due;
- pendingEvents++;
- // FIXME(bartlomieju): this is problematic, because `clearGlobalTimeout`
- // is synchronous. That means that timer is cancelled, but this promise is still pending
- // until next turn of event loop. This leads to "leaking of async ops" in tests;
- // because `clearTimeout/clearInterval` might be the last statement in test function
- // `opSanitizer` will immediately complain that there is pending op going on, unless
- // some timeout/defer is put in place to allow promise resolution.
- // Ideally `clearGlobalTimeout` doesn't return until this op is resolved, but
- // I'm not if that's possible.
- opStartGlobalTimer(timeout);
- await opWaitGlobalTimer();
- pendingEvents--;
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- prepareReadyTimers();
- }
-
- function prepareReadyTimers() {
- const now = OriginalDate.now();
- // Bail out if we're not expecting the global timer to fire.
- if (globalTimeoutDue === null || pendingEvents > 0) {
- return;
- }
- // After firing the timers that are due now, this will hold the first timer
- // list that hasn't fired yet.
- let nextDueNode;
- while ((nextDueNode = dueTree.min()) !== null && nextDueNode.due <= now) {
- dueTree.remove(nextDueNode);
- // Fire all the timers in the list.
- for (const timer of nextDueNode.timers) {
- // With the list dropped, the timer is no longer scheduled.
- timer.scheduled = false;
- // Place the callback to pending timers to fire.
- pendingFireTimers.push(timer);
- }
- }
- setOrClearGlobalTimeout(nextDueNode && nextDueNode.due, now);
- }
-
- function setOrClearGlobalTimeout(due, now) {
- if (due == null) {
- clearGlobalTimeout();
- } else {
- setGlobalTimeout(due, now);
- }
- }
-
- function schedule(timer, now) {
- assert(!timer.scheduled);
- assert(now <= timer.due);
- // Find or create the list of timers that will fire at point-in-time `due`.
- const maybeNewDueNode = { due: timer.due, timers: [] };
- let dueNode = dueTree.find(maybeNewDueNode);
- if (dueNode === null) {
- dueTree.insert(maybeNewDueNode);
- dueNode = maybeNewDueNode;
- }
- // Append the newly scheduled timer to the list and mark it as scheduled.
- dueNode.timers.push(timer);
- timer.scheduled = true;
- // If the new timer is scheduled to fire before any timer that existed before,
- // update the global timeout to reflect this.
- if (globalTimeoutDue === null || globalTimeoutDue > timer.due) {
- setOrClearGlobalTimeout(timer.due, now);
- }
- }
-
- function unschedule(timer) {
- // Check if our timer is pending scheduling or pending firing.
- // If either is true, they are not in tree, and their idMap entry
- // will be deleted soon. Remove it from queue.
- let index = -1;
- if ((index = pendingFireTimers.indexOf(timer)) >= 0) {
- pendingFireTimers.splice(index);
- return;
- }
- // If timer is not in the 2 pending queues and is unscheduled,
- // it is not in the tree.
- if (!timer.scheduled) {
- return;
- }
- const searchKey = { due: timer.due, timers: [] };
- // Find the list of timers that will fire at point-in-time `due`.
- const list = dueTree.find(searchKey).timers;
- if (list.length === 1) {
- // Time timer is the only one in the list. Remove the entire list.
- assert(list[0] === timer);
- dueTree.remove(searchKey);
- // If the unscheduled timer was 'next up', find when the next timer that
- // still exists is due, and update the global alarm accordingly.
- if (timer.due === globalTimeoutDue) {
- const nextDueNode = dueTree.min();
- setOrClearGlobalTimeout(
- nextDueNode && nextDueNode.due,
- OriginalDate.now(),
- );
- }
- } else {
- // Multiple timers that are due at the same point in time.
- // Remove this timer from the list.
- const index = list.indexOf(timer);
- assert(index > -1);
- list.splice(index, 1);
- }
- }
-
- function fire(timer) {
- // If the timer isn't found in the ID map, that means it has been cancelled
- // between the timer firing and the promise callback (this function).
- if (!idMap.has(timer.id)) {
- return;
- }
- // Reschedule the timer if it is a repeating one, otherwise drop it.
- if (!timer.repeat) {
- // One-shot timer: remove the timer from this id-to-timer map.
- idMap.delete(timer.id);
- } else {
- // Interval timer: compute when timer was supposed to fire next.
- // However make sure to never schedule the next interval in the past.
- const now = OriginalDate.now();
- timer.due = Math.max(now, timer.due + timer.delay);
- schedule(timer, now);
- }
- // Call the user callback. Intermediate assignment is to avoid leaking `this`
- // to it, while also keeping the stack trace neat when it shows up in there.
- const callback = timer.callback;
- callback();
- }
-
- function checkThis(thisArg) {
- if (thisArg !== null && thisArg !== undefined && thisArg !== globalThis) {
- throw new TypeError("Illegal invocation");
- }
- }
-
- function checkBigInt(n) {
- if (typeof n === "bigint") {
- throw new TypeError("Cannot convert a BigInt value to a number");
- }
- }
-
- function setTimer(
- cb,
- delay,
- args,
- repeat,
- ) {
- // Bind `args` to the callback and bind `this` to globalThis(global).
- const callback = cb.bind(globalThis, ...args);
- // In the browser, the delay value must be coercible to an integer between 0
- // and INT32_MAX. Any other value will cause the timer to fire immediately.
- // We emulate this behavior.
- const now = OriginalDate.now();
- if (delay > TIMEOUT_MAX) {
- console.warn(
- `${delay} does not fit into` +
- " a 32-bit signed integer." +
- "\nTimeout duration was set to 1.",
- );
- delay = 1;
- }
- delay = Math.max(0, delay | 0);
-
- // Create a new, unscheduled timer object.
- const timer = {
- id: nextTimerId++,
- callback,
- args,
- delay,
- due: now + delay,
- repeat,
- scheduled: false,
- };
- // Register the timer's existence in the id-to-timer map.
- idMap.set(timer.id, timer);
- // Schedule the timer in the due table.
- schedule(timer, now);
- return timer.id;
- }
-
- function setTimeout(
- cb,
- delay = 0,
- ...args
- ) {
- checkBigInt(delay);
- checkThis(this);
- return setTimer(cb, delay, args, false);
- }
-
- function setInterval(
- cb,
- delay = 0,
- ...args
- ) {
- checkBigInt(delay);
- checkThis(this);
- return setTimer(cb, delay, args, true);
- }
-
- function clearTimer(id) {
- id = Number(id);
- const timer = idMap.get(id);
- if (timer === undefined) {
- // Timer doesn't exist any more or never existed. This is not an error.
- return;
- }
- // Unschedule the timer if it is currently scheduled, and forget about it.
- unschedule(timer);
- idMap.delete(timer.id);
- }
-
- function clearTimeout(id = 0) {
- checkBigInt(id);
- if (id === 0) {
- return;
- }
- clearTimer(id);
- }
-
- function clearInterval(id = 0) {
- checkBigInt(id);
- if (id === 0) {
- return;
- }
- clearTimer(id);
- }
-
- window.__bootstrap.timers = {
- clearInterval,
- setInterval,
- clearTimeout,
- setTimeout,
- handleTimerMacrotask,
- opStopGlobalTimer,
- opStartGlobalTimer,
- opNow,
- sleepSync,
- };
-})(this);
diff --git a/cli/rt/11_workers.js b/cli/rt/11_workers.js
deleted file mode 100644
index 62210dfae..000000000
--- a/cli/rt/11_workers.js
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { Window } = window.__bootstrap.globalInterfaces;
- const { log } = window.__bootstrap.util;
- const { defineEventHandler } = window.__bootstrap.webUtil;
-
- function createWorker(
- specifier,
- hasSourceCode,
- sourceCode,
- useDenoNamespace,
- name,
- ) {
- return core.jsonOpSync("op_create_worker", {
- specifier,
- hasSourceCode,
- sourceCode,
- name,
- useDenoNamespace,
- });
- }
-
- function hostTerminateWorker(id) {
- core.jsonOpSync("op_host_terminate_worker", { id });
- }
-
- function hostPostMessage(id, data) {
- core.jsonOpSync("op_host_post_message", { id }, data);
- }
-
- function hostGetMessage(id) {
- return core.jsonOpAsync("op_host_get_message", { id });
- }
-
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- function encodeMessage(data) {
- const dataJson = JSON.stringify(data);
- return encoder.encode(dataJson);
- }
-
- function decodeMessage(dataIntArray) {
- const dataJson = decoder.decode(dataIntArray);
- return JSON.parse(dataJson);
- }
-
- class Worker extends EventTarget {
- #id = 0;
- #name = "";
- #terminated = false;
-
- constructor(specifier, options) {
- super();
- const { type = "classic", name = "unknown" } = options ?? {};
-
- if (type !== "module") {
- throw new Error(
- 'Not yet implemented: only "module" type workers are supported',
- );
- }
-
- this.#name = name;
- const hasSourceCode = false;
- const sourceCode = decoder.decode(new Uint8Array());
-
- const useDenoNamespace = options ? !!options.deno : false;
-
- const { id } = createWorker(
- specifier,
- hasSourceCode,
- sourceCode,
- useDenoNamespace,
- options?.name,
- );
- this.#id = id;
- this.#poll();
- }
-
- #handleMessage = (msgData) => {
- let data;
- try {
- data = decodeMessage(new Uint8Array(msgData));
- } catch (e) {
- const msgErrorEvent = new MessageEvent("messageerror", {
- cancelable: false,
- data,
- });
- return;
- }
-
- const msgEvent = new MessageEvent("message", {
- cancelable: false,
- data,
- });
-
- this.dispatchEvent(msgEvent);
- };
-
- #handleError = (e) => {
- const event = new ErrorEvent("error", {
- cancelable: true,
- message: e.message,
- lineno: e.lineNumber ? e.lineNumber + 1 : undefined,
- colno: e.columnNumber ? e.columnNumber + 1 : undefined,
- filename: e.fileName,
- error: null,
- });
-
- let handled = false;
-
- this.dispatchEvent(event);
- if (event.defaultPrevented) {
- handled = true;
- }
-
- return handled;
- };
-
- #poll = async () => {
- while (!this.#terminated) {
- const event = await hostGetMessage(this.#id);
-
- // If terminate was called then we ignore all messages
- if (this.#terminated) {
- return;
- }
-
- const type = event.type;
-
- if (type === "terminalError") {
- this.#terminated = true;
- if (!this.#handleError(event.error)) {
- if (globalThis instanceof Window) {
- throw new Error("Unhandled error event reached main worker.");
- } else {
- core.jsonOpSync(
- "op_host_unhandled_error",
- { message: event.error.message },
- );
- }
- }
- continue;
- }
-
- if (type === "msg") {
- this.#handleMessage(event.data);
- continue;
- }
-
- if (type === "error") {
- if (!this.#handleError(event.error)) {
- if (globalThis instanceof Window) {
- throw new Error("Unhandled error event reached main worker.");
- } else {
- core.jsonOpSync(
- "op_host_unhandled_error",
- { message: event.error.message },
- );
- }
- }
- continue;
- }
-
- if (type === "close") {
- log(`Host got "close" message from worker: ${this.#name}`);
- this.#terminated = true;
- return;
- }
-
- throw new Error(`Unknown worker event: "${type}"`);
- }
- };
-
- postMessage(message, transferOrOptions) {
- if (transferOrOptions) {
- throw new Error(
- "Not yet implemented: `transfer` and `options` are not supported.",
- );
- }
-
- if (this.#terminated) {
- return;
- }
-
- hostPostMessage(this.#id, encodeMessage(message));
- }
-
- terminate() {
- if (!this.#terminated) {
- this.#terminated = true;
- hostTerminateWorker(this.#id);
- }
- }
- }
-
- defineEventHandler(Worker.prototype, "error");
- defineEventHandler(Worker.prototype, "message");
- defineEventHandler(Worker.prototype, "messageerror");
-
- window.__bootstrap.worker = {
- Worker,
- };
-})(this);
diff --git a/cli/rt/12_io.js b/cli/rt/12_io.js
deleted file mode 100644
index 006d51cdd..000000000
--- a/cli/rt/12_io.js
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-// Interfaces 100% copied from Go.
-// Documentation liberally lifted from them too.
-// Thank you! We love Go! <3
-
-((window) => {
- const DEFAULT_BUFFER_SIZE = 32 * 1024;
- const { sendSync, sendAsync } = window.__bootstrap.dispatchMinimal;
- // Seek whence values.
- // https://golang.org/pkg/io/#pkg-constants
- const SeekMode = {
- 0: "Start",
- 1: "Current",
- 2: "End",
-
- Start: 0,
- Current: 1,
- End: 2,
- };
-
- async function copy(
- src,
- dst,
- options,
- ) {
- let n = 0;
- const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE;
- const b = new Uint8Array(bufSize);
- let gotEOF = false;
- while (gotEOF === false) {
- const result = await src.read(b);
- if (result === null) {
- gotEOF = true;
- } else {
- let nwritten = 0;
- while (nwritten < result) {
- nwritten += await dst.write(b.subarray(nwritten, result));
- }
- n += nwritten;
- }
- }
- return n;
- }
-
- async function* iter(
- r,
- options,
- ) {
- const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE;
- const b = new Uint8Array(bufSize);
- while (true) {
- const result = await r.read(b);
- if (result === null) {
- break;
- }
-
- yield b.subarray(0, result);
- }
- }
-
- function* iterSync(
- r,
- options,
- ) {
- const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE;
- const b = new Uint8Array(bufSize);
- while (true) {
- const result = r.readSync(b);
- if (result === null) {
- break;
- }
-
- yield b.subarray(0, result);
- }
- }
-
- function readSync(rid, buffer) {
- if (buffer.length === 0) {
- return 0;
- }
-
- const nread = sendSync("op_read", rid, buffer);
- if (nread < 0) {
- throw new Error("read error");
- }
-
- return nread === 0 ? null : nread;
- }
-
- async function read(
- rid,
- buffer,
- ) {
- if (buffer.length === 0) {
- return 0;
- }
-
- const nread = await sendAsync("op_read", rid, buffer);
- if (nread < 0) {
- throw new Error("read error");
- }
-
- return nread === 0 ? null : nread;
- }
-
- function writeSync(rid, data) {
- const result = sendSync("op_write", rid, data);
- if (result < 0) {
- throw new Error("write error");
- }
-
- return result;
- }
-
- async function write(rid, data) {
- const result = await sendAsync("op_write", rid, data);
- if (result < 0) {
- throw new Error("write error");
- }
-
- return result;
- }
-
- window.__bootstrap.io = {
- iterSync,
- iter,
- copy,
- SeekMode,
- read,
- readSync,
- write,
- writeSync,
- };
-})(this);
diff --git a/cli/rt/13_buffer.js b/cli/rt/13_buffer.js
deleted file mode 100644
index e06e2138b..000000000
--- a/cli/rt/13_buffer.js
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-// This code has been ported almost directly from Go's src/bytes/buffer.go
-// Copyright 2009 The Go Authors. All rights reserved. BSD license.
-// https://github.com/golang/go/blob/master/LICENSE
-
-((window) => {
- const { assert } = window.__bootstrap.util;
-
- // MIN_READ is the minimum ArrayBuffer size passed to a read call by
- // buffer.ReadFrom. As long as the Buffer has at least MIN_READ bytes beyond
- // what is required to hold the contents of r, readFrom() will not grow the
- // underlying buffer.
- const MIN_READ = 32 * 1024;
- const MAX_SIZE = 2 ** 32 - 2;
-
- // `off` is the offset into `dst` where it will at which to begin writing values
- // from `src`.
- // Returns the number of bytes copied.
- function copyBytes(src, dst, off = 0) {
- const r = dst.byteLength - off;
- if (src.byteLength > r) {
- src = src.subarray(0, r);
- }
- dst.set(src, off);
- return src.byteLength;
- }
-
- class Buffer {
- #buf = null; // contents are the bytes buf[off : len(buf)]
- #off = 0; // read at buf[off], write at buf[buf.byteLength]
-
- constructor(ab) {
- if (ab == null) {
- this.#buf = new Uint8Array(0);
- return;
- }
-
- this.#buf = new Uint8Array(ab);
- }
-
- bytes(options = { copy: true }) {
- if (options.copy === false) return this.#buf.subarray(this.#off);
- return this.#buf.slice(this.#off);
- }
-
- empty() {
- return this.#buf.byteLength <= this.#off;
- }
-
- get length() {
- return this.#buf.byteLength - this.#off;
- }
-
- get capacity() {
- return this.#buf.buffer.byteLength;
- }
-
- truncate(n) {
- if (n === 0) {
- this.reset();
- return;
- }
- if (n < 0 || n > this.length) {
- throw Error("bytes.Buffer: truncation out of range");
- }
- this.#reslice(this.#off + n);
- }
-
- reset() {
- this.#reslice(0);
- this.#off = 0;
- }
-
- #tryGrowByReslice = (n) => {
- const l = this.#buf.byteLength;
- if (n <= this.capacity - l) {
- this.#reslice(l + n);
- return l;
- }
- return -1;
- };
-
- #reslice = (len) => {
- assert(len <= this.#buf.buffer.byteLength);
- this.#buf = new Uint8Array(this.#buf.buffer, 0, len);
- };
-
- readSync(p) {
- if (this.empty()) {
- // Buffer is empty, reset to recover space.
- this.reset();
- if (p.byteLength === 0) {
- // this edge case is tested in 'bufferReadEmptyAtEOF' test
- return 0;
- }
- return null;
- }
- const nread = copyBytes(this.#buf.subarray(this.#off), p);
- this.#off += nread;
- return nread;
- }
-
- read(p) {
- const rr = this.readSync(p);
- return Promise.resolve(rr);
- }
-
- writeSync(p) {
- const m = this.#grow(p.byteLength);
- return copyBytes(p, this.#buf, m);
- }
-
- write(p) {
- const n = this.writeSync(p);
- return Promise.resolve(n);
- }
-
- #grow = (n) => {
- const m = this.length;
- // If buffer is empty, reset to recover space.
- if (m === 0 && this.#off !== 0) {
- this.reset();
- }
- // Fast: Try to grow by means of a reslice.
- const i = this.#tryGrowByReslice(n);
- if (i >= 0) {
- return i;
- }
- const c = this.capacity;
- if (n <= Math.floor(c / 2) - m) {
- // We can slide things down instead of allocating a new
- // ArrayBuffer. We only need m+n <= c to slide, but
- // we instead let capacity get twice as large so we
- // don't spend all our time copying.
- copyBytes(this.#buf.subarray(this.#off), this.#buf);
- } else if (c + n > MAX_SIZE) {
- throw new Error("The buffer cannot be grown beyond the maximum size.");
- } else {
- // Not enough space anywhere, we need to allocate.
- const buf = new Uint8Array(Math.min(2 * c + n, MAX_SIZE));
- copyBytes(this.#buf.subarray(this.#off), buf);
- this.#buf = buf;
- }
- // Restore this.#off and len(this.#buf).
- this.#off = 0;
- this.#reslice(Math.min(m + n, MAX_SIZE));
- return m;
- };
-
- grow(n) {
- if (n < 0) {
- throw Error("Buffer.grow: negative count");
- }
- const m = this.#grow(n);
- this.#reslice(m);
- }
-
- async readFrom(r) {
- let n = 0;
- const tmp = new Uint8Array(MIN_READ);
- while (true) {
- const shouldGrow = this.capacity - this.length < MIN_READ;
- // read into tmp buffer if there's not enough room
- // otherwise read directly into the internal buffer
- const buf = shouldGrow
- ? tmp
- : new Uint8Array(this.#buf.buffer, this.length);
-
- const nread = await r.read(buf);
- if (nread === null) {
- return n;
- }
-
- // write will grow if needed
- if (shouldGrow) this.writeSync(buf.subarray(0, nread));
- else this.#reslice(this.length + nread);
-
- n += nread;
- }
- }
-
- readFromSync(r) {
- let n = 0;
- const tmp = new Uint8Array(MIN_READ);
- while (true) {
- const shouldGrow = this.capacity - this.length < MIN_READ;
- // read into tmp buffer if there's not enough room
- // otherwise read directly into the internal buffer
- const buf = shouldGrow
- ? tmp
- : new Uint8Array(this.#buf.buffer, this.length);
-
- const nread = r.readSync(buf);
- if (nread === null) {
- return n;
- }
-
- // write will grow if needed
- if (shouldGrow) this.writeSync(buf.subarray(0, nread));
- else this.#reslice(this.length + nread);
-
- n += nread;
- }
- }
- }
-
- async function readAll(r) {
- const buf = new Buffer();
- await buf.readFrom(r);
- return buf.bytes();
- }
-
- function readAllSync(r) {
- const buf = new Buffer();
- buf.readFromSync(r);
- return buf.bytes();
- }
-
- async function writeAll(w, arr) {
- let nwritten = 0;
- while (nwritten < arr.length) {
- nwritten += await w.write(arr.subarray(nwritten));
- }
- }
-
- function writeAllSync(w, arr) {
- let nwritten = 0;
- while (nwritten < arr.length) {
- nwritten += w.writeSync(arr.subarray(nwritten));
- }
- }
-
- window.__bootstrap.buffer = {
- writeAll,
- writeAllSync,
- readAll,
- readAllSync,
- Buffer,
- };
-})(this);
diff --git a/cli/rt/27_websocket.js b/cli/rt/27_websocket.js
deleted file mode 100644
index 60428c24d..000000000
--- a/cli/rt/27_websocket.js
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { requiredArguments, defineEventHandler } = window.__bootstrap.webUtil;
- const CONNECTING = 0;
- const OPEN = 1;
- const CLOSING = 2;
- const CLOSED = 3;
-
- class WebSocket extends EventTarget {
- #readyState = CONNECTING;
-
- constructor(url, protocols = []) {
- super();
- requiredArguments("WebSocket", arguments.length, 1);
-
- const wsURL = new URL(url);
-
- if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") {
- throw new DOMException(
- "Only ws & wss schemes are allowed in a WebSocket URL.",
- "SyntaxError",
- );
- }
-
- if (wsURL.hash !== "" || wsURL.href.endsWith("#")) {
- throw new DOMException(
- "Fragments are not allowed in a WebSocket URL.",
- "SyntaxError",
- );
- }
-
- this.#url = wsURL.href;
-
- core.jsonOpSync("op_ws_check_permission", {
- url: this.#url,
- });
-
- if (protocols && typeof protocols === "string") {
- protocols = [protocols];
- }
-
- if (
- protocols.some((x) => protocols.indexOf(x) !== protocols.lastIndexOf(x))
- ) {
- throw new DOMException(
- "Can't supply multiple times the same protocol.",
- "SyntaxError",
- );
- }
-
- core.jsonOpAsync("op_ws_create", {
- url: wsURL.href,
- protocols: protocols.join(", "),
- }).then((create) => {
- if (create.success) {
- this.#rid = create.rid;
- this.#extensions = create.extensions;
- this.#protocol = create.protocol;
-
- if (this.#readyState === CLOSING) {
- core.jsonOpAsync("op_ws_close", {
- rid: this.#rid,
- }).then(() => {
- this.#readyState = CLOSED;
-
- const errEvent = new ErrorEvent("error");
- errEvent.target = this;
- this.dispatchEvent(errEvent);
-
- const event = new CloseEvent("close");
- event.target = this;
- this.dispatchEvent(event);
- core.close(this.#rid);
- });
- } else {
- this.#readyState = OPEN;
- const event = new Event("open");
- event.target = this;
- this.dispatchEvent(event);
-
- this.#eventLoop();
- }
- } else {
- this.#readyState = CLOSED;
-
- const errEvent = new ErrorEvent("error");
- errEvent.target = this;
- this.dispatchEvent(errEvent);
-
- const closeEvent = new CloseEvent("close");
- closeEvent.target = this;
- this.dispatchEvent(closeEvent);
- }
- }).catch((err) => {
- this.#readyState = CLOSED;
-
- const errorEv = new ErrorEvent(
- "error",
- { error: err, message: err.toString() },
- );
- errorEv.target = this;
- this.dispatchEvent(errorEv);
-
- const closeEv = new CloseEvent("close");
- closeEv.target = this;
- this.dispatchEvent(closeEv);
- });
- }
-
- get CONNECTING() {
- return CONNECTING;
- }
- get OPEN() {
- return OPEN;
- }
- get CLOSING() {
- return CLOSING;
- }
- get CLOSED() {
- return CLOSED;
- }
-
- get readyState() {
- return this.#readyState;
- }
-
- #extensions = "";
- #protocol = "";
- #url = "";
- #rid;
-
- get extensions() {
- return this.#extensions;
- }
- get protocol() {
- return this.#protocol;
- }
-
- #binaryType = "blob";
- get binaryType() {
- return this.#binaryType;
- }
- set binaryType(value) {
- if (value === "blob" || value === "arraybuffer") {
- this.#binaryType = value;
- }
- }
- #bufferedAmount = 0;
- get bufferedAmount() {
- return this.#bufferedAmount;
- }
-
- get url() {
- return this.#url;
- }
-
- send(data) {
- requiredArguments("WebSocket.send", arguments.length, 1);
-
- if (this.#readyState != OPEN) {
- throw Error("readyState not OPEN");
- }
-
- const sendTypedArray = (ta) => {
- this.#bufferedAmount += ta.size;
- core.jsonOpAsync("op_ws_send", {
- rid: this.#rid,
- }, ta).then(() => {
- this.#bufferedAmount -= ta.size;
- });
- };
-
- if (data instanceof Blob) {
- data.slice().arrayBuffer().then((ab) =>
- sendTypedArray(new DataView(ab))
- );
- } else if (
- data instanceof Int8Array || data instanceof Int16Array ||
- data instanceof Int32Array || data instanceof Uint8Array ||
- data instanceof Uint16Array || data instanceof Uint32Array ||
- data instanceof Uint8ClampedArray || data instanceof Float32Array ||
- data instanceof Float64Array || data instanceof DataView
- ) {
- sendTypedArray(data);
- } else if (data instanceof ArrayBuffer) {
- sendTypedArray(new DataView(data));
- } else {
- const string = String(data);
- const encoder = new TextEncoder();
- const d = encoder.encode(string);
- this.#bufferedAmount += d.size;
- core.jsonOpAsync("op_ws_send", {
- rid: this.#rid,
- text: string,
- }).then(() => {
- this.#bufferedAmount -= d.size;
- });
- }
- }
-
- close(code, reason) {
- if (code && (code !== 1000 && !(3000 <= code > 5000))) {
- throw new DOMException(
- "The close code must be either 1000 or in the range of 3000 to 4999.",
- "NotSupportedError",
- );
- }
-
- const encoder = new TextEncoder();
- if (reason && encoder.encode(reason).byteLength > 123) {
- throw new DOMException(
- "The close reason may not be longer than 123 bytes.",
- "SyntaxError",
- );
- }
-
- if (this.#readyState === CONNECTING) {
- this.#readyState = CLOSING;
- } else if (this.#readyState === OPEN) {
- this.#readyState = CLOSING;
-
- core.jsonOpAsync("op_ws_close", {
- rid: this.#rid,
- code,
- reason,
- }).then(() => {
- this.#readyState = CLOSED;
- const event = new CloseEvent("close", {
- wasClean: true,
- code,
- reason,
- });
- event.target = this;
- this.dispatchEvent(event);
- core.close(this.#rid);
- });
- }
- }
-
- async #eventLoop() {
- if (this.#readyState === OPEN) {
- const message = await core.jsonOpAsync(
- "op_ws_next_event",
- { rid: this.#rid },
- );
- if (message.type === "string" || message.type === "binary") {
- let data;
-
- if (message.type === "string") {
- data = message.data;
- } else {
- if (this.binaryType === "blob") {
- data = new Blob([new Uint8Array(message.data)]);
- } else {
- data = new Uint8Array(message.data).buffer;
- }
- }
-
- const event = new MessageEvent("message", {
- data,
- origin: this.#url,
- });
- event.target = this;
- this.dispatchEvent(event);
-
- this.#eventLoop();
- } else if (message.type === "close") {
- this.#readyState = CLOSED;
- const event = new CloseEvent("close", {
- wasClean: true,
- code: message.code,
- reason: message.reason,
- });
- event.target = this;
- this.dispatchEvent(event);
- } else if (message.type === "error") {
- this.#readyState = CLOSED;
-
- const errorEv = new ErrorEvent("error");
- errorEv.target = this;
- this.dispatchEvent(errorEv);
-
- this.#readyState = CLOSED;
- const closeEv = new CloseEvent("close");
- closeEv.target = this;
- this.dispatchEvent(closeEv);
- }
- }
- }
- }
-
- Object.defineProperties(WebSocket, {
- CONNECTING: {
- value: 0,
- },
- OPEN: {
- value: 1,
- },
- CLOSING: {
- value: 2,
- },
- CLOSED: {
- value: 3,
- },
- });
-
- defineEventHandler(WebSocket.prototype, "message");
- defineEventHandler(WebSocket.prototype, "error");
- defineEventHandler(WebSocket.prototype, "close");
- defineEventHandler(WebSocket.prototype, "open");
- window.__bootstrap.webSocket = {
- WebSocket,
- };
-})(this);
diff --git a/cli/rt/30_files.js b/cli/rt/30_files.js
deleted file mode 100644
index 679b184fd..000000000
--- a/cli/rt/30_files.js
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { read, readSync, write, writeSync } = window.__bootstrap.io;
- const { pathFromURL } = window.__bootstrap.util;
-
- function seekSync(
- rid,
- offset,
- whence,
- ) {
- return core.jsonOpSync("op_seek_sync", { rid, offset, whence });
- }
-
- function seek(
- rid,
- offset,
- whence,
- ) {
- return core.jsonOpAsync("op_seek_async", { rid, offset, whence });
- }
-
- function openSync(
- path,
- options = { read: true },
- ) {
- checkOpenOptions(options);
- const mode = options?.mode;
- const rid = core.jsonOpSync(
- "op_open_sync",
- { path: pathFromURL(path), options, mode },
- );
-
- return new File(rid);
- }
-
- async function open(
- path,
- options = { read: true },
- ) {
- checkOpenOptions(options);
- const mode = options?.mode;
- const rid = await core.jsonOpAsync(
- "op_open_async",
- { path: pathFromURL(path), options, mode },
- );
-
- return new File(rid);
- }
-
- function createSync(path) {
- return openSync(path, {
- read: true,
- write: true,
- truncate: true,
- create: true,
- });
- }
-
- function create(path) {
- return open(path, {
- read: true,
- write: true,
- truncate: true,
- create: true,
- });
- }
-
- class File {
- #rid = 0;
-
- constructor(rid) {
- this.#rid = rid;
- }
-
- get rid() {
- return this.#rid;
- }
-
- write(p) {
- return write(this.rid, p);
- }
-
- writeSync(p) {
- return writeSync(this.rid, p);
- }
-
- read(p) {
- return read(this.rid, p);
- }
-
- readSync(p) {
- return readSync(this.rid, p);
- }
-
- seek(offset, whence) {
- return seek(this.rid, offset, whence);
- }
-
- seekSync(offset, whence) {
- return seekSync(this.rid, offset, whence);
- }
-
- close() {
- core.close(this.rid);
- }
- }
-
- class Stdin {
- constructor() {
- }
-
- get rid() {
- return 0;
- }
-
- read(p) {
- return read(this.rid, p);
- }
-
- readSync(p) {
- return readSync(this.rid, p);
- }
-
- close() {
- core.close(this.rid);
- }
- }
-
- class Stdout {
- constructor() {
- }
-
- get rid() {
- return 1;
- }
-
- write(p) {
- return write(this.rid, p);
- }
-
- writeSync(p) {
- return writeSync(this.rid, p);
- }
-
- close() {
- core.close(this.rid);
- }
- }
-
- class Stderr {
- constructor() {
- }
-
- get rid() {
- return 2;
- }
-
- write(p) {
- return write(this.rid, p);
- }
-
- writeSync(p) {
- return writeSync(this.rid, p);
- }
-
- close() {
- core.close(this.rid);
- }
- }
-
- const stdin = new Stdin();
- const stdout = new Stdout();
- const stderr = new Stderr();
-
- function checkOpenOptions(options) {
- if (Object.values(options).filter((val) => val === true).length === 0) {
- throw new Error("OpenOptions requires at least one option to be true");
- }
-
- if (options.truncate && !options.write) {
- throw new Error("'truncate' option requires 'write' option");
- }
-
- const createOrCreateNewWithoutWriteOrAppend =
- (options.create || options.createNew) &&
- !(options.write || options.append);
-
- if (createOrCreateNewWithoutWriteOrAppend) {
- throw new Error(
- "'create' or 'createNew' options require 'write' or 'append' option",
- );
- }
- }
-
- window.__bootstrap.files = {
- stdin,
- stdout,
- stderr,
- File,
- create,
- createSync,
- open,
- openSync,
- seek,
- seekSync,
- };
-})(this);
diff --git a/cli/rt/30_fs.js b/cli/rt/30_fs.js
deleted file mode 100644
index 33fab01e4..000000000
--- a/cli/rt/30_fs.js
+++ /dev/null
@@ -1,425 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { pathFromURL } = window.__bootstrap.util;
- const build = window.__bootstrap.build.build;
-
- function chmodSync(path, mode) {
- core.jsonOpSync("op_chmod_sync", { path: pathFromURL(path), mode });
- }
-
- async function chmod(path, mode) {
- await core.jsonOpAsync("op_chmod_async", { path: pathFromURL(path), mode });
- }
-
- function chownSync(
- path,
- uid,
- gid,
- ) {
- core.jsonOpSync("op_chown_sync", { path: pathFromURL(path), uid, gid });
- }
-
- async function chown(
- path,
- uid,
- gid,
- ) {
- await core.jsonOpAsync(
- "op_chown_async",
- { path: pathFromURL(path), uid, gid },
- );
- }
-
- function copyFileSync(
- fromPath,
- toPath,
- ) {
- core.jsonOpSync("op_copy_file_sync", {
- from: pathFromURL(fromPath),
- to: pathFromURL(toPath),
- });
- }
-
- async function copyFile(
- fromPath,
- toPath,
- ) {
- await core.jsonOpAsync("op_copy_file_async", {
- from: pathFromURL(fromPath),
- to: pathFromURL(toPath),
- });
- }
-
- function cwd() {
- return core.jsonOpSync("op_cwd");
- }
-
- function chdir(directory) {
- core.jsonOpSync("op_chdir", { directory });
- }
-
- function makeTempDirSync(options = {}) {
- return core.jsonOpSync("op_make_temp_dir_sync", options);
- }
-
- function makeTempDir(options = {}) {
- return core.jsonOpAsync("op_make_temp_dir_async", options);
- }
-
- function makeTempFileSync(options = {}) {
- return core.jsonOpSync("op_make_temp_file_sync", options);
- }
-
- function makeTempFile(options = {}) {
- return core.jsonOpAsync("op_make_temp_file_async", options);
- }
-
- function mkdirArgs(path, options) {
- const args = { path: pathFromURL(path), recursive: false };
- if (options != null) {
- if (typeof options.recursive == "boolean") {
- args.recursive = options.recursive;
- }
- if (options.mode) {
- args.mode = options.mode;
- }
- }
- return args;
- }
-
- function mkdirSync(path, options) {
- core.jsonOpSync("op_mkdir_sync", mkdirArgs(path, options));
- }
-
- async function mkdir(
- path,
- options,
- ) {
- await core.jsonOpAsync("op_mkdir_async", mkdirArgs(path, options));
- }
-
- function res(response) {
- return response.entries;
- }
-
- function readDirSync(path) {
- return res(
- core.jsonOpSync("op_read_dir_sync", { path: pathFromURL(path) }),
- )[
- Symbol.iterator
- ]();
- }
-
- function readDir(path) {
- const array = core.jsonOpAsync(
- "op_read_dir_async",
- { path: pathFromURL(path) },
- )
- .then(
- res,
- );
- return {
- async *[Symbol.asyncIterator]() {
- yield* await array;
- },
- };
- }
-
- function readLinkSync(path) {
- return core.jsonOpSync("op_read_link_sync", { path: pathFromURL(path) });
- }
-
- function readLink(path) {
- return core.jsonOpAsync("op_read_link_async", { path: pathFromURL(path) });
- }
-
- function realPathSync(path) {
- return core.jsonOpSync("op_realpath_sync", { path });
- }
-
- function realPath(path) {
- return core.jsonOpAsync("op_realpath_async", { path });
- }
-
- function removeSync(
- path,
- options = {},
- ) {
- core.jsonOpSync("op_remove_sync", {
- path: pathFromURL(path),
- recursive: !!options.recursive,
- });
- }
-
- async function remove(
- path,
- options = {},
- ) {
- await core.jsonOpAsync("op_remove_async", {
- path: pathFromURL(path),
- recursive: !!options.recursive,
- });
- }
-
- function renameSync(oldpath, newpath) {
- core.jsonOpSync("op_rename_sync", { oldpath, newpath });
- }
-
- async function rename(oldpath, newpath) {
- await core.jsonOpAsync("op_rename_async", { oldpath, newpath });
- }
-
- function parseFileInfo(response) {
- const unix = build.os === "darwin" || build.os === "linux";
- return {
- isFile: response.isFile,
- isDirectory: response.isDirectory,
- isSymlink: response.isSymlink,
- size: response.size,
- mtime: response.mtime != null ? new Date(response.mtime) : null,
- atime: response.atime != null ? new Date(response.atime) : null,
- birthtime: response.birthtime != null
- ? new Date(response.birthtime)
- : null,
- // Only non-null if on Unix
- dev: unix ? response.dev : null,
- ino: unix ? response.ino : null,
- mode: unix ? response.mode : null,
- nlink: unix ? response.nlink : null,
- uid: unix ? response.uid : null,
- gid: unix ? response.gid : null,
- rdev: unix ? response.rdev : null,
- blksize: unix ? response.blksize : null,
- blocks: unix ? response.blocks : null,
- };
- }
-
- function fstatSync(rid) {
- return parseFileInfo(core.jsonOpSync("op_fstat_sync", { rid }));
- }
-
- async function fstat(rid) {
- return parseFileInfo(await core.jsonOpAsync("op_fstat_async", { rid }));
- }
-
- async function lstat(path) {
- const res = await core.jsonOpAsync("op_stat_async", {
- path: pathFromURL(path),
- lstat: true,
- });
- return parseFileInfo(res);
- }
-
- function lstatSync(path) {
- const res = core.jsonOpSync("op_stat_sync", {
- path: pathFromURL(path),
- lstat: true,
- });
- return parseFileInfo(res);
- }
-
- async function stat(path) {
- const res = await core.jsonOpAsync("op_stat_async", {
- path: pathFromURL(path),
- lstat: false,
- });
- return parseFileInfo(res);
- }
-
- function statSync(path) {
- const res = core.jsonOpSync("op_stat_sync", {
- path: pathFromURL(path),
- lstat: false,
- });
- return parseFileInfo(res);
- }
-
- function coerceLen(len) {
- if (len == null || len < 0) {
- return 0;
- }
-
- return len;
- }
-
- function ftruncateSync(rid, len) {
- core.jsonOpSync("op_ftruncate_sync", { rid, len: coerceLen(len) });
- }
-
- async function ftruncate(rid, len) {
- await core.jsonOpAsync("op_ftruncate_async", { rid, len: coerceLen(len) });
- }
-
- function truncateSync(path, len) {
- core.jsonOpSync("op_truncate_sync", { path, len: coerceLen(len) });
- }
-
- async function truncate(path, len) {
- await core.jsonOpAsync("op_truncate_async", { path, len: coerceLen(len) });
- }
-
- function umask(mask) {
- return core.jsonOpSync("op_umask", { mask });
- }
-
- function linkSync(oldpath, newpath) {
- core.jsonOpSync("op_link_sync", { oldpath, newpath });
- }
-
- async function link(oldpath, newpath) {
- await core.jsonOpAsync("op_link_async", { oldpath, newpath });
- }
-
- function toUnixTimeFromEpoch(value) {
- if (value instanceof Date) {
- const time = value.valueOf();
- const seconds = Math.trunc(time / 1e3);
- const nanoseconds = Math.trunc(time - (seconds * 1e3)) * 1e6;
-
- return [
- seconds,
- nanoseconds,
- ];
- }
-
- const seconds = value;
- const nanoseconds = 0;
-
- return [
- seconds,
- nanoseconds,
- ];
- }
-
- function futimeSync(
- rid,
- atime,
- mtime,
- ) {
- core.jsonOpSync("op_futime_sync", {
- rid,
- atime: toUnixTimeFromEpoch(atime),
- mtime: toUnixTimeFromEpoch(mtime),
- });
- }
-
- async function futime(
- rid,
- atime,
- mtime,
- ) {
- await core.jsonOpAsync("op_futime_async", {
- rid,
- atime: toUnixTimeFromEpoch(atime),
- mtime: toUnixTimeFromEpoch(mtime),
- });
- }
-
- function utimeSync(
- path,
- atime,
- mtime,
- ) {
- core.jsonOpSync("op_utime_sync", {
- path,
- atime: toUnixTimeFromEpoch(atime),
- mtime: toUnixTimeFromEpoch(mtime),
- });
- }
-
- async function utime(
- path,
- atime,
- mtime,
- ) {
- await core.jsonOpAsync("op_utime_async", {
- path,
- atime: toUnixTimeFromEpoch(atime),
- mtime: toUnixTimeFromEpoch(mtime),
- });
- }
-
- function symlinkSync(
- oldpath,
- newpath,
- options,
- ) {
- core.jsonOpSync("op_symlink_sync", { oldpath, newpath, options });
- }
-
- async function symlink(
- oldpath,
- newpath,
- options,
- ) {
- await core.jsonOpAsync("op_symlink_async", { oldpath, newpath, options });
- }
-
- function fdatasyncSync(rid) {
- core.jsonOpSync("op_fdatasync_sync", { rid });
- }
-
- async function fdatasync(rid) {
- await core.jsonOpAsync("op_fdatasync_async", { rid });
- }
-
- function fsyncSync(rid) {
- core.jsonOpSync("op_fsync_sync", { rid });
- }
-
- async function fsync(rid) {
- await core.jsonOpAsync("op_fsync_async", { rid });
- }
-
- window.__bootstrap.fs = {
- cwd,
- chdir,
- chmodSync,
- chmod,
- chown,
- chownSync,
- copyFile,
- copyFileSync,
- makeTempFile,
- makeTempDir,
- makeTempFileSync,
- makeTempDirSync,
- mkdir,
- mkdirSync,
- readDir,
- readDirSync,
- readLinkSync,
- readLink,
- realPathSync,
- realPath,
- remove,
- removeSync,
- renameSync,
- rename,
- fstatSync,
- fstat,
- lstat,
- lstatSync,
- stat,
- statSync,
- ftruncate,
- ftruncateSync,
- truncate,
- truncateSync,
- umask,
- link,
- linkSync,
- futime,
- futimeSync,
- utime,
- utimeSync,
- symlink,
- symlinkSync,
- fdatasync,
- fdatasyncSync,
- fsync,
- fsyncSync,
- };
-})(this);
diff --git a/cli/rt/30_metrics.js b/cli/rt/30_metrics.js
deleted file mode 100644
index d44a629cb..000000000
--- a/cli/rt/30_metrics.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
-
- function metrics() {
- return core.jsonOpSync("op_metrics");
- }
-
- window.__bootstrap.metrics = {
- metrics,
- };
-})(this);
diff --git a/cli/rt/30_net.js b/cli/rt/30_net.js
deleted file mode 100644
index 9a71f0693..000000000
--- a/cli/rt/30_net.js
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { errors } = window.__bootstrap.errors;
- const { read, write } = window.__bootstrap.io;
-
- const ShutdownMode = {
- // See http://man7.org/linux/man-pages/man2/shutdown.2.html
- // Corresponding to SHUT_RD, SHUT_WR, SHUT_RDWR
- 0: "Read",
- 1: "Write",
- 2: "ReadWrite",
- Read: 0,
- Write: 1,
- ReadWrite: 2, // unused
- };
-
- function shutdown(rid, how) {
- core.jsonOpSync("op_shutdown", { rid, how });
- return Promise.resolve();
- }
-
- function opAccept(
- rid,
- transport,
- ) {
- return core.jsonOpAsync("op_accept", { rid, transport });
- }
-
- function opListen(args) {
- return core.jsonOpSync("op_listen", args);
- }
-
- function opConnect(args) {
- return core.jsonOpAsync("op_connect", args);
- }
-
- function opReceive(
- rid,
- transport,
- zeroCopy,
- ) {
- return core.jsonOpAsync(
- "op_datagram_receive",
- { rid, transport },
- zeroCopy,
- );
- }
-
- function opSend(args, zeroCopy) {
- return core.jsonOpAsync("op_datagram_send", args, zeroCopy);
- }
-
- class Conn {
- #rid = 0;
- #remoteAddr = null;
- #localAddr = null;
- constructor(
- rid,
- remoteAddr,
- localAddr,
- ) {
- this.#rid = rid;
- this.#remoteAddr = remoteAddr;
- this.#localAddr = localAddr;
- }
-
- get rid() {
- return this.#rid;
- }
-
- get remoteAddr() {
- return this.#remoteAddr;
- }
-
- get localAddr() {
- return this.#localAddr;
- }
-
- write(p) {
- return write(this.rid, p);
- }
-
- read(p) {
- return read(this.rid, p);
- }
-
- close() {
- core.close(this.rid);
- }
-
- // TODO(lucacasonato): make this unavailable in stable
- closeWrite() {
- shutdown(this.rid, ShutdownMode.Write);
- }
- }
-
- class Listener {
- #rid = 0;
- #addr = null;
-
- constructor(rid, addr) {
- this.#rid = rid;
- this.#addr = addr;
- }
-
- get rid() {
- return this.#rid;
- }
-
- get addr() {
- return this.#addr;
- }
-
- async accept() {
- const res = await opAccept(this.rid, this.addr.transport);
- return new Conn(res.rid, res.remoteAddr, res.localAddr);
- }
-
- async next() {
- let conn;
- try {
- conn = await this.accept();
- } catch (error) {
- if (error instanceof errors.BadResource) {
- return { value: undefined, done: true };
- }
- throw error;
- }
- return { value: conn, done: false };
- }
-
- return(value) {
- this.close();
- return Promise.resolve({ value, done: true });
- }
-
- close() {
- core.close(this.rid);
- }
-
- [Symbol.asyncIterator]() {
- return this;
- }
- }
-
- class Datagram {
- #rid = 0;
- #addr = null;
-
- constructor(
- rid,
- addr,
- bufSize = 1024,
- ) {
- this.#rid = rid;
- this.#addr = addr;
- this.bufSize = bufSize;
- }
-
- get rid() {
- return this.#rid;
- }
-
- get addr() {
- return this.#addr;
- }
-
- async receive(p) {
- const buf = p || new Uint8Array(this.bufSize);
- const { size, remoteAddr } = await opReceive(
- this.rid,
- this.addr.transport,
- buf,
- );
- const sub = buf.subarray(0, size);
- return [sub, remoteAddr];
- }
-
- send(p, addr) {
- const remote = { hostname: "127.0.0.1", ...addr };
-
- const args = { ...remote, rid: this.rid };
- return opSend(args, p);
- }
-
- close() {
- core.close(this.rid);
- }
-
- async *[Symbol.asyncIterator]() {
- while (true) {
- try {
- yield await this.receive();
- } catch (err) {
- if (err instanceof errors.BadResource) {
- break;
- }
- throw err;
- }
- }
- }
- }
-
- function listen({ hostname, ...options }) {
- const res = opListen({
- transport: "tcp",
- hostname: typeof hostname === "undefined" ? "0.0.0.0" : hostname,
- ...options,
- });
-
- return new Listener(res.rid, res.localAddr);
- }
-
- async function connect(
- options,
- ) {
- let res;
-
- if (options.transport === "unix") {
- res = await opConnect(options);
- } else {
- res = await opConnect({
- transport: "tcp",
- hostname: "127.0.0.1",
- ...options,
- });
- }
-
- return new Conn(res.rid, res.remoteAddr, res.localAddr);
- }
-
- window.__bootstrap.net = {
- connect,
- Conn,
- opConnect,
- listen,
- opListen,
- Listener,
- shutdown,
- ShutdownMode,
- Datagram,
- };
-})(this);
diff --git a/cli/rt/30_os.js b/cli/rt/30_os.js
deleted file mode 100644
index ebc4e8916..000000000
--- a/cli/rt/30_os.js
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
-
- function loadavg() {
- return core.jsonOpSync("op_loadavg");
- }
-
- function hostname() {
- return core.jsonOpSync("op_hostname");
- }
-
- function osRelease() {
- return core.jsonOpSync("op_os_release");
- }
-
- function systemMemoryInfo() {
- return core.jsonOpSync("op_system_memory_info");
- }
-
- function systemCpuInfo() {
- return core.jsonOpSync("op_system_cpu_info");
- }
-
- function exit(code = 0) {
- core.jsonOpSync("op_exit", { code });
- throw new Error("Code not reachable");
- }
-
- function setEnv(key, value) {
- core.jsonOpSync("op_set_env", { key, value });
- }
-
- function getEnv(key) {
- return core.jsonOpSync("op_get_env", { key })[0];
- }
-
- function deleteEnv(key) {
- core.jsonOpSync("op_delete_env", { key });
- }
-
- const env = {
- get: getEnv,
- toObject() {
- return core.jsonOpSync("op_env");
- },
- set: setEnv,
- delete: deleteEnv,
- };
-
- function execPath() {
- return core.jsonOpSync("op_exec_path");
- }
-
- window.__bootstrap.os = {
- env,
- execPath,
- exit,
- osRelease,
- systemMemoryInfo,
- systemCpuInfo,
- hostname,
- loadavg,
- };
-})(this);
diff --git a/cli/rt/40_compiler_api.js b/cli/rt/40_compiler_api.js
deleted file mode 100644
index ea963b67b..000000000
--- a/cli/rt/40_compiler_api.js
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-// This file contains the runtime APIs which will dispatch work to the internal
-// compiler within Deno.
-((window) => {
- const core = window.Deno.core;
- const util = window.__bootstrap.util;
-
- function opCompile(request) {
- return core.jsonOpAsync("op_compile", request);
- }
-
- function opTranspile(
- request,
- ) {
- return core.jsonOpAsync("op_transpile", request);
- }
-
- function checkRelative(specifier) {
- return specifier.match(/^([\.\/\\]|https?:\/{2}|file:\/{2})/)
- ? specifier
- : `./${specifier}`;
- }
-
- // TODO(bartlomieju): change return type to interface?
- function transpileOnly(
- sources,
- options = {},
- ) {
- util.log("Deno.transpileOnly", { sources: Object.keys(sources), options });
- const payload = {
- sources,
- options: JSON.stringify(options),
- };
- return opTranspile(payload);
- }
-
- // TODO(bartlomieju): change return type to interface?
- async function compile(
- rootName,
- sources,
- options = {},
- ) {
- const payload = {
- rootName: sources ? rootName : checkRelative(rootName),
- sources,
- options: JSON.stringify(options),
- bundle: false,
- };
- util.log("Deno.compile", {
- rootName: payload.rootName,
- sources: !!sources,
- options,
- });
- /** @type {{ emittedFiles: Record<string, string>, diagnostics: any[] }} */
- const result = await opCompile(payload);
- util.assert(result.emittedFiles);
- const maybeDiagnostics = result.diagnostics.length === 0
- ? undefined
- : result.diagnostics;
-
- return [maybeDiagnostics, result.emittedFiles];
- }
-
- // TODO(bartlomieju): change return type to interface?
- async function bundle(
- rootName,
- sources,
- options = {},
- ) {
- const payload = {
- rootName: sources ? rootName : checkRelative(rootName),
- sources,
- options: JSON.stringify(options),
- bundle: true,
- };
- util.log("Deno.bundle", {
- rootName: payload.rootName,
- sources: !!sources,
- options,
- });
- /** @type {{ emittedFiles: Record<string, string>, diagnostics: any[] }} */
- const result = await opCompile(payload);
- const output = result.emittedFiles["deno:///bundle.js"];
- util.assert(output);
- const maybeDiagnostics = result.diagnostics.length === 0
- ? undefined
- : result.diagnostics;
- return [maybeDiagnostics, output];
- }
-
- window.__bootstrap.compilerApi = {
- bundle,
- compile,
- transpileOnly,
- };
-})(this);
diff --git a/cli/rt/40_diagnostics.js b/cli/rt/40_diagnostics.js
deleted file mode 100644
index 2b7457853..000000000
--- a/cli/rt/40_diagnostics.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-// Diagnostic provides an abstraction for advice/errors received from a
-// compiler, which is strongly influenced by the format of TypeScript
-// diagnostics.
-
-((window) => {
- const DiagnosticCategory = {
- 0: "Warning",
- 1: "Error",
- 2: "Suggestion",
- 3: "Message",
-
- Warning: 0,
- Error: 1,
- Suggestion: 2,
- Message: 3,
- };
-
- window.__bootstrap.diagnostics = {
- DiagnosticCategory,
- };
-})(this);
diff --git a/cli/rt/40_error_stack.js b/cli/rt/40_error_stack.js
deleted file mode 100644
index da2ee51f3..000000000
--- a/cli/rt/40_error_stack.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
-
- function opFormatDiagnostics(diagnostics) {
- return core.jsonOpSync("op_format_diagnostic", diagnostics);
- }
-
- function opApplySourceMap(location) {
- const res = core.jsonOpSync("op_apply_source_map", location);
- return {
- fileName: res.fileName,
- lineNumber: res.lineNumber,
- columnNumber: res.columnNumber,
- };
- }
-
- window.__bootstrap.errorStack = {
- opApplySourceMap,
- opFormatDiagnostics,
- };
-})(this);
diff --git a/cli/rt/40_fs_events.js b/cli/rt/40_fs_events.js
deleted file mode 100644
index a36adecba..000000000
--- a/cli/rt/40_fs_events.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { errors } = window.__bootstrap.errors;
-
- class FsWatcher {
- #rid = 0;
-
- constructor(paths, options) {
- const { recursive } = options;
- this.#rid = core.jsonOpSync("op_fs_events_open", { recursive, paths });
- }
-
- get rid() {
- return this.#rid;
- }
-
- async next() {
- try {
- return await core.jsonOpAsync("op_fs_events_poll", {
- rid: this.rid,
- });
- } catch (error) {
- if (error instanceof errors.BadResource) {
- return { value: undefined, done: true };
- }
- throw error;
- }
- }
-
- return(value) {
- core.close(this.rid);
- return Promise.resolve({ value, done: true });
- }
-
- [Symbol.asyncIterator]() {
- return this;
- }
- }
-
- function watchFs(
- paths,
- options = { recursive: true },
- ) {
- return new FsWatcher(Array.isArray(paths) ? paths : [paths], options);
- }
-
- window.__bootstrap.fsEvents = {
- watchFs,
- };
-})(this);
diff --git a/cli/rt/40_net_unstable.js b/cli/rt/40_net_unstable.js
deleted file mode 100644
index fcc899a30..000000000
--- a/cli/rt/40_net_unstable.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const net = window.__bootstrap.net;
-
- function listen(options) {
- if (options.transport === "unix") {
- const res = net.opListen(options);
- return new net.Listener(res.rid, res.localAddr);
- } else {
- return net.listen(options);
- }
- }
-
- function listenDatagram(
- options,
- ) {
- let res;
- if (options.transport === "unixpacket") {
- res = net.opListen(options);
- } else {
- res = net.opListen({
- transport: "udp",
- hostname: "127.0.0.1",
- ...options,
- });
- }
-
- return new net.Datagram(res.rid, res.localAddr);
- }
-
- async function connect(
- options,
- ) {
- if (options.transport === "unix") {
- const res = await net.opConnect(options);
- return new net.Conn(res.rid, res.remoteAddr, res.localAddr);
- } else {
- return net.connect(options);
- }
- }
-
- window.__bootstrap.netUnstable = {
- connect,
- listenDatagram,
- listen,
- };
-})(this);
diff --git a/cli/rt/40_performance.js b/cli/rt/40_performance.js
deleted file mode 100644
index 0a63dc704..000000000
--- a/cli/rt/40_performance.js
+++ /dev/null
@@ -1,341 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const { opNow } = window.__bootstrap.timers;
- const { cloneValue, illegalConstructorKey } = window.__bootstrap.webUtil;
-
- const customInspect = Symbol.for("Deno.customInspect");
- let performanceEntries = [];
-
- function findMostRecent(
- name,
- type,
- ) {
- return performanceEntries
- .slice()
- .reverse()
- .find((entry) => entry.name === name && entry.entryType === type);
- }
-
- function convertMarkToTimestamp(mark) {
- if (typeof mark === "string") {
- const entry = findMostRecent(mark, "mark");
- if (!entry) {
- throw new SyntaxError(`Cannot find mark: "${mark}".`);
- }
- return entry.startTime;
- }
- if (mark < 0) {
- throw new TypeError("Mark cannot be negative.");
- }
- return mark;
- }
-
- function filterByNameType(
- name,
- type,
- ) {
- return performanceEntries.filter(
- (entry) =>
- (name ? entry.name === name : true) &&
- (type ? entry.entryType === type : true),
- );
- }
-
- function now() {
- return opNow();
- }
-
- class PerformanceEntry {
- #name = "";
- #entryType = "";
- #startTime = 0;
- #duration = 0;
-
- get name() {
- return this.#name;
- }
-
- get entryType() {
- return this.#entryType;
- }
-
- get startTime() {
- return this.#startTime;
- }
-
- get duration() {
- return this.#duration;
- }
-
- constructor(
- name = null,
- entryType = null,
- startTime = null,
- duration = null,
- key = null,
- ) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- this.#name = name;
- this.#entryType = entryType;
- this.#startTime = startTime;
- this.#duration = duration;
- }
-
- toJSON() {
- return {
- name: this.#name,
- entryType: this.#entryType,
- startTime: this.#startTime,
- duration: this.#duration,
- };
- }
-
- [customInspect]() {
- return `${this.constructor.name} { name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
- }
- }
-
- class PerformanceMark extends PerformanceEntry {
- #detail = null;
-
- get detail() {
- return this.#detail;
- }
-
- get entryType() {
- return "mark";
- }
-
- constructor(
- name,
- { detail = null, startTime = now() } = {},
- ) {
- super(name, "mark", startTime, 0, illegalConstructorKey);
- if (startTime < 0) {
- throw new TypeError("startTime cannot be negative");
- }
- this.#detail = cloneValue(detail);
- }
-
- toJSON() {
- return {
- name: this.name,
- entryType: this.entryType,
- startTime: this.startTime,
- duration: this.duration,
- detail: this.detail,
- };
- }
-
- [customInspect]() {
- return this.detail
- ? `${this.constructor.name} {\n detail: ${
- JSON.stringify(this.detail, null, 2)
- },\n name: "${this.name}",\n entryType: "${this.entryType}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}`
- : `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
- }
- }
-
- class PerformanceMeasure extends PerformanceEntry {
- #detail = null;
-
- get detail() {
- return this.#detail;
- }
-
- get entryType() {
- return "measure";
- }
-
- constructor(
- name,
- startTime,
- duration,
- detail = null,
- key,
- ) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- super(name, "measure", startTime, duration, illegalConstructorKey);
- this.#detail = cloneValue(detail);
- }
-
- toJSON() {
- return {
- name: this.name,
- entryType: this.entryType,
- startTime: this.startTime,
- duration: this.duration,
- detail: this.detail,
- };
- }
-
- [customInspect]() {
- return this.detail
- ? `${this.constructor.name} {\n detail: ${
- JSON.stringify(this.detail, null, 2)
- },\n name: "${this.name}",\n entryType: "${this.entryType}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}`
- : `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
- }
- }
-
- class Performance {
- constructor(key = null) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- }
-
- clearMarks(markName) {
- if (markName == null) {
- performanceEntries = performanceEntries.filter(
- (entry) => entry.entryType !== "mark",
- );
- } else {
- performanceEntries = performanceEntries.filter(
- (entry) => !(entry.name === markName && entry.entryType === "mark"),
- );
- }
- }
-
- clearMeasures(measureName) {
- if (measureName == null) {
- performanceEntries = performanceEntries.filter(
- (entry) => entry.entryType !== "measure",
- );
- } else {
- performanceEntries = performanceEntries.filter(
- (entry) =>
- !(entry.name === measureName && entry.entryType === "measure"),
- );
- }
- }
-
- getEntries() {
- return filterByNameType();
- }
-
- getEntriesByName(
- name,
- type,
- ) {
- return filterByNameType(name, type);
- }
-
- getEntriesByType(type) {
- return filterByNameType(undefined, type);
- }
-
- mark(
- markName,
- options = {},
- ) {
- // 3.1.1.1 If the global object is a Window object and markName uses the
- // same name as a read only attribute in the PerformanceTiming interface,
- // throw a SyntaxError. - not implemented
- const entry = new PerformanceMark(markName, options);
- // 3.1.1.7 Queue entry - not implemented
- performanceEntries.push(entry);
- return entry;
- }
-
- measure(
- measureName,
- startOrMeasureOptions = {},
- endMark,
- ) {
- if (
- startOrMeasureOptions && typeof startOrMeasureOptions === "object" &&
- Object.keys(startOrMeasureOptions).length > 0
- ) {
- if (endMark) {
- throw new TypeError("Options cannot be passed with endMark.");
- }
- if (
- !("start" in startOrMeasureOptions) &&
- !("end" in startOrMeasureOptions)
- ) {
- throw new TypeError(
- "A start or end mark must be supplied in options.",
- );
- }
- if (
- "start" in startOrMeasureOptions &&
- "duration" in startOrMeasureOptions &&
- "end" in startOrMeasureOptions
- ) {
- throw new TypeError(
- "Cannot specify start, end, and duration together in options.",
- );
- }
- }
- let endTime;
- if (endMark) {
- endTime = convertMarkToTimestamp(endMark);
- } else if (
- typeof startOrMeasureOptions === "object" &&
- "end" in startOrMeasureOptions
- ) {
- endTime = convertMarkToTimestamp(startOrMeasureOptions.end);
- } else if (
- typeof startOrMeasureOptions === "object" &&
- "start" in startOrMeasureOptions &&
- "duration" in startOrMeasureOptions
- ) {
- const start = convertMarkToTimestamp(startOrMeasureOptions.start);
- const duration = convertMarkToTimestamp(startOrMeasureOptions.duration);
- endTime = start + duration;
- } else {
- endTime = now();
- }
- let startTime;
- if (
- typeof startOrMeasureOptions === "object" &&
- "start" in startOrMeasureOptions
- ) {
- startTime = convertMarkToTimestamp(startOrMeasureOptions.start);
- } else if (
- typeof startOrMeasureOptions === "object" &&
- "end" in startOrMeasureOptions &&
- "duration" in startOrMeasureOptions
- ) {
- const end = convertMarkToTimestamp(startOrMeasureOptions.end);
- const duration = convertMarkToTimestamp(startOrMeasureOptions.duration);
- startTime = end - duration;
- } else if (typeof startOrMeasureOptions === "string") {
- startTime = convertMarkToTimestamp(startOrMeasureOptions);
- } else {
- startTime = 0;
- }
- const entry = new PerformanceMeasure(
- measureName,
- startTime,
- endTime - startTime,
- typeof startOrMeasureOptions === "object"
- ? startOrMeasureOptions.detail ?? null
- : null,
- illegalConstructorKey,
- );
- performanceEntries.push(entry);
- return entry;
- }
-
- now() {
- return now();
- }
- }
-
- const performance = new Performance(illegalConstructorKey);
-
- window.__bootstrap.performance = {
- PerformanceEntry,
- PerformanceMark,
- PerformanceMeasure,
- Performance,
- performance,
- };
-})(this);
diff --git a/cli/rt/40_permissions.js b/cli/rt/40_permissions.js
deleted file mode 100644
index 50d471b6a..000000000
--- a/cli/rt/40_permissions.js
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { illegalConstructorKey } = window.__bootstrap.webUtil;
-
- function opQuery(desc) {
- return core.jsonOpSync("op_query_permission", desc).state;
- }
-
- function opRevoke(desc) {
- return core.jsonOpSync("op_revoke_permission", desc).state;
- }
-
- function opRequest(desc) {
- return core.jsonOpSync("op_request_permission", desc).state;
- }
-
- class PermissionStatus {
- constructor(state = null, key = null) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- this.state = state;
- }
- // TODO(kt3k): implement onchange handler
- }
-
- class Permissions {
- constructor(key) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- }
-
- query(desc) {
- const state = opQuery(desc);
- return Promise.resolve(
- new PermissionStatus(state, illegalConstructorKey),
- );
- }
-
- revoke(desc) {
- const state = opRevoke(desc);
- return Promise.resolve(
- new PermissionStatus(state, illegalConstructorKey),
- );
- }
-
- request(desc) {
- const state = opRequest(desc);
- return Promise.resolve(
- new PermissionStatus(state, illegalConstructorKey),
- );
- }
- }
-
- const permissions = new Permissions(illegalConstructorKey);
-
- window.__bootstrap.permissions = {
- permissions,
- Permissions,
- PermissionStatus,
- };
-})(this);
diff --git a/cli/rt/40_plugins.js b/cli/rt/40_plugins.js
deleted file mode 100644
index f5aefd400..000000000
--- a/cli/rt/40_plugins.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
-
- function openPlugin(filename) {
- return core.jsonOpSync("op_open_plugin", { filename });
- }
-
- window.__bootstrap.plugins = {
- openPlugin,
- };
-})(this);
diff --git a/cli/rt/40_process.js b/cli/rt/40_process.js
deleted file mode 100644
index b46a1aead..000000000
--- a/cli/rt/40_process.js
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { File } = window.__bootstrap.files;
- const { readAll } = window.__bootstrap.buffer;
- const { assert, pathFromURL } = window.__bootstrap.util;
-
- function opKill(pid, signo) {
- core.jsonOpSync("op_kill", { pid, signo });
- }
-
- function opRunStatus(rid) {
- return core.jsonOpAsync("op_run_status", { rid });
- }
-
- function opRun(request) {
- assert(request.cmd.length > 0);
- return core.jsonOpSync("op_run", request);
- }
-
- async function runStatus(rid) {
- const res = await opRunStatus(rid);
-
- if (res.gotSignal) {
- const signal = res.exitSignal;
- return { success: false, code: 128 + signal, signal };
- } else if (res.exitCode != 0) {
- return { success: false, code: res.exitCode };
- } else {
- return { success: true, code: 0 };
- }
- }
-
- class Process {
- constructor(res) {
- this.rid = res.rid;
- this.pid = res.pid;
-
- if (res.stdinRid && res.stdinRid > 0) {
- this.stdin = new File(res.stdinRid);
- }
-
- if (res.stdoutRid && res.stdoutRid > 0) {
- this.stdout = new File(res.stdoutRid);
- }
-
- if (res.stderrRid && res.stderrRid > 0) {
- this.stderr = new File(res.stderrRid);
- }
- }
-
- status() {
- return runStatus(this.rid);
- }
-
- async output() {
- if (!this.stdout) {
- throw new TypeError("stdout was not piped");
- }
- try {
- return await readAll(this.stdout);
- } finally {
- this.stdout.close();
- }
- }
-
- async stderrOutput() {
- if (!this.stderr) {
- throw new TypeError("stderr was not piped");
- }
- try {
- return await readAll(this.stderr);
- } finally {
- this.stderr.close();
- }
- }
-
- close() {
- core.close(this.rid);
- }
-
- kill(signo) {
- opKill(this.pid, signo);
- }
- }
-
- function isRid(arg) {
- return !isNaN(arg);
- }
-
- function run({
- cmd,
- cwd = undefined,
- env = {},
- stdout = "inherit",
- stderr = "inherit",
- stdin = "inherit",
- }) {
- if (cmd[0] != null) {
- cmd[0] = pathFromURL(cmd[0]);
- }
- const res = opRun({
- cmd: cmd.map(String),
- cwd,
- env: Object.entries(env),
- stdin: isRid(stdin) ? "" : stdin,
- stdout: isRid(stdout) ? "" : stdout,
- stderr: isRid(stderr) ? "" : stderr,
- stdinRid: isRid(stdin) ? stdin : 0,
- stdoutRid: isRid(stdout) ? stdout : 0,
- stderrRid: isRid(stderr) ? stderr : 0,
- });
- return new Process(res);
- }
-
- window.__bootstrap.process = {
- run,
- Process,
- kill: opKill,
- };
-})(this);
diff --git a/cli/rt/40_read_file.js b/cli/rt/40_read_file.js
deleted file mode 100644
index 9a36f335b..000000000
--- a/cli/rt/40_read_file.js
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const { open, openSync } = window.__bootstrap.files;
- const { readAll, readAllSync } = window.__bootstrap.buffer;
-
- function readFileSync(path) {
- const file = openSync(path);
- const contents = readAllSync(file);
- file.close();
- return contents;
- }
-
- async function readFile(path) {
- const file = await open(path);
- const contents = await readAll(file);
- file.close();
- return contents;
- }
-
- function readTextFileSync(path) {
- const file = openSync(path);
- const contents = readAllSync(file);
- file.close();
- const decoder = new TextDecoder();
- return decoder.decode(contents);
- }
-
- async function readTextFile(path) {
- const file = await open(path);
- const contents = await readAll(file);
- file.close();
- const decoder = new TextDecoder();
- return decoder.decode(contents);
- }
-
- window.__bootstrap.readFile = {
- readFile,
- readFileSync,
- readTextFileSync,
- readTextFile,
- };
-})(this);
diff --git a/cli/rt/40_signals.js b/cli/rt/40_signals.js
deleted file mode 100644
index 739c963fd..000000000
--- a/cli/rt/40_signals.js
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { build } = window.__bootstrap.build;
-
- function bindSignal(signo) {
- return core.jsonOpSync("op_signal_bind", { signo });
- }
-
- function pollSignal(rid) {
- return core.jsonOpAsync("op_signal_poll", { rid });
- }
-
- function unbindSignal(rid) {
- core.jsonOpSync("op_signal_unbind", { rid });
- }
-
- // From `kill -l`
- const LinuxSignal = {
- 1: "SIGHUP",
- 2: "SIGINT",
- 3: "SIGQUIT",
- 4: "SIGILL",
- 5: "SIGTRAP",
- 6: "SIGABRT",
- 7: "SIGBUS",
- 8: "SIGFPE",
- 9: "SIGKILL",
- 10: "SIGUSR1",
- 11: "SIGSEGV",
- 12: "SIGUSR2",
- 13: "SIGPIPE",
- 14: "SIGALRM",
- 15: "SIGTERM",
- 16: "SIGSTKFLT",
- 17: "SIGCHLD",
- 18: "SIGCONT",
- 19: "SIGSTOP",
- 20: "SIGTSTP",
- 21: "SIGTTIN",
- 22: "SIGTTOU",
- 23: "SIGURG",
- 24: "SIGXCPU",
- 25: "SIGXFSZ",
- 26: "SIGVTALRM",
- 27: "SIGPROF",
- 28: "SIGWINCH",
- 29: "SIGIO",
- 30: "SIGPWR",
- 31: "SIGSYS",
- SIGHUP: 1,
- SIGINT: 2,
- SIGQUIT: 3,
- SIGILL: 4,
- SIGTRAP: 5,
- SIGABRT: 6,
- SIGBUS: 7,
- SIGFPE: 8,
- SIGKILL: 9,
- SIGUSR1: 10,
- SIGSEGV: 11,
- SIGUSR2: 12,
- SIGPIPE: 13,
- SIGALRM: 14,
- SIGTERM: 15,
- SIGSTKFLT: 16,
- SIGCHLD: 17,
- SIGCONT: 18,
- SIGSTOP: 19,
- SIGTSTP: 20,
- SIGTTIN: 21,
- SIGTTOU: 22,
- SIGURG: 23,
- SIGXCPU: 24,
- SIGXFSZ: 25,
- SIGVTALRM: 26,
- SIGPROF: 27,
- SIGWINCH: 28,
- SIGIO: 29,
- SIGPWR: 30,
- SIGSYS: 31,
- };
-
- // From `kill -l`
- const MacOSSignal = {
- 1: "SIGHUP",
- 2: "SIGINT",
- 3: "SIGQUIT",
- 4: "SIGILL",
- 5: "SIGTRAP",
- 6: "SIGABRT",
- 7: "SIGEMT",
- 8: "SIGFPE",
- 9: "SIGKILL",
- 10: "SIGBUS",
- 11: "SIGSEGV",
- 12: "SIGSYS",
- 13: "SIGPIPE",
- 14: "SIGALRM",
- 15: "SIGTERM",
- 16: "SIGURG",
- 17: "SIGSTOP",
- 18: "SIGTSTP",
- 19: "SIGCONT",
- 20: "SIGCHLD",
- 21: "SIGTTIN",
- 22: "SIGTTOU",
- 23: "SIGIO",
- 24: "SIGXCPU",
- 25: "SIGXFSZ",
- 26: "SIGVTALRM",
- 27: "SIGPROF",
- 28: "SIGWINCH",
- 29: "SIGINFO",
- 30: "SIGUSR1",
- 31: "SIGUSR2",
- SIGHUP: 1,
- SIGINT: 2,
- SIGQUIT: 3,
- SIGILL: 4,
- SIGTRAP: 5,
- SIGABRT: 6,
- SIGEMT: 7,
- SIGFPE: 8,
- SIGKILL: 9,
- SIGBUS: 10,
- SIGSEGV: 11,
- SIGSYS: 12,
- SIGPIPE: 13,
- SIGALRM: 14,
- SIGTERM: 15,
- SIGURG: 16,
- SIGSTOP: 17,
- SIGTSTP: 18,
- SIGCONT: 19,
- SIGCHLD: 20,
- SIGTTIN: 21,
- SIGTTOU: 22,
- SIGIO: 23,
- SIGXCPU: 24,
- SIGXFSZ: 25,
- SIGVTALRM: 26,
- SIGPROF: 27,
- SIGWINCH: 28,
- SIGINFO: 29,
- SIGUSR1: 30,
- SIGUSR2: 31,
- };
-
- const Signal = {};
-
- function setSignals() {
- if (build.os === "darwin") {
- Object.assign(Signal, MacOSSignal);
- } else {
- Object.assign(Signal, LinuxSignal);
- }
- }
-
- function signal(signo) {
- if (build.os === "windows") {
- throw new Error("not implemented!");
- }
- return new SignalStream(signo);
- }
-
- const signals = {
- alarm() {
- return signal(Signal.SIGALRM);
- },
- child() {
- return signal(Signal.SIGCHLD);
- },
- hungup() {
- return signal(Signal.SIGHUP);
- },
- interrupt() {
- return signal(Signal.SIGINT);
- },
- io() {
- return signal(Signal.SIGIO);
- },
- pipe() {
- return signal(Signal.SIGPIPE);
- },
- quit() {
- return signal(Signal.SIGQUIT);
- },
- terminate() {
- return signal(Signal.SIGTERM);
- },
- userDefined1() {
- return signal(Signal.SIGUSR1);
- },
- userDefined2() {
- return signal(Signal.SIGUSR2);
- },
- windowChange() {
- return signal(Signal.SIGWINCH);
- },
- };
-
- class SignalStream {
- #disposed = false;
- #pollingPromise = Promise.resolve(false);
- #rid = 0;
-
- constructor(signo) {
- this.#rid = bindSignal(signo).rid;
- this.#loop();
- }
-
- #pollSignal = async () => {
- const res = await pollSignal(this.#rid);
- return res.done;
- };
-
- #loop = async () => {
- do {
- this.#pollingPromise = this.#pollSignal();
- } while (!(await this.#pollingPromise) && !this.#disposed);
- };
-
- then(
- f,
- g,
- ) {
- return this.#pollingPromise.then(() => {}).then(f, g);
- }
-
- async next() {
- return { done: await this.#pollingPromise, value: undefined };
- }
-
- [Symbol.asyncIterator]() {
- return this;
- }
-
- dispose() {
- if (this.#disposed) {
- throw new Error("The stream has already been disposed.");
- }
- this.#disposed = true;
- unbindSignal(this.#rid);
- }
- }
-
- window.__bootstrap.signals = {
- signal,
- signals,
- Signal,
- SignalStream,
- setSignals,
- };
-})(this);
diff --git a/cli/rt/40_testing.js b/cli/rt/40_testing.js
deleted file mode 100644
index 082d17fe0..000000000
--- a/cli/rt/40_testing.js
+++ /dev/null
@@ -1,350 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const colors = window.__bootstrap.colors;
- const { exit } = window.__bootstrap.os;
- const { Console, inspectArgs } = window.__bootstrap.console;
- const { stdout } = window.__bootstrap.files;
- const { exposeForTest } = window.__bootstrap.internals;
- const { metrics } = window.__bootstrap.metrics;
- const { assert } = window.__bootstrap.util;
-
- const disabledConsole = new Console(() => {});
-
- function delay(ms) {
- return new Promise((resolve) => {
- setTimeout(resolve, ms);
- });
- }
-
- function formatDuration(time = 0) {
- const gray = colors.maybeColor(colors.gray);
- const italic = colors.maybeColor(colors.italic);
- const timeStr = `(${time}ms)`;
- return gray(italic(timeStr));
- }
-
- // Wrap test function in additional assertion that makes sure
- // the test case does not leak async "ops" - ie. number of async
- // completed ops after the test is the same as number of dispatched
- // ops. Note that "unref" ops are ignored since in nature that are
- // optional.
- function assertOps(fn) {
- return async function asyncOpSanitizer() {
- const pre = metrics();
- await fn();
- // Defer until next event loop turn - that way timeouts and intervals
- // cleared can actually be removed from resource table, otherwise
- // false positives may occur (https://github.com/denoland/deno/issues/4591)
- await delay(0);
- const post = metrics();
- // We're checking diff because one might spawn HTTP server in the background
- // that will be a pending async op before test starts.
- const dispatchedDiff = post.opsDispatchedAsync - pre.opsDispatchedAsync;
- const completedDiff = post.opsCompletedAsync - pre.opsCompletedAsync;
- assert(
- dispatchedDiff === completedDiff,
- `Test case is leaking async ops.
-Before:
- - dispatched: ${pre.opsDispatchedAsync}
- - completed: ${pre.opsCompletedAsync}
-After:
- - dispatched: ${post.opsDispatchedAsync}
- - completed: ${post.opsCompletedAsync}
-
-Make sure to await all promises returned from Deno APIs before
-finishing test case.`,
- );
- };
- }
-
- // Wrap test function in additional assertion that makes sure
- // the test case does not "leak" resources - ie. resource table after
- // the test has exactly the same contents as before the test.
- function assertResources(
- fn,
- ) {
- return async function resourceSanitizer() {
- const pre = core.resources();
- await fn();
- const post = core.resources();
-
- const preStr = JSON.stringify(pre, null, 2);
- const postStr = JSON.stringify(post, null, 2);
- const msg = `Test case is leaking resources.
-Before: ${preStr}
-After: ${postStr}
-
-Make sure to close all open resource handles returned from Deno APIs before
-finishing test case.`;
- assert(preStr === postStr, msg);
- };
- }
-
- const TEST_REGISTRY = [];
-
- // Main test function provided by Deno, as you can see it merely
- // creates a new object with "name" and "fn" fields.
- function test(
- t,
- fn,
- ) {
- let testDef;
- const defaults = {
- ignore: false,
- only: false,
- sanitizeOps: true,
- sanitizeResources: true,
- };
-
- if (typeof t === "string") {
- if (!fn || typeof fn != "function") {
- throw new TypeError("Missing test function");
- }
- if (!t) {
- throw new TypeError("The test name can't be empty");
- }
- testDef = { fn: fn, name: t, ...defaults };
- } else {
- if (!t.fn) {
- throw new TypeError("Missing test function");
- }
- if (!t.name) {
- throw new TypeError("The test name can't be empty");
- }
- testDef = { ...defaults, ...t };
- }
-
- if (testDef.sanitizeOps) {
- testDef.fn = assertOps(testDef.fn);
- }
-
- if (testDef.sanitizeResources) {
- testDef.fn = assertResources(testDef.fn);
- }
-
- TEST_REGISTRY.push(testDef);
- }
-
- const encoder = new TextEncoder();
-
- function log(msg, noNewLine = false) {
- if (!noNewLine) {
- msg += "\n";
- }
-
- // Using `stdout` here because it doesn't force new lines
- // compared to `console.log`; `core.print` on the other hand
- // is line-buffered and doesn't output message without newline
- stdout.writeSync(encoder.encode(msg));
- }
-
- function reportToConsole(message) {
- const green = colors.maybeColor(colors.green);
- const red = colors.maybeColor(colors.red);
- const yellow = colors.maybeColor(colors.yellow);
- const redFailed = red("FAILED");
- const greenOk = green("ok");
- const yellowIgnored = yellow("ignored");
- if (message.start != null) {
- log(`running ${message.start.tests.length} tests`);
- } else if (message.testStart != null) {
- const { name } = message.testStart;
-
- log(`test ${name} ... `, true);
- return;
- } else if (message.testEnd != null) {
- switch (message.testEnd.status) {
- case "passed":
- log(`${greenOk} ${formatDuration(message.testEnd.duration)}`);
- break;
- case "failed":
- log(`${redFailed} ${formatDuration(message.testEnd.duration)}`);
- break;
- case "ignored":
- log(`${yellowIgnored} ${formatDuration(message.testEnd.duration)}`);
- break;
- }
- } else if (message.end != null) {
- const failures = message.end.results.filter((m) => m.error != null);
- if (failures.length > 0) {
- log(`\nfailures:\n`);
-
- for (const { name, error } of failures) {
- log(name);
- log(inspectArgs([error]));
- log("");
- }
-
- log(`failures:\n`);
-
- for (const { name } of failures) {
- log(`\t${name}`);
- }
- }
- log(
- `\ntest result: ${message.end.failed ? redFailed : greenOk}. ` +
- `${message.end.passed} passed; ${message.end.failed} failed; ` +
- `${message.end.ignored} ignored; ${message.end.measured} measured; ` +
- `${message.end.filtered} filtered out ` +
- `${formatDuration(message.end.duration)}\n`,
- );
-
- if (message.end.usedOnly && message.end.failed == 0) {
- log(`${redFailed} because the "only" option was used\n`);
- }
- }
- }
-
- exposeForTest("reportToConsole", reportToConsole);
-
- // TODO: already implements AsyncGenerator<RunTestsMessage>, but add as "implements to class"
- // TODO: implements PromiseLike<RunTestsEndResult>
- class TestRunner {
- #usedOnly = false;
-
- constructor(
- tests,
- filterFn,
- failFast,
- ) {
- this.stats = {
- filtered: 0,
- ignored: 0,
- measured: 0,
- passed: 0,
- failed: 0,
- };
- this.filterFn = filterFn;
- this.failFast = failFast;
- const onlyTests = tests.filter(({ only }) => only);
- this.#usedOnly = onlyTests.length > 0;
- const unfilteredTests = this.#usedOnly ? onlyTests : tests;
- this.testsToRun = unfilteredTests.filter(filterFn);
- this.stats.filtered = unfilteredTests.length - this.testsToRun.length;
- }
-
- async *[Symbol.asyncIterator]() {
- yield { start: { tests: this.testsToRun } };
-
- const results = [];
- const suiteStart = +new Date();
- for (const test of this.testsToRun) {
- const endMessage = {
- name: test.name,
- duration: 0,
- };
- yield { testStart: { ...test } };
- if (test.ignore) {
- endMessage.status = "ignored";
- this.stats.ignored++;
- } else {
- const start = +new Date();
- try {
- await test.fn();
- endMessage.status = "passed";
- this.stats.passed++;
- } catch (err) {
- endMessage.status = "failed";
- endMessage.error = err;
- this.stats.failed++;
- }
- endMessage.duration = +new Date() - start;
- }
- results.push(endMessage);
- yield { testEnd: endMessage };
- if (this.failFast && endMessage.error != null) {
- break;
- }
- }
-
- const duration = +new Date() - suiteStart;
-
- yield {
- end: { ...this.stats, usedOnly: this.#usedOnly, duration, results },
- };
- }
- }
-
- function createFilterFn(
- filter,
- skip,
- ) {
- return (def) => {
- let passes = true;
-
- if (filter) {
- if (filter instanceof RegExp) {
- passes = passes && filter.test(def.name);
- } else if (filter.startsWith("/") && filter.endsWith("/")) {
- const filterAsRegex = new RegExp(filter.slice(1, filter.length - 1));
- passes = passes && filterAsRegex.test(def.name);
- } else {
- passes = passes && def.name.includes(filter);
- }
- }
-
- if (skip) {
- if (skip instanceof RegExp) {
- passes = passes && !skip.test(def.name);
- } else {
- passes = passes && !def.name.includes(skip);
- }
- }
-
- return passes;
- };
- }
-
- exposeForTest("createFilterFn", createFilterFn);
-
- async function runTests({
- exitOnFail = true,
- failFast = false,
- filter = undefined,
- skip = undefined,
- disableLog = false,
- reportToConsole: reportToConsole_ = true,
- onMessage = undefined,
- } = {}) {
- const filterFn = createFilterFn(filter, skip);
- const testRunner = new TestRunner(TEST_REGISTRY, filterFn, failFast);
-
- const originalConsole = globalThis.console;
-
- if (disableLog) {
- globalThis.console = disabledConsole;
- }
-
- let endMsg;
-
- for await (const message of testRunner) {
- if (onMessage != null) {
- await onMessage(message);
- }
- if (reportToConsole_) {
- reportToConsole(message);
- }
- if (message.end != null) {
- endMsg = message.end;
- }
- }
-
- if (disableLog) {
- globalThis.console = originalConsole;
- }
-
- if ((endMsg.failed > 0 || endMsg?.usedOnly) && exitOnFail) {
- exit(1);
- }
-
- return endMsg;
- }
-
- exposeForTest("runTests", runTests);
-
- window.__bootstrap.testing = {
- test,
- };
-})(this);
diff --git a/cli/rt/40_tls.js b/cli/rt/40_tls.js
deleted file mode 100644
index d66e0bd01..000000000
--- a/cli/rt/40_tls.js
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { Listener, Conn } = window.__bootstrap.net;
-
- function opConnectTls(
- args,
- ) {
- return core.jsonOpAsync("op_connect_tls", args);
- }
-
- function opAcceptTLS(rid) {
- return core.jsonOpAsync("op_accept_tls", { rid });
- }
-
- function opListenTls(args) {
- return core.jsonOpSync("op_listen_tls", args);
- }
-
- function opStartTls(args) {
- return core.jsonOpAsync("op_start_tls", args);
- }
-
- async function connectTls({
- port,
- hostname = "127.0.0.1",
- transport = "tcp",
- certFile = undefined,
- }) {
- const res = await opConnectTls({
- port,
- hostname,
- transport,
- certFile,
- });
- return new Conn(res.rid, res.remoteAddr, res.localAddr);
- }
-
- class TLSListener extends Listener {
- async accept() {
- const res = await opAcceptTLS(this.rid);
- return new Conn(res.rid, res.remoteAddr, res.localAddr);
- }
- }
-
- function listenTls({
- port,
- certFile,
- keyFile,
- hostname = "0.0.0.0",
- transport = "tcp",
- }) {
- const res = opListenTls({
- port,
- certFile,
- keyFile,
- hostname,
- transport,
- });
- return new TLSListener(res.rid, res.localAddr);
- }
-
- async function startTls(
- conn,
- { hostname = "127.0.0.1", certFile } = {},
- ) {
- const res = await opStartTls({
- rid: conn.rid,
- hostname,
- certFile,
- });
- return new Conn(res.rid, res.remoteAddr, res.localAddr);
- }
-
- window.__bootstrap.tls = {
- startTls,
- listenTls,
- connectTls,
- TLSListener,
- };
-})(this);
diff --git a/cli/rt/40_tty.js b/cli/rt/40_tty.js
deleted file mode 100644
index 598d33237..000000000
--- a/cli/rt/40_tty.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
-
- function consoleSize(rid) {
- return core.jsonOpSync("op_console_size", { rid });
- }
-
- function isatty(rid) {
- return core.jsonOpSync("op_isatty", { rid });
- }
-
- const DEFAULT_SET_RAW_OPTIONS = {
- cbreak: false,
- };
-
- function setRaw(rid, mode, options = {}) {
- const rOptions = { ...DEFAULT_SET_RAW_OPTIONS, ...options };
- core.jsonOpSync("op_set_raw", { rid, mode, options: rOptions });
- }
-
- window.__bootstrap.tty = {
- consoleSize,
- isatty,
- setRaw,
- };
-})(this);
diff --git a/cli/rt/40_write_file.js b/cli/rt/40_write_file.js
deleted file mode 100644
index 7a9cb1f40..000000000
--- a/cli/rt/40_write_file.js
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-((window) => {
- const { stat, statSync, chmod, chmodSync } = window.__bootstrap.fs;
- const { open, openSync } = window.__bootstrap.files;
- const { writeAll, writeAllSync } = window.__bootstrap.buffer;
- const { build } = window.__bootstrap.build;
-
- function writeFileSync(
- path,
- data,
- options = {},
- ) {
- if (options.create !== undefined) {
- const create = !!options.create;
- if (!create) {
- // verify that file exists
- statSync(path);
- }
- }
-
- const openOptions = options.append
- ? { write: true, create: true, append: true }
- : { write: true, create: true, truncate: true };
- const file = openSync(path, openOptions);
-
- if (
- options.mode !== undefined &&
- options.mode !== null &&
- build.os !== "windows"
- ) {
- chmodSync(path, options.mode);
- }
-
- writeAllSync(file, data);
- file.close();
- }
-
- async function writeFile(
- path,
- data,
- options = {},
- ) {
- if (options.create !== undefined) {
- const create = !!options.create;
- if (!create) {
- // verify that file exists
- await stat(path);
- }
- }
-
- const openOptions = options.append
- ? { write: true, create: true, append: true }
- : { write: true, create: true, truncate: true };
- const file = await open(path, openOptions);
-
- if (
- options.mode !== undefined &&
- options.mode !== null &&
- build.os !== "windows"
- ) {
- await chmod(path, options.mode);
- }
-
- await writeAll(file, data);
- file.close();
- }
-
- function writeTextFileSync(
- path,
- data,
- options = {},
- ) {
- const encoder = new TextEncoder();
- return writeFileSync(path, encoder.encode(data), options);
- }
-
- function writeTextFile(
- path,
- data,
- options = {},
- ) {
- const encoder = new TextEncoder();
- return writeFile(path, encoder.encode(data), options);
- }
-
- window.__bootstrap.writeFile = {
- writeTextFile,
- writeTextFileSync,
- writeFile,
- writeFileSync,
- };
-})(this);
diff --git a/cli/rt/41_prompt.js b/cli/rt/41_prompt.js
deleted file mode 100644
index ec294668b..000000000
--- a/cli/rt/41_prompt.js
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-((window) => {
- const { stdin } = window.__bootstrap.files;
- const { isatty } = window.__bootstrap.tty;
- const LF = "\n".charCodeAt(0);
- const CR = "\r".charCodeAt(0);
- const decoder = new TextDecoder();
- const core = window.Deno.core;
-
- function alert(message = "Alert") {
- if (!isatty(stdin.rid)) {
- return;
- }
-
- core.print(`${message} [Enter] `, false);
-
- readLineFromStdinSync();
- }
-
- function confirm(message = "Confirm") {
- if (!isatty(stdin.rid)) {
- return false;
- }
-
- core.print(`${message} [y/N] `, false);
-
- const answer = readLineFromStdinSync();
-
- return answer === "Y" || answer === "y";
- }
-
- function prompt(message = "Prompt", defaultValue) {
- defaultValue ??= null;
-
- if (!isatty(stdin.rid)) {
- return null;
- }
-
- core.print(`${message} `, false);
-
- if (defaultValue) {
- core.print(`[${defaultValue}] `, false);
- }
-
- return readLineFromStdinSync() || defaultValue;
- }
-
- function readLineFromStdinSync() {
- const c = new Uint8Array(1);
- const buf = [];
-
- while (true) {
- const n = stdin.readSync(c);
- if (n === null || n === 0) {
- break;
- }
- if (c[0] === CR) {
- const n = stdin.readSync(c);
- if (c[0] === LF) {
- break;
- }
- buf.push(CR);
- if (n === null || n === 0) {
- break;
- }
- }
- if (c[0] === LF) {
- break;
- }
- buf.push(c[0]);
- }
- return decoder.decode(new Uint8Array(buf));
- }
-
- window.__bootstrap.prompt = {
- alert,
- confirm,
- prompt,
- };
-})(this);
diff --git a/cli/rt/90_deno_ns.js b/cli/rt/90_deno_ns.js
deleted file mode 100644
index 9188788ec..000000000
--- a/cli/rt/90_deno_ns.js
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const __bootstrap = window.__bootstrap;
- __bootstrap.denoNs = {
- test: __bootstrap.testing.test,
- metrics: __bootstrap.metrics.metrics,
- Process: __bootstrap.process.Process,
- run: __bootstrap.process.run,
- isatty: __bootstrap.tty.isatty,
- writeFileSync: __bootstrap.writeFile.writeFileSync,
- writeFile: __bootstrap.writeFile.writeFile,
- writeTextFileSync: __bootstrap.writeFile.writeTextFileSync,
- writeTextFile: __bootstrap.writeFile.writeTextFile,
- readTextFile: __bootstrap.readFile.readTextFile,
- readTextFileSync: __bootstrap.readFile.readTextFileSync,
- readFile: __bootstrap.readFile.readFile,
- readFileSync: __bootstrap.readFile.readFileSync,
- watchFs: __bootstrap.fsEvents.watchFs,
- chmodSync: __bootstrap.fs.chmodSync,
- chmod: __bootstrap.fs.chmod,
- chown: __bootstrap.fs.chown,
- chownSync: __bootstrap.fs.chownSync,
- copyFileSync: __bootstrap.fs.copyFileSync,
- cwd: __bootstrap.fs.cwd,
- makeTempDirSync: __bootstrap.fs.makeTempDirSync,
- makeTempDir: __bootstrap.fs.makeTempDir,
- makeTempFileSync: __bootstrap.fs.makeTempFileSync,
- makeTempFile: __bootstrap.fs.makeTempFile,
- mkdirSync: __bootstrap.fs.mkdirSync,
- mkdir: __bootstrap.fs.mkdir,
- chdir: __bootstrap.fs.chdir,
- copyFile: __bootstrap.fs.copyFile,
- readDirSync: __bootstrap.fs.readDirSync,
- readDir: __bootstrap.fs.readDir,
- readLinkSync: __bootstrap.fs.readLinkSync,
- readLink: __bootstrap.fs.readLink,
- realPathSync: __bootstrap.fs.realPathSync,
- realPath: __bootstrap.fs.realPath,
- removeSync: __bootstrap.fs.removeSync,
- remove: __bootstrap.fs.remove,
- renameSync: __bootstrap.fs.renameSync,
- rename: __bootstrap.fs.rename,
- version: __bootstrap.version.version,
- build: __bootstrap.build.build,
- statSync: __bootstrap.fs.statSync,
- lstatSync: __bootstrap.fs.lstatSync,
- stat: __bootstrap.fs.stat,
- lstat: __bootstrap.fs.lstat,
- truncateSync: __bootstrap.fs.truncateSync,
- truncate: __bootstrap.fs.truncate,
- errors: __bootstrap.errors.errors,
- customInspect: __bootstrap.console.customInspect,
- inspect: __bootstrap.console.inspect,
- env: __bootstrap.os.env,
- exit: __bootstrap.os.exit,
- execPath: __bootstrap.os.execPath,
- Buffer: __bootstrap.buffer.Buffer,
- readAll: __bootstrap.buffer.readAll,
- readAllSync: __bootstrap.buffer.readAllSync,
- writeAll: __bootstrap.buffer.writeAll,
- writeAllSync: __bootstrap.buffer.writeAllSync,
- copy: __bootstrap.io.copy,
- iter: __bootstrap.io.iter,
- iterSync: __bootstrap.io.iterSync,
- SeekMode: __bootstrap.io.SeekMode,
- read: __bootstrap.io.read,
- readSync: __bootstrap.io.readSync,
- write: __bootstrap.io.write,
- writeSync: __bootstrap.io.writeSync,
- File: __bootstrap.files.File,
- open: __bootstrap.files.open,
- openSync: __bootstrap.files.openSync,
- create: __bootstrap.files.create,
- createSync: __bootstrap.files.createSync,
- stdin: __bootstrap.files.stdin,
- stdout: __bootstrap.files.stdout,
- stderr: __bootstrap.files.stderr,
- seek: __bootstrap.files.seek,
- seekSync: __bootstrap.files.seekSync,
- connect: __bootstrap.net.connect,
- listen: __bootstrap.net.listen,
- connectTls: __bootstrap.tls.connectTls,
- listenTls: __bootstrap.tls.listenTls,
- sleepSync: __bootstrap.timers.sleepSync,
- fsyncSync: __bootstrap.fs.fsyncSync,
- fsync: __bootstrap.fs.fsync,
- fdatasyncSync: __bootstrap.fs.fdatasyncSync,
- fdatasync: __bootstrap.fs.fdatasync,
- };
-
- __bootstrap.denoNsUnstable = {
- signal: __bootstrap.signals.signal,
- signals: __bootstrap.signals.signals,
- Signal: __bootstrap.signals.Signal,
- SignalStream: __bootstrap.signals.SignalStream,
- transpileOnly: __bootstrap.compilerApi.transpileOnly,
- compile: __bootstrap.compilerApi.compile,
- bundle: __bootstrap.compilerApi.bundle,
- permissions: __bootstrap.permissions.permissions,
- Permissions: __bootstrap.permissions.Permissions,
- PermissionStatus: __bootstrap.permissions.PermissionStatus,
- openPlugin: __bootstrap.plugins.openPlugin,
- kill: __bootstrap.process.kill,
- setRaw: __bootstrap.tty.setRaw,
- consoleSize: __bootstrap.tty.consoleSize,
- DiagnosticCategory: __bootstrap.diagnostics.DiagnosticCategory,
- loadavg: __bootstrap.os.loadavg,
- hostname: __bootstrap.os.hostname,
- osRelease: __bootstrap.os.osRelease,
- systemMemoryInfo: __bootstrap.os.systemMemoryInfo,
- systemCpuInfo: __bootstrap.os.systemCpuInfo,
- applySourceMap: __bootstrap.errorStack.opApplySourceMap,
- formatDiagnostics: __bootstrap.errorStack.opFormatDiagnostics,
- shutdown: __bootstrap.net.shutdown,
- ShutdownMode: __bootstrap.net.ShutdownMode,
- listen: __bootstrap.netUnstable.listen,
- connect: __bootstrap.netUnstable.connect,
- listenDatagram: __bootstrap.netUnstable.listenDatagram,
- startTls: __bootstrap.tls.startTls,
- fstatSync: __bootstrap.fs.fstatSync,
- fstat: __bootstrap.fs.fstat,
- ftruncateSync: __bootstrap.fs.ftruncateSync,
- ftruncate: __bootstrap.fs.ftruncate,
- umask: __bootstrap.fs.umask,
- link: __bootstrap.fs.link,
- linkSync: __bootstrap.fs.linkSync,
- futime: __bootstrap.fs.futime,
- futimeSync: __bootstrap.fs.futimeSync,
- utime: __bootstrap.fs.utime,
- utimeSync: __bootstrap.fs.utimeSync,
- symlink: __bootstrap.fs.symlink,
- symlinkSync: __bootstrap.fs.symlinkSync,
- HttpClient: __bootstrap.fetch.HttpClient,
- createHttpClient: __bootstrap.fetch.createHttpClient,
- };
-})(this);
diff --git a/cli/rt/99_main.js b/cli/rt/99_main.js
deleted file mode 100644
index f38d51936..000000000
--- a/cli/rt/99_main.js
+++ /dev/null
@@ -1,395 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-// Removes the `__proto__` for security reasons. This intentionally makes
-// Deno non compliant with ECMA-262 Annex B.2.2.1
-//
-delete Object.prototype.__proto__;
-
-((window) => {
- const core = Deno.core;
- const util = window.__bootstrap.util;
- const eventTarget = window.__bootstrap.eventTarget;
- const globalInterfaces = window.__bootstrap.globalInterfaces;
- const dispatchMinimal = window.__bootstrap.dispatchMinimal;
- const build = window.__bootstrap.build;
- const version = window.__bootstrap.version;
- const errorStack = window.__bootstrap.errorStack;
- const os = window.__bootstrap.os;
- const timers = window.__bootstrap.timers;
- const Console = window.__bootstrap.console.Console;
- const worker = window.__bootstrap.worker;
- const signals = window.__bootstrap.signals;
- const { internalSymbol, internalObject } = window.__bootstrap.internals;
- const performance = window.__bootstrap.performance;
- const crypto = window.__bootstrap.crypto;
- const url = window.__bootstrap.url;
- const headers = window.__bootstrap.headers;
- const streams = window.__bootstrap.streams;
- const fileReader = window.__bootstrap.fileReader;
- const webSocket = window.__bootstrap.webSocket;
- const fetch = window.__bootstrap.fetch;
- const prompt = window.__bootstrap.prompt;
- const denoNs = window.__bootstrap.denoNs;
- const denoNsUnstable = window.__bootstrap.denoNsUnstable;
- const errors = window.__bootstrap.errors.errors;
- const { defineEventHandler } = window.__bootstrap.webUtil;
-
- let windowIsClosing = false;
-
- function windowClose() {
- if (!windowIsClosing) {
- windowIsClosing = true;
- // Push a macrotask to exit after a promise resolve.
- // This is not perfect, but should be fine for first pass.
- Promise.resolve().then(() =>
- timers.setTimeout.call(
- null,
- () => {
- // This should be fine, since only Window/MainWorker has .close()
- os.exit(0);
- },
- 0,
- )
- );
- }
- }
-
- const encoder = new TextEncoder();
-
- function workerClose() {
- if (isClosing) {
- return;
- }
-
- isClosing = true;
- opCloseWorker();
- }
-
- // TODO(bartlomieju): remove these functions
- // Stuff for workers
- const onmessage = () => {};
- const onerror = () => {};
-
- function postMessage(data) {
- const dataJson = JSON.stringify(data);
- const dataIntArray = encoder.encode(dataJson);
- opPostMessage(dataIntArray);
- }
-
- let isClosing = false;
- async function workerMessageRecvCallback(data) {
- const msgEvent = new MessageEvent("message", {
- cancelable: false,
- data,
- });
-
- try {
- if (globalThis["onmessage"]) {
- const result = globalThis.onmessage(msgEvent);
- if (result && "then" in result) {
- await result;
- }
- }
- globalThis.dispatchEvent(msgEvent);
- } catch (e) {
- let handled = false;
-
- const errorEvent = new ErrorEvent("error", {
- cancelable: true,
- message: e.message,
- lineno: e.lineNumber ? e.lineNumber + 1 : undefined,
- colno: e.columnNumber ? e.columnNumber + 1 : undefined,
- filename: e.fileName,
- error: null,
- });
-
- if (globalThis["onerror"]) {
- const ret = globalThis.onerror(
- e.message,
- e.fileName,
- e.lineNumber,
- e.columnNumber,
- e,
- );
- handled = ret === true;
- }
-
- globalThis.dispatchEvent(errorEvent);
- if (errorEvent.defaultPrevented) {
- handled = true;
- }
-
- if (!handled) {
- throw e;
- }
- }
- }
-
- function opPostMessage(data) {
- core.jsonOpSync("op_worker_post_message", {}, data);
- }
-
- function opCloseWorker() {
- core.jsonOpSync("op_worker_close");
- }
-
- function opMainModule() {
- return core.jsonOpSync("op_main_module");
- }
-
- 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);
- 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 (runtimeOptions.applySourceMaps) {
- prepareStackTrace = core.createPrepareStackTrace(
- errorStack.opApplySourceMap,
- );
- } else {
- prepareStackTrace = core.createPrepareStackTrace();
- }
- Error.prepareStackTrace = prepareStackTrace;
- }
-
- function registerErrors() {
- core.registerErrorClass("NotFound", errors.NotFound);
- core.registerErrorClass("PermissionDenied", errors.PermissionDenied);
- core.registerErrorClass("ConnectionRefused", errors.ConnectionRefused);
- core.registerErrorClass("ConnectionReset", errors.ConnectionReset);
- core.registerErrorClass("ConnectionAborted", errors.ConnectionAborted);
- core.registerErrorClass("NotConnected", errors.NotConnected);
- core.registerErrorClass("AddrInUse", errors.AddrInUse);
- core.registerErrorClass("AddrNotAvailable", errors.AddrNotAvailable);
- core.registerErrorClass("BrokenPipe", errors.BrokenPipe);
- core.registerErrorClass("AlreadyExists", errors.AlreadyExists);
- core.registerErrorClass("InvalidData", errors.InvalidData);
- core.registerErrorClass("TimedOut", errors.TimedOut);
- core.registerErrorClass("Interrupted", errors.Interrupted);
- core.registerErrorClass("WriteZero", errors.WriteZero);
- core.registerErrorClass("UnexpectedEof", errors.UnexpectedEof);
- core.registerErrorClass("BadResource", errors.BadResource);
- core.registerErrorClass("Http", errors.Http);
- core.registerErrorClass("Busy", errors.Busy);
- core.registerErrorClass("NotSupported", errors.NotSupported);
- core.registerErrorClass("Error", Error);
- core.registerErrorClass("RangeError", RangeError);
- core.registerErrorClass("ReferenceError", ReferenceError);
- core.registerErrorClass("SyntaxError", SyntaxError);
- core.registerErrorClass("TypeError", TypeError);
- core.registerErrorClass("URIError", URIError);
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
- const windowOrWorkerGlobalScope = {
- Blob: util.nonEnumerable(fetch.Blob),
- ByteLengthQueuingStrategy: util.nonEnumerable(
- streams.ByteLengthQueuingStrategy,
- ),
- CloseEvent: util.nonEnumerable(CloseEvent),
- CountQueuingStrategy: util.nonEnumerable(
- streams.CountQueuingStrategy,
- ),
- CustomEvent: util.nonEnumerable(CustomEvent),
- DOMException: util.nonEnumerable(DOMException),
- ErrorEvent: util.nonEnumerable(ErrorEvent),
- Event: util.nonEnumerable(Event),
- EventTarget: util.nonEnumerable(EventTarget),
- File: util.nonEnumerable(fetch.DomFile),
- FileReader: util.nonEnumerable(fileReader.FileReader),
- FormData: util.nonEnumerable(fetch.FormData),
- Headers: util.nonEnumerable(headers.Headers),
- MessageEvent: util.nonEnumerable(MessageEvent),
- Performance: util.nonEnumerable(performance.Performance),
- PerformanceEntry: util.nonEnumerable(performance.PerformanceEntry),
- PerformanceMark: util.nonEnumerable(performance.PerformanceMark),
- PerformanceMeasure: util.nonEnumerable(performance.PerformanceMeasure),
- ProgressEvent: util.nonEnumerable(ProgressEvent),
- ReadableStream: util.nonEnumerable(streams.ReadableStream),
- Request: util.nonEnumerable(fetch.Request),
- Response: util.nonEnumerable(fetch.Response),
- TextDecoder: util.nonEnumerable(TextDecoder),
- TextEncoder: util.nonEnumerable(TextEncoder),
- TransformStream: util.nonEnumerable(streams.TransformStream),
- URL: util.nonEnumerable(url.URL),
- URLSearchParams: util.nonEnumerable(url.URLSearchParams),
- WebSocket: util.nonEnumerable(webSocket.WebSocket),
- Worker: util.nonEnumerable(worker.Worker),
- WritableStream: util.nonEnumerable(streams.WritableStream),
- atob: util.writable(atob),
- btoa: util.writable(btoa),
- clearInterval: util.writable(timers.clearInterval),
- clearTimeout: util.writable(timers.clearTimeout),
- console: util.writable(new Console(core.print)),
- crypto: util.readOnly(crypto),
- fetch: util.writable(fetch.fetch),
- performance: util.writable(performance.performance),
- setInterval: util.writable(timers.setInterval),
- setTimeout: util.writable(timers.setTimeout),
- };
-
- const mainRuntimeGlobalProperties = {
- Window: globalInterfaces.windowConstructorDescriptor,
- window: util.readOnly(globalThis),
- self: util.readOnly(globalThis),
- // TODO(bartlomieju): from MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope)
- // it seems those two properties should be available to workers as well
- onload: util.writable(null),
- onunload: util.writable(null),
- close: util.writable(windowClose),
- closed: util.getterOnly(() => windowIsClosing),
- alert: util.writable(prompt.alert),
- confirm: util.writable(prompt.confirm),
- prompt: util.writable(prompt.prompt),
- };
-
- const workerRuntimeGlobalProperties = {
- WorkerGlobalScope: globalInterfaces.workerGlobalScopeConstructorDescriptor,
- DedicatedWorkerGlobalScope:
- globalInterfaces.dedicatedWorkerGlobalScopeConstructorDescriptor,
- self: util.readOnly(globalThis),
- onmessage: util.writable(onmessage),
- onerror: util.writable(onerror),
- // TODO: should be readonly?
- close: util.nonEnumerable(workerClose),
- postMessage: util.writable(postMessage),
- workerMessageRecvCallback: util.nonEnumerable(workerMessageRecvCallback),
- };
-
- let hasBootstrapped = false;
-
- function bootstrapMainRuntime(runtimeOptions) {
- if (hasBootstrapped) {
- throw new Error("Worker runtime already bootstrapped");
- }
- // Remove bootstrapping data from the global scope
- delete globalThis.__bootstrap;
- delete globalThis.bootstrap;
- util.log("bootstrapMainRuntime");
- hasBootstrapped = true;
- Object.defineProperties(globalThis, windowOrWorkerGlobalScope);
- Object.defineProperties(globalThis, mainRuntimeGlobalProperties);
- Object.setPrototypeOf(globalThis, Window.prototype);
- eventTarget.setEventTargetData(globalThis);
-
- defineEventHandler(window, "load", null);
- defineEventHandler(window, "unload", null);
-
- runtimeStart(runtimeOptions);
- const { args, noColor, pid, ppid, unstableFlag } = runtimeOptions;
-
- registerErrors();
-
- const finalDenoNs = {
- core,
- internal: internalSymbol,
- [internalSymbol]: internalObject,
- resources: core.resources,
- close: core.close,
- ...denoNs,
- };
- Object.defineProperties(finalDenoNs, {
- pid: util.readOnly(pid),
- ppid: util.readOnly(ppid),
- noColor: util.readOnly(noColor),
- args: util.readOnly(Object.freeze(args)),
- mainModule: util.getterOnly(opMainModule),
- });
-
- if (unstableFlag) {
- Object.assign(finalDenoNs, denoNsUnstable);
- }
-
- // Setup `Deno` global - we're actually overriding already
- // existing global `Deno` with `Deno` namespace from "./deno.ts".
- util.immutableDefine(globalThis, "Deno", finalDenoNs);
- Object.freeze(globalThis.Deno);
- Object.freeze(globalThis.Deno.core);
- Object.freeze(globalThis.Deno.core.sharedQueue);
- signals.setSignals();
-
- util.log("args", args);
- }
-
- function bootstrapWorkerRuntime(
- runtimeOptions,
- name,
- useDenoNamespace,
- internalName,
- ) {
- if (hasBootstrapped) {
- throw new Error("Worker runtime already bootstrapped");
- }
- // Remove bootstrapping data from the global scope
- delete globalThis.__bootstrap;
- delete globalThis.bootstrap;
- util.log("bootstrapWorkerRuntime");
- hasBootstrapped = true;
- Object.defineProperties(globalThis, windowOrWorkerGlobalScope);
- Object.defineProperties(globalThis, workerRuntimeGlobalProperties);
- Object.defineProperties(globalThis, { name: util.readOnly(name) });
- Object.setPrototypeOf(globalThis, DedicatedWorkerGlobalScope.prototype);
- eventTarget.setEventTargetData(globalThis);
-
- runtimeStart(
- runtimeOptions,
- internalName ?? name,
- );
- const { unstableFlag, pid, noColor, args } = runtimeOptions;
-
- registerErrors();
-
- const finalDenoNs = {
- core,
- internal: internalSymbol,
- [internalSymbol]: internalObject,
- resources: core.resources,
- close: core.close,
- ...denoNs,
- };
- if (useDenoNamespace) {
- if (unstableFlag) {
- Object.assign(finalDenoNs, denoNsUnstable);
- }
- Object.defineProperties(finalDenoNs, {
- pid: util.readOnly(pid),
- noColor: util.readOnly(noColor),
- args: util.readOnly(Object.freeze(args)),
- });
- // Setup `Deno` global - we're actually overriding already
- // existing global `Deno` with `Deno` namespace from "./deno.ts".
- util.immutableDefine(globalThis, "Deno", finalDenoNs);
- Object.freeze(globalThis.Deno);
- Object.freeze(globalThis.Deno.core);
- Object.freeze(globalThis.Deno.core.sharedQueue);
- signals.setSignals();
- } else {
- delete globalThis.Deno;
- util.assert(globalThis.Deno === undefined);
- }
- }
-
- Object.defineProperties(globalThis, {
- bootstrap: {
- value: {
- mainRuntime: bootstrapMainRuntime,
- workerRuntime: bootstrapWorkerRuntime,
- },
- configurable: true,
- },
- });
-})(this);
diff --git a/cli/rt/README.md b/cli/rt/README.md
deleted file mode 100644
index b17fa22e5..000000000
--- a/cli/rt/README.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# Runtime JavaScript Code
-
-This directory contains Deno runtime code written in plain JavaScript.
-
-Each file is a plain, old **script**, not ES modules. The reason is that
-snapshotting ES modules is much harder, especially if one needs to manipulate
-global scope (like in case of Deno).
-
-Each file is prefixed with a number, telling in which order scripts should be
-loaded into V8 isolate. This is temporary solution and we're striving not to
-require specific order (though it's not 100% obvious if that's feasible).
-
-## Deno Web APIs
-
-This directory facilities Web APIs that are available in Deno.
-
-Please note, that some implementations might not be completely aligned with
-specification.
-
-Some Web APIs are using ops under the hood, eg. `console`, `performance`.
-
-## Implemented Web APIs
-
-- [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob): for
- representing opaque binary data.
-- [Console](https://developer.mozilla.org/en-US/docs/Web/API/Console): for
- logging purposes.
-- [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent),
- [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
- and
- [EventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventListener):
- to work with DOM events.
- - **Implementation notes:** There is no DOM hierarchy in Deno, so there is no
- tree for Events to bubble/capture through.
-- [fetch](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch),
- [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request),
- [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response),
- [Body](https://developer.mozilla.org/en-US/docs/Web/API/Body) and
- [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers): modern
- Promise-based HTTP Request API.
-- [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData): access
- to a `multipart/form-data` serialization.
-- [Performance](https://developer.mozilla.org/en-US/docs/Web/API/Performance):
- retrieving current time with a high precision.
-- [setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout),
- [setInterval](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval),
- [clearTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout):
- scheduling callbacks in future and
- [clearInterval](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval).
-- [Stream](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) for
- creating, composing, and consuming streams of data.
-- [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) and
- [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams):
- to construct and parse URLSs.
-- [Worker](https://developer.mozilla.org/en-US/docs/Web/API/Worker): executing
- additional code in a separate thread.
- - **Implementation notes:** Blob URLs are not supported, object ownership
- cannot be transferred, posted data is serialized to JSON instead of
- [structured cloning](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).
diff --git a/cli/signal.rs b/cli/signal.rs
deleted file mode 100644
index b597714f4..000000000
--- a/cli/signal.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::error::AnyError;
-
-#[cfg(not(unix))]
-use deno_core::error::last_os_error;
-#[cfg(not(unix))]
-use deno_core::error::type_error;
-
-#[cfg(not(unix))]
-const SIGINT: i32 = 2;
-#[cfg(not(unix))]
-const SIGKILL: i32 = 9;
-#[cfg(not(unix))]
-const SIGTERM: i32 = 15;
-
-#[cfg(not(unix))]
-use winapi::{
- shared::minwindef::DWORD,
- um::{
- handleapi::CloseHandle,
- processthreadsapi::{OpenProcess, TerminateProcess},
- winnt::PROCESS_TERMINATE,
- },
-};
-
-#[cfg(unix)]
-pub fn kill(pid: i32, signo: i32) -> Result<(), AnyError> {
- use nix::sys::signal::{kill as unix_kill, Signal};
- use nix::unistd::Pid;
- use std::convert::TryFrom;
- let sig = Signal::try_from(signo)?;
- unix_kill(Pid::from_raw(pid), Option::Some(sig)).map_err(AnyError::from)
-}
-
-#[cfg(not(unix))]
-pub fn kill(pid: i32, signal: i32) -> Result<(), AnyError> {
- match signal {
- SIGINT | SIGKILL | SIGTERM => {
- if pid <= 0 {
- return Err(type_error("unsupported pid"));
- }
- unsafe {
- let handle = OpenProcess(PROCESS_TERMINATE, 0, pid as DWORD);
- if handle.is_null() {
- return Err(last_os_error());
- }
- if TerminateProcess(handle, 1) == 0 {
- CloseHandle(handle);
- return Err(last_os_error());
- }
- if CloseHandle(handle) == 0 {
- return Err(last_os_error());
- }
- }
- }
- _ => {
- return Err(type_error("unsupported signal"));
- }
- }
- Ok(())
-}
diff --git a/cli/specifier_handler.rs b/cli/specifier_handler.rs
index 083316740..02a1196d3 100644
--- a/cli/specifier_handler.rs
+++ b/cli/specifier_handler.rs
@@ -5,8 +5,8 @@ use crate::deno_dir::DenoDir;
use crate::disk_cache::DiskCache;
use crate::file_fetcher::FileFetcher;
use crate::media_type::MediaType;
-use crate::permissions::Permissions;
use crate::program_state::ProgramState;
+use deno_runtime::permissions::Permissions;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
diff --git a/cli/standalone.rs b/cli/standalone.rs
index 6559242bd..fea42fc96 100644
--- a/cli/standalone.rs
+++ b/cli/standalone.rs
@@ -1,10 +1,7 @@
use crate::colors;
use crate::flags::Flags;
-use crate::permissions::Permissions;
use crate::tokio_util;
use crate::version;
-use crate::worker::MainWorker;
-use crate::worker::WorkerOptions;
use deno_core::error::bail;
use deno_core::error::type_error;
use deno_core::error::AnyError;
@@ -12,6 +9,9 @@ use deno_core::futures::FutureExt;
use deno_core::ModuleLoader;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
+use deno_runtime::permissions::Permissions;
+use deno_runtime::worker::MainWorker;
+use deno_runtime::worker::WorkerOptions;
use std::cell::RefCell;
use std::convert::TryInto;
use std::env::current_exe;
@@ -135,6 +135,7 @@ async fn run(source_code: String, args: Vec<String>) -> Result<(), AnyError> {
runtime_version: version::deno(),
ts_version: version::TYPESCRIPT.to_string(),
no_color: !colors::use_color(),
+ get_error_class_fn: Some(&crate::errors::get_error_class_name),
};
let mut worker =
MainWorker::from_options(main_module.clone(), permissions, &options);
diff --git a/cli/tools/coverage.rs b/cli/tools/coverage.rs
index 726ce9749..229cb8020 100644
--- a/cli/tools/coverage.rs
+++ b/cli/tools/coverage.rs
@@ -1,11 +1,11 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::colors;
-use crate::inspector::InspectorSession;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::url::Url;
+use deno_runtime::inspector::InspectorSession;
use serde::Deserialize;
pub struct CoverageCollector {
diff --git a/cli/tools/repl.rs b/cli/tools/repl.rs
index 9b4d94a23..61d7809c3 100644
--- a/cli/tools/repl.rs
+++ b/cli/tools/repl.rs
@@ -3,13 +3,13 @@
use crate::ast;
use crate::ast::TokenOrComment;
use crate::colors;
-use crate::inspector::InspectorSession;
use crate::media_type::MediaType;
use crate::program_state::ProgramState;
-use crate::worker::MainWorker;
use deno_core::error::AnyError;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
+use deno_runtime::inspector::InspectorSession;
+use deno_runtime::worker::MainWorker;
use rustyline::completion::Completer;
use rustyline::error::ReadlineError;
use rustyline::highlight::Highlighter;
diff --git a/cli/tools/upgrade.rs b/cli/tools/upgrade.rs
index b76850dde..da26b3159 100644
--- a/cli/tools/upgrade.rs
+++ b/cli/tools/upgrade.rs
@@ -3,8 +3,8 @@
//! This module provides feature to upgrade deno executable
use crate::AnyError;
-use deno_fetch::reqwest;
-use deno_fetch::reqwest::Client;
+use deno_runtime::deno_fetch::reqwest;
+use deno_runtime::deno_fetch::reqwest::Client;
use semver_parser::version::parse as semver_parse;
use std::fs;
use std::path::Path;
diff --git a/cli/web_worker.rs b/cli/web_worker.rs
deleted file mode 100644
index 18d391580..000000000
--- a/cli/web_worker.rs
+++ /dev/null
@@ -1,588 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::colors;
-use crate::inspector::DenoInspector;
-use crate::inspector::InspectorServer;
-use crate::js;
-use crate::metrics::Metrics;
-use crate::ops;
-use crate::permissions::Permissions;
-use crate::tokio_util::create_basic_runtime;
-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;
-use std::task::Context;
-use std::task::Poll;
-use tokio::sync::Mutex as AsyncMutex;
-
-/// Events that are sent to host from child
-/// worker.
-pub enum WorkerEvent {
- Message(Box<[u8]>),
- Error(AnyError),
- TerminalError(AnyError),
-}
-
-pub struct WorkerChannelsInternal {
- pub sender: mpsc::Sender<WorkerEvent>,
- pub receiver: mpsc::Receiver<Box<[u8]>>,
-}
-
-/// Wrapper for `WorkerHandle` that adds functionality
-/// for terminating workers.
-///
-/// This struct is used by host as well as worker itself.
-///
-/// Host uses it to communicate with worker and terminate it,
-/// while worker uses it only to finish execution on `self.close()`.
-#[derive(Clone)]
-pub struct WebWorkerHandle {
- pub sender: mpsc::Sender<Box<[u8]>>,
- pub receiver: Arc<AsyncMutex<mpsc::Receiver<WorkerEvent>>>,
- terminate_tx: mpsc::Sender<()>,
- terminated: Arc<AtomicBool>,
- isolate_handle: v8::IsolateHandle,
-}
-
-impl WebWorkerHandle {
- /// Post message to worker as a host.
- pub fn post_message(&self, buf: Box<[u8]>) -> Result<(), AnyError> {
- let mut sender = self.sender.clone();
- sender.try_send(buf)?;
- Ok(())
- }
-
- /// Get the event with lock.
- /// Return error if more than one listener tries to get event
- pub async fn get_event(&self) -> Result<Option<WorkerEvent>, AnyError> {
- let mut receiver = self.receiver.try_lock()?;
- Ok(receiver.next().await)
- }
-
- pub fn terminate(&self) {
- // This function can be called multiple times by whomever holds
- // the handle. However only a single "termination" should occur so
- // we need a guard here.
- let already_terminated = self.terminated.swap(true, Ordering::SeqCst);
-
- if !already_terminated {
- self.isolate_handle.terminate_execution();
- let mut sender = self.terminate_tx.clone();
- // This call should be infallible hence the `expect`.
- // This might change in the future.
- sender.try_send(()).expect("Failed to terminate");
- }
- }
-}
-
-fn create_channels(
- isolate_handle: v8::IsolateHandle,
- terminate_tx: mpsc::Sender<()>,
-) -> (WorkerChannelsInternal, WebWorkerHandle) {
- let (in_tx, in_rx) = mpsc::channel::<Box<[u8]>>(1);
- let (out_tx, out_rx) = mpsc::channel::<WorkerEvent>(1);
- let internal_channels = WorkerChannelsInternal {
- sender: out_tx,
- receiver: in_rx,
- };
- let external_channels = WebWorkerHandle {
- sender: in_tx,
- receiver: Arc::new(AsyncMutex::new(out_rx)),
- terminated: Arc::new(AtomicBool::new(false)),
- terminate_tx,
- isolate_handle,
- };
- (internal_channels, external_channels)
-}
-
-/// This struct is an implementation of `Worker` Web API
-///
-/// 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.
- pub(crate) internal_channels: WorkerChannelsInternal,
- pub(crate) js_runtime: JsRuntime,
- pub(crate) name: String,
- waker: AtomicWaker,
- event_loop_idle: bool,
- terminate_rx: mpsc::Receiver<()>,
- handle: WebWorkerHandle,
- pub use_deno_namespace: bool,
-}
-
-pub struct WebWorkerOptions {
- /// Sets `Deno.args` in JS runtime.
- pub args: Vec<String>,
- pub debug_flag: bool,
- pub unstable: bool,
- pub ca_filepath: Option<String>,
- pub user_agent: 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,
- /// Sets `Deno.version.deno` in JS runtime.
- pub runtime_version: String,
- /// Sets `Deno.version.typescript` in JS runtime.
- pub ts_version: String,
- /// Sets `Deno.noColor` in JS runtime.
- pub no_color: bool,
-}
-
-impl WebWorker {
- pub fn from_options(
- name: String,
- permissions: Permissions,
- main_module: ModuleSpecifier,
- worker_id: u32,
- options: &WebWorkerOptions,
- ) -> Self {
- let mut js_runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(options.module_loader.clone()),
- startup_snapshot: Some(js::deno_isolate_init()),
- 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 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();
- let (internal_channels, handle) =
- create_channels(isolate_handle, terminate_tx);
-
- let mut worker = Self {
- id: worker_id,
- inspector,
- internal_channels,
- js_runtime,
- name,
- waker: AtomicWaker::new(),
- event_loop_idle: false,
- terminate_rx,
- handle,
- use_deno_namespace: options.use_deno_namespace,
- };
-
- {
- let handle = worker.thread_safe_handle();
- let sender = worker.internal_channels.sender.clone();
- let js_runtime = &mut worker.js_runtime;
- // All ops registered in this function depend on these
- {
- let op_state = js_runtime.op_state();
- let mut op_state = op_state.borrow_mut();
- op_state.put::<Metrics>(Default::default());
- 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);
- ops::fetch::init(js_runtime, options.ca_filepath.as_deref());
- ops::timers::init(js_runtime);
- 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(
- js_runtime,
- "op_domain_to_ascii",
- deno_web::op_domain_to_ascii,
- );
- ops::io::init(js_runtime);
- ops::websocket::init(
- js_runtime,
- options.ca_filepath.as_deref(),
- options.user_agent.clone(),
- );
-
- if options.use_deno_namespace {
- ops::fs_events::init(js_runtime);
- ops::fs::init(js_runtime);
- ops::net::init(js_runtime);
- ops::os::init(js_runtime);
- ops::permissions::init(js_runtime);
- ops::plugin::init(js_runtime);
- ops::process::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);
-
- let op_state = js_runtime.op_state();
- let mut op_state = op_state.borrow_mut();
- let (stdin, stdout, stderr) = ops::io::get_stdio();
- if let Some(stream) = stdin {
- op_state.resource_table.add("stdin", Box::new(stream));
- }
- if let Some(stream) = stdout {
- op_state.resource_table.add("stdout", Box::new(stream));
- }
- if let Some(stream) = stderr {
- 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": options.runtime_version,
- "noColor": options.no_color,
- "pid": std::process::id(),
- "ppid": ops::runtime::ppid(),
- "target": env!("TARGET"),
- "tsVersion": options.ts_version,
- "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-{}\")",
- runtime_options_str, self.name, options.use_deno_namespace, self.id
- );
- self
- .execute(&script)
- .expect("Failed to execute worker bootstrap script");
- }
-
- /// Same as execute2() but the filename defaults to "$CWD/__anonymous__".
- pub fn execute(&mut self, js_source: &str) -> Result<(), AnyError> {
- let path = env::current_dir().unwrap().join("__anonymous__");
- let url = Url::from_file_path(path).unwrap();
- self.js_runtime.execute(url.as_str(), js_source)
- }
-
- /// Loads, instantiates and executes specified JavaScript module.
- pub async fn execute_module(
- &mut self,
- module_specifier: &ModuleSpecifier,
- ) -> Result<(), AnyError> {
- let id = self.js_runtime.load_module(module_specifier, None).await?;
- self.js_runtime.mod_evaluate(id).await
- }
-
- /// Returns a way to communicate with the Worker from other threads.
- pub fn thread_safe_handle(&self) -> WebWorkerHandle {
- self.handle.clone()
- }
-
- pub fn has_been_terminated(&self) -> bool {
- self.handle.terminated.load(Ordering::SeqCst)
- }
-
- pub fn poll_event_loop(
- &mut self,
- cx: &mut Context,
- ) -> Poll<Result<(), AnyError>> {
- if self.has_been_terminated() {
- return Poll::Ready(Ok(()));
- }
-
- if !self.event_loop_idle {
- let poll_result = {
- // We always poll the inspector if it exists.
- let _ = self.inspector.as_mut().map(|i| i.poll_unpin(cx));
- self.waker.register(cx.waker());
- self.js_runtime.poll_event_loop(cx)
- };
-
- if let Poll::Ready(r) = poll_result {
- if self.has_been_terminated() {
- return Poll::Ready(Ok(()));
- }
-
- if let Err(e) = r {
- print_worker_error(e.to_string(), &self.name);
- let mut sender = self.internal_channels.sender.clone();
- sender
- .try_send(WorkerEvent::Error(e))
- .expect("Failed to post message to host");
- }
- self.event_loop_idle = true;
- }
- }
-
- if let Poll::Ready(r) = self.terminate_rx.poll_next_unpin(cx) {
- // terminate_rx should never be closed
- assert!(r.is_some());
- return Poll::Ready(Ok(()));
- }
-
- let maybe_msg_poll_result =
- self.internal_channels.receiver.poll_next_unpin(cx);
-
- if let Poll::Ready(maybe_msg) = maybe_msg_poll_result {
- let msg =
- maybe_msg.expect("Received `None` instead of message in worker");
- let msg = String::from_utf8(msg.to_vec()).unwrap();
- let script = format!("workerMessageRecvCallback({})", msg);
-
- if let Err(e) = self.execute(&script) {
- // If execution was terminated during message callback then
- // just ignore it
- if self.has_been_terminated() {
- return Poll::Ready(Ok(()));
- }
-
- // Otherwise forward error to host
- let mut sender = self.internal_channels.sender.clone();
- sender
- .try_send(WorkerEvent::Error(e))
- .expect("Failed to post message to host");
- }
-
- // Let event loop be polled again
- self.event_loop_idle = false;
- self.waker.wake();
- }
-
- Poll::Pending
- }
-
- pub async fn run_event_loop(&mut self) -> Result<(), AnyError> {
- poll_fn(|cx| self.poll_event_loop(cx)).await
- }
-}
-
-impl Drop for WebWorker {
- fn drop(&mut self) {
- // The Isolate object must outlive the Inspector object, but this is
- // currently not enforced by the type system.
- self.inspector.take();
- }
-}
-
-fn print_worker_error(error_str: String, name: &str) {
- eprintln!(
- "{}: Uncaught (in worker \"{}\") {}",
- colors::red_bold("error"),
- name,
- error_str.trim_start_matches("Uncaught "),
- );
-}
-
-/// This function should be called from a thread dedicated to this worker.
-// TODO(bartlomieju): check if order of actions is aligned to Worker spec
-pub fn run_web_worker(
- mut worker: WebWorker,
- specifier: ModuleSpecifier,
- maybe_source_code: Option<String>,
-) -> Result<(), AnyError> {
- let name = worker.name.to_string();
-
- let mut rt = create_basic_runtime();
-
- // TODO(bartlomieju): run following block using "select!"
- // with terminate
-
- // Execute provided source code immediately
- let result = if let Some(source_code) = maybe_source_code {
- worker.execute(&source_code)
- } else {
- // TODO(bartlomieju): add "type": "classic", ie. ability to load
- // script instead of module
- let load_future = worker.execute_module(&specifier).boxed_local();
-
- rt.block_on(load_future)
- };
-
- let mut sender = worker.internal_channels.sender.clone();
-
- // If sender is closed it means that worker has already been closed from
- // within using "globalThis.close()"
- if sender.is_closed() {
- return Ok(());
- }
-
- if let Err(e) = result {
- print_worker_error(e.to_string(), &name);
- sender
- .try_send(WorkerEvent::TerminalError(e))
- .expect("Failed to post message to host");
-
- // Failure to execute script is a terminal error, bye, bye.
- return Ok(());
- }
-
- let result = rt.block_on(worker.run_event_loop());
- debug!("Worker thread shuts down {}", &name);
- result
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- 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 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,
- user_agent: "x".to_string(),
- seed: None,
- module_loader,
- create_web_worker_cb,
- js_error_create_fn: None,
- use_deno_namespace: false,
- attach_inspector: false,
- maybe_inspector_server: None,
- runtime_version: "x".to_string(),
- ts_version: "x".to_string(),
- no_color: true,
- };
-
- let mut worker = WebWorker::from_options(
- "TEST".to_string(),
- Permissions::allow_all(),
- main_module,
- 1,
- &options,
- );
- worker.bootstrap(&options);
- worker
- }
-
- #[tokio::test]
- async fn test_worker_messages() {
- let (handle_sender, handle_receiver) =
- std::sync::mpsc::sync_channel::<WebWorkerHandle>(1);
-
- let join_handle = std::thread::spawn(move || {
- let mut worker = create_test_web_worker();
- let source = r#"
- onmessage = function(e) {
- console.log("msg from main script", e.data);
- if (e.data == "exit") {
- return close();
- } else {
- console.assert(e.data === "hi");
- }
- postMessage([1, 2, 3]);
- console.log("after postMessage");
- }
- "#;
- worker.execute(source).unwrap();
- let handle = worker.thread_safe_handle();
- handle_sender.send(handle).unwrap();
- let r = tokio_util::run_basic(worker.run_event_loop());
- assert!(r.is_ok())
- });
-
- let mut handle = handle_receiver.recv().unwrap();
-
- let msg = json!("hi").to_string().into_boxed_str().into_boxed_bytes();
- let r = handle.post_message(msg.clone());
- assert!(r.is_ok());
-
- let maybe_msg = handle.get_event().await.unwrap();
- assert!(maybe_msg.is_some());
-
- let r = handle.post_message(msg.clone());
- assert!(r.is_ok());
-
- let maybe_msg = handle.get_event().await.unwrap();
- assert!(maybe_msg.is_some());
- match maybe_msg {
- Some(WorkerEvent::Message(buf)) => {
- assert_eq!(*buf, *b"[1,2,3]");
- }
- _ => unreachable!(),
- }
-
- let msg = json!("exit")
- .to_string()
- .into_boxed_str()
- .into_boxed_bytes();
- let r = handle.post_message(msg);
- assert!(r.is_ok());
- let event = handle.get_event().await.unwrap();
- assert!(event.is_none());
- handle.sender.close_channel();
- join_handle.join().expect("Failed to join worker thread");
- }
-
- #[tokio::test]
- async fn removed_from_resource_table_on_close() {
- let (handle_sender, handle_receiver) =
- std::sync::mpsc::sync_channel::<WebWorkerHandle>(1);
-
- let join_handle = std::thread::spawn(move || {
- let mut worker = create_test_web_worker();
- worker.execute("onmessage = () => { close(); }").unwrap();
- let handle = worker.thread_safe_handle();
- handle_sender.send(handle).unwrap();
- let r = tokio_util::run_basic(worker.run_event_loop());
- assert!(r.is_ok())
- });
-
- let mut handle = handle_receiver.recv().unwrap();
-
- let msg = json!("hi").to_string().into_boxed_str().into_boxed_bytes();
- let r = handle.post_message(msg.clone());
- assert!(r.is_ok());
- let event = handle.get_event().await.unwrap();
- assert!(event.is_none());
- handle.sender.close_channel();
-
- join_handle.join().expect("Failed to join worker thread");
- }
-}
diff --git a/cli/worker.rs b/cli/worker.rs
deleted file mode 100644
index d1238df41..000000000
--- a/cli/worker.rs
+++ /dev/null
@@ -1,342 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::inspector::DenoInspector;
-use crate::inspector::InspectorServer;
-use crate::inspector::InspectorSession;
-use crate::js;
-use crate::metrics::Metrics;
-use crate::ops;
-use crate::permissions::Permissions;
-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;
-use deno_core::ModuleId;
-use deno_core::ModuleLoader;
-use deno_core::ModuleSpecifier;
-use deno_core::RuntimeOptions;
-use std::env;
-use std::rc::Rc;
-use std::sync::Arc;
-use std::task::Context;
-use std::task::Poll;
-
-/// This worker is created and used by almost all
-/// subcommands in Deno executable.
-///
-/// It provides ops available in the `Deno` namespace.
-///
-/// All `WebWorker`s created during program execution
-/// are descendants of this worker.
-pub struct MainWorker {
- inspector: Option<Box<DenoInspector>>,
- pub js_runtime: JsRuntime,
- should_break_on_first_statement: bool,
-}
-
-pub struct WorkerOptions {
- pub apply_source_maps: bool,
- /// Sets `Deno.args` in JS runtime.
- pub args: Vec<String>,
- pub debug_flag: bool,
- pub unstable: bool,
- pub ca_filepath: Option<String>,
- pub user_agent: 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,
- /// Sets `Deno.version.deno` in JS runtime.
- pub runtime_version: String,
- /// Sets `Deno.version.typescript` in JS runtime.
- pub ts_version: String,
- /// Sets `Deno.noColor` in JS runtime.
- pub no_color: bool,
-}
-
-impl MainWorker {
- pub fn from_options(
- main_module: ModuleSpecifier,
- permissions: Permissions,
- options: &WorkerOptions,
- ) -> Self {
- let mut js_runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(options.module_loader.clone()),
- startup_snapshot: Some(js::deno_isolate_init()),
- 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 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() && options.should_break_on_first_statement;
-
- let mut worker = Self {
- inspector,
- js_runtime,
- should_break_on_first_statement,
- };
-
- let js_runtime = &mut worker.js_runtime;
- {
- // All ops registered in this function depend on these
- {
- let op_state = js_runtime.op_state();
- let mut op_state = op_state.borrow_mut();
- op_state.put::<Metrics>(Default::default());
- op_state.put::<Permissions>(permissions);
- op_state.put::<ops::UnstableChecker>(ops::UnstableChecker {
- unstable: options.unstable,
- });
- }
-
- 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,
- 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(
- js_runtime,
- "op_domain_to_ascii",
- deno_web::op_domain_to_ascii,
- );
- ops::fs_events::init(js_runtime);
- ops::fs::init(js_runtime);
- ops::io::init(js_runtime);
- ops::net::init(js_runtime);
- ops::os::init(js_runtime);
- ops::permissions::init(js_runtime);
- ops::plugin::init(js_runtime);
- ops::process::init(js_runtime);
- ops::signal::init(js_runtime);
- ops::tls::init(js_runtime);
- ops::tty::init(js_runtime);
- ops::websocket::init(
- js_runtime,
- options.ca_filepath.as_deref(),
- options.user_agent.clone(),
- );
- }
- {
- let op_state = js_runtime.op_state();
- let mut op_state = op_state.borrow_mut();
- let t = &mut op_state.resource_table;
- let (stdin, stdout, stderr) = ops::io::get_stdio();
- if let Some(stream) = stdin {
- t.add("stdin", Box::new(stream));
- }
- if let Some(stream) = stdout {
- t.add("stdout", Box::new(stream));
- }
- if let Some(stream) = stderr {
- t.add("stderr", Box::new(stream));
- }
- }
-
- worker
- }
-
- pub fn bootstrap(&mut self, options: &WorkerOptions) {
- let runtime_options = json!({
- "args": options.args,
- "applySourceMaps": options.apply_source_maps,
- "debugFlag": options.debug_flag,
- "denoVersion": options.runtime_version,
- "noColor": options.no_color,
- "pid": std::process::id(),
- "ppid": ops::runtime::ppid(),
- "target": env!("TARGET"),
- "tsVersion": options.ts_version,
- "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");
- }
-
- /// Same as execute2() but the filename defaults to "$CWD/__anonymous__".
- pub fn execute(&mut self, js_source: &str) -> Result<(), AnyError> {
- let path = env::current_dir().unwrap().join("__anonymous__");
- let url = Url::from_file_path(path).unwrap();
- self.js_runtime.execute(url.as_str(), js_source)
- }
-
- /// Loads and instantiates specified JavaScript module.
- pub async fn preload_module(
- &mut self,
- module_specifier: &ModuleSpecifier,
- ) -> Result<ModuleId, AnyError> {
- self.js_runtime.load_module(module_specifier, None).await
- }
-
- /// Loads, instantiates and executes specified JavaScript module.
- pub async fn execute_module(
- &mut self,
- module_specifier: &ModuleSpecifier,
- ) -> Result<(), AnyError> {
- let id = self.preload_module(module_specifier).await?;
- self.wait_for_inspector_session();
- self.js_runtime.mod_evaluate(id).await
- }
-
- fn wait_for_inspector_session(&mut self) {
- if self.should_break_on_first_statement {
- self
- .inspector
- .as_mut()
- .unwrap()
- .wait_for_session_and_break_on_next_statement()
- }
- }
-
- /// Create new inspector session. This function panics if Worker
- /// was not configured to create inspector.
- pub fn create_inspector_session(&mut self) -> Box<InspectorSession> {
- let inspector = self.inspector.as_mut().unwrap();
-
- InspectorSession::new(&mut **inspector)
- }
-
- pub fn poll_event_loop(
- &mut self,
- cx: &mut Context,
- ) -> Poll<Result<(), AnyError>> {
- // We always poll the inspector if it exists.
- let _ = self.inspector.as_mut().map(|i| i.poll_unpin(cx));
- self.js_runtime.poll_event_loop(cx)
- }
-
- pub async fn run_event_loop(&mut self) -> Result<(), AnyError> {
- poll_fn(|cx| self.poll_event_loop(cx)).await
- }
-}
-
-impl Drop for MainWorker {
- fn drop(&mut self) {
- // The Isolate object must outlive the Inspector object, but this is
- // currently not enforced by the type system.
- self.inspector.take();
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- fn create_test_worker() -> MainWorker {
- let main_module =
- ModuleSpecifier::resolve_url_or_path("./hello.js").unwrap();
- let permissions = Permissions::default();
-
- let options = WorkerOptions {
- apply_source_maps: false,
- user_agent: "x".to_string(),
- 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),
- runtime_version: "x".to_string(),
- ts_version: "x".to_string(),
- no_color: true,
- };
-
- MainWorker::from_options(main_module, permissions, &options)
- }
-
- #[tokio::test]
- async fn execute_mod_esm_imports_a() {
- let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
- .parent()
- .unwrap()
- .join("cli/tests/esm_imports_a.js");
- 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_mod_circular() {
- let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
- .parent()
- .unwrap()
- .join("tests/circular1.js");
- 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_mod_resolve_error() {
- // "foo" is not a valid module specifier so this should return an error.
- let mut worker = create_test_worker();
- let module_specifier =
- ModuleSpecifier::resolve_url_or_path("does-not-exist").unwrap();
- let result = worker.execute_module(&module_specifier).await;
- assert!(result.is_err());
- }
-
- #[tokio::test]
- async fn execute_mod_002_hello() {
- // This assumes cwd is project root (an assumption made throughout the
- // tests).
- let mut worker = create_test_worker();
- let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
- .parent()
- .unwrap()
- .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;
- assert!(result.is_ok());
- }
-}