"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "runtime/web_worker.rs" between
deno-1.10.3.tar.gz and deno-1.11.0.tar.gz

About: Deno is is a simple, modern and secure runtime for JavaScript and TypeScript that uses the V8 JavaScript engine and is built in Rust.

web_worker.rs  (deno-1.10.3):web_worker.rs  (deno-1.11.0)
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use crate::colors; use crate::colors;
use crate::inspector::DenoInspector; use crate::inspector_server::InspectorServer;
use crate::inspector::InspectorServer;
use crate::js; use crate::js;
use crate::metrics; use crate::metrics;
use crate::ops; use crate::ops;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::tokio_util::create_basic_runtime; use crate::tokio_util::create_basic_runtime;
use deno_broadcast_channel::InMemoryBroadcastChannel;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::error::Context as ErrorContext; use deno_core::error::Context as ErrorContext;
use deno_core::futures::channel::mpsc; use deno_core::futures::channel::mpsc;
use deno_core::futures::future::poll_fn; use deno_core::futures::future::poll_fn;
use deno_core::futures::future::FutureExt; use deno_core::futures::future::FutureExt;
use deno_core::futures::stream::StreamExt; use deno_core::futures::stream::StreamExt;
use deno_core::serde::Deserialize; use deno_core::serde::Deserialize;
use deno_core::serde::Serialize; use deno_core::serde::Serialize;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::serde_json::json; use deno_core::serde_json::json;
skipping to change at line 201 skipping to change at line 201
}; };
(internal_handle, external_handle) (internal_handle, external_handle)
} }
/// This struct is an implementation of `Worker` Web API /// This struct is an implementation of `Worker` Web API
/// ///
/// Each `WebWorker` is either a child of `MainWorker` or other /// Each `WebWorker` is either a child of `MainWorker` or other
/// `WebWorker`. /// `WebWorker`.
pub struct WebWorker { pub struct WebWorker {
id: WorkerId, id: WorkerId,
inspector: Option<Box<DenoInspector>>,
pub js_runtime: JsRuntime, pub js_runtime: JsRuntime,
pub name: String, pub name: String,
internal_handle: WebWorkerInternalHandle, internal_handle: WebWorkerInternalHandle,
external_handle: WebWorkerHandle, external_handle: WebWorkerHandle,
pub use_deno_namespace: bool, pub use_deno_namespace: bool,
pub main_module: ModuleSpecifier, pub main_module: ModuleSpecifier,
} }
pub struct WebWorkerOptions { pub struct WebWorkerOptions {
/// Sets `Deno.args` in JS runtime. /// Sets `Deno.args` in JS runtime.
skipping to change at line 233 skipping to change at line 232
pub maybe_inspector_server: Option<Arc<InspectorServer>>, pub maybe_inspector_server: Option<Arc<InspectorServer>>,
pub apply_source_maps: bool, pub apply_source_maps: bool,
/// Sets `Deno.version.deno` in JS runtime. /// Sets `Deno.version.deno` in JS runtime.
pub runtime_version: String, pub runtime_version: String,
/// Sets `Deno.version.typescript` in JS runtime. /// Sets `Deno.version.typescript` in JS runtime.
pub ts_version: String, pub ts_version: String,
/// Sets `Deno.noColor` in JS runtime. /// Sets `Deno.noColor` in JS runtime.
pub no_color: bool, pub no_color: bool,
pub get_error_class_fn: Option<GetErrorClassFn>, pub get_error_class_fn: Option<GetErrorClassFn>,
pub blob_url_store: BlobUrlStore, pub blob_url_store: BlobUrlStore,
pub broadcast_channel: InMemoryBroadcastChannel,
} }
impl WebWorker { impl WebWorker {
pub fn from_options( pub fn from_options(
name: String, name: String,
permissions: Permissions, permissions: Permissions,
main_module: ModuleSpecifier, main_module: ModuleSpecifier,
worker_id: WorkerId, worker_id: WorkerId,
options: &WebWorkerOptions, options: &WebWorkerOptions,
) -> Self { ) -> Self {
skipping to change at line 271 skipping to change at line 271
Some(main_module.clone()), Some(main_module.clone()),
), ),
deno_fetch::init::<Permissions>( deno_fetch::init::<Permissions>(
options.user_agent.clone(), options.user_agent.clone(),
options.ca_data.clone(), options.ca_data.clone(),
), ),
deno_websocket::init::<Permissions>( deno_websocket::init::<Permissions>(
options.user_agent.clone(), options.user_agent.clone(),
options.ca_data.clone(), options.ca_data.clone(),
), ),
deno_broadcast_channel::init(
options.broadcast_channel.clone(),
options.unstable,
),
deno_crypto::init(options.seed), deno_crypto::init(options.seed),
deno_webgpu::init(options.unstable), deno_webgpu::init(options.unstable),
deno_timers::init::<Permissions>(), deno_timers::init::<Permissions>(),
// Metrics // Metrics
metrics::init(), metrics::init(),
// Permissions ext (worker specific state) // Permissions ext (worker specific state)
perm_ext, perm_ext,
]; ];
// Runtime ops that are always initialized for WebWorkers // Runtime ops that are always initialized for WebWorkers
skipping to change at line 317 skipping to change at line 321
// Append exts // Append exts
extensions.extend(runtime_exts); extensions.extend(runtime_exts);
extensions.extend(deno_ns_exts); // May be empty extensions.extend(deno_ns_exts); // May be empty
let mut js_runtime = JsRuntime::new(RuntimeOptions { let mut js_runtime = JsRuntime::new(RuntimeOptions {
module_loader: Some(options.module_loader.clone()), module_loader: Some(options.module_loader.clone()),
startup_snapshot: Some(js::deno_isolate_init()), startup_snapshot: Some(js::deno_isolate_init()),
js_error_create_fn: options.js_error_create_fn.clone(), js_error_create_fn: options.js_error_create_fn.clone(),
get_error_class_fn: options.get_error_class_fn, get_error_class_fn: options.get_error_class_fn,
attach_inspector: options.attach_inspector,
extensions, extensions,
..Default::default() ..Default::default()
}); });
let inspector = if options.attach_inspector { if let Some(inspector) = js_runtime.inspector() {
Some(DenoInspector::new( if let Some(server) = options.maybe_inspector_server.clone() {
&mut js_runtime, let session_sender = inspector.get_session_sender();
options.maybe_inspector_server.clone(), let deregister_rx = inspector.add_deregister_handler();
)) server.register_inspector(session_sender, deregister_rx);
} else { }
None }
};
let (internal_handle, external_handle) = { let (internal_handle, external_handle) = {
let handle = js_runtime.v8_isolate().thread_safe_handle(); let handle = js_runtime.v8_isolate().thread_safe_handle();
let (internal_handle, external_handle) = create_handles(handle); let (internal_handle, external_handle) = create_handles(handle);
let op_state = js_runtime.op_state(); let op_state = js_runtime.op_state();
let mut op_state = op_state.borrow_mut(); let mut op_state = op_state.borrow_mut();
op_state.put(internal_handle.clone()); op_state.put(internal_handle.clone());
(internal_handle, external_handle) (internal_handle, external_handle)
}; };
Self { Self {
id: worker_id, id: worker_id,
inspector,
js_runtime, js_runtime,
name, name,
internal_handle, internal_handle,
external_handle, external_handle,
use_deno_namespace: options.use_deno_namespace, use_deno_namespace: options.use_deno_namespace,
main_module, main_module,
} }
} }
pub fn bootstrap(&mut self, options: &WebWorkerOptions) { pub fn bootstrap(&mut self, options: &WebWorkerOptions) {
skipping to change at line 416 skipping to change at line 419
tokio::select! { tokio::select! {
maybe_result = receiver.next() => { maybe_result = receiver.next() => {
debug!("received worker module evaluate {:#?}", maybe_result); debug!("received worker module evaluate {:#?}", maybe_result);
// If `None` is returned it means that runtime was destroyed before // If `None` is returned it means that runtime was destroyed before
// evaluation was complete. This can happen in Web Worker when `self.clo se()` // evaluation was complete. This can happen in Web Worker when `self.clo se()`
// is called at top level. // is called at top level.
let result = maybe_result.unwrap_or(Ok(())); let result = maybe_result.unwrap_or(Ok(()));
return result; return result;
} }
event_loop_result = self.run_event_loop() => { event_loop_result = self.run_event_loop(false) => {
if self.internal_handle.is_terminated() { if self.internal_handle.is_terminated() {
return Ok(()); return Ok(());
} }
event_loop_result?; event_loop_result?;
let maybe_result = receiver.next().await; let maybe_result = receiver.next().await;
let result = maybe_result.unwrap_or(Ok(())); let result = maybe_result.unwrap_or(Ok(()));
return result; return result;
} }
} }
} }
/// Returns a way to communicate with the Worker from other threads. /// Returns a way to communicate with the Worker from other threads.
pub fn thread_safe_handle(&self) -> WebWorkerHandle { pub fn thread_safe_handle(&self) -> WebWorkerHandle {
self.external_handle.clone() self.external_handle.clone()
} }
pub fn poll_event_loop( pub fn poll_event_loop(
&mut self, &mut self,
cx: &mut Context, cx: &mut Context,
wait_for_inspector: bool,
) -> Poll<Result<(), AnyError>> { ) -> Poll<Result<(), AnyError>> {
// If awakened because we are terminating, just return Ok // If awakened because we are terminating, just return Ok
if self.internal_handle.is_terminated() { if self.internal_handle.is_terminated() {
return Poll::Ready(Ok(())); return Poll::Ready(Ok(()));
} }
// We always poll the inspector if it exists. match self.js_runtime.poll_event_loop(cx, wait_for_inspector) {
let _ = self.inspector.as_mut().map(|i| i.poll_unpin(cx));
match self.js_runtime.poll_event_loop(cx) {
Poll::Ready(r) => { Poll::Ready(r) => {
// If js ended because we are terminating, just return Ok // If js ended because we are terminating, just return Ok
if self.internal_handle.is_terminated() { if self.internal_handle.is_terminated() {
return Poll::Ready(Ok(())); return Poll::Ready(Ok(()));
} }
// In case of an error, pass to parent without terminating worker // In case of an error, pass to parent without terminating worker
if let Err(e) = r { if let Err(e) = r {
print_worker_error(e.to_string(), &self.name); print_worker_error(e.to_string(), &self.name);
let handle = self.internal_handle.clone(); let handle = self.internal_handle.clone();
skipping to change at line 470 skipping to change at line 472
} }
panic!( panic!(
"coding error: either js is polling or the worker is terminated" "coding error: either js is polling or the worker is terminated"
); );
} }
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
} }
} }
pub async fn run_event_loop(&mut self) -> Result<(), AnyError> { pub async fn run_event_loop(
poll_fn(|cx| self.poll_event_loop(cx)).await &mut self,
} wait_for_inspector: bool,
} ) -> Result<(), AnyError> {
poll_fn(|cx| self.poll_event_loop(cx, wait_for_inspector)).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) { fn print_worker_error(error_str: String, name: &str) {
eprintln!( eprintln!(
"{}: Uncaught (in worker \"{}\") {}", "{}: Uncaught (in worker \"{}\") {}",
colors::red_bold("error"), colors::red_bold("error"),
name, name,
error_str.trim_start_matches("Uncaught "), error_str.trim_start_matches("Uncaught "),
); );
skipping to change at line 535 skipping to change at line 532
if let Err(e) = result { if let Err(e) = result {
print_worker_error(e.to_string(), &name); print_worker_error(e.to_string(), &name);
internal_handle internal_handle
.post_event(WorkerEvent::TerminalError(e)) .post_event(WorkerEvent::TerminalError(e))
.expect("Failed to post message to host"); .expect("Failed to post message to host");
// Failure to execute script is a terminal error, bye, bye. // Failure to execute script is a terminal error, bye, bye.
return Ok(()); return Ok(());
} }
let result = rt.block_on(worker.run_event_loop()); let result = rt.block_on(worker.run_event_loop(true));
debug!("Worker thread shuts down {}", &name); debug!("Worker thread shuts down {}", &name);
result result
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::tokio_util; use crate::tokio_util;
fn create_test_web_worker() -> WebWorker { fn create_test_web_worker() -> WebWorker {
skipping to change at line 569 skipping to change at line 566
create_web_worker_cb, create_web_worker_cb,
js_error_create_fn: None, js_error_create_fn: None,
use_deno_namespace: false, use_deno_namespace: false,
attach_inspector: false, attach_inspector: false,
maybe_inspector_server: None, maybe_inspector_server: None,
runtime_version: "x".to_string(), runtime_version: "x".to_string(),
ts_version: "x".to_string(), ts_version: "x".to_string(),
no_color: true, no_color: true,
get_error_class_fn: None, get_error_class_fn: None,
blob_url_store: BlobUrlStore::default(), blob_url_store: BlobUrlStore::default(),
broadcast_channel: InMemoryBroadcastChannel::default(),
}; };
let mut worker = WebWorker::from_options( let mut worker = WebWorker::from_options(
"TEST".to_string(), "TEST".to_string(),
Permissions::allow_all(), Permissions::allow_all(),
main_module, main_module,
WorkerId(1), WorkerId(1),
&options, &options,
); );
worker.bootstrap(&options); worker.bootstrap(&options);
skipping to change at line 604 skipping to change at line 602
} else { } else {
console.assert(e.data === "hi"); console.assert(e.data === "hi");
} }
postMessage([1, 2, 3]); postMessage([1, 2, 3]);
console.log("after postMessage"); console.log("after postMessage");
} }
"#; "#;
worker.execute(source).unwrap(); worker.execute(source).unwrap();
let handle = worker.thread_safe_handle(); let handle = worker.thread_safe_handle();
handle_sender.send(handle).unwrap(); handle_sender.send(handle).unwrap();
let r = tokio_util::run_basic(worker.run_event_loop()); let r = tokio_util::run_basic(worker.run_event_loop(false));
assert!(r.is_ok()) assert!(r.is_ok())
}); });
let mut handle = handle_receiver.recv().unwrap(); let mut handle = handle_receiver.recv().unwrap();
// TODO(Inteon): use Deno.core.serialize() instead of hardcoded encoded valu e // TODO(Inteon): use Deno.core.serialize() instead of hardcoded encoded valu e
let msg = vec![34, 2, 104, 105].into_boxed_slice(); // "hi" encoded let msg = vec![34, 2, 104, 105].into_boxed_slice(); // "hi" encoded
let r = handle.post_message(msg.clone().into()); let r = handle.post_message(msg.clone().into());
assert!(r.is_ok()); assert!(r.is_ok());
skipping to change at line 651 skipping to change at line 649
#[tokio::test] #[tokio::test]
async fn removed_from_resource_table_on_close() { async fn removed_from_resource_table_on_close() {
let (handle_sender, handle_receiver) = let (handle_sender, handle_receiver) =
std::sync::mpsc::sync_channel::<WebWorkerHandle>(1); std::sync::mpsc::sync_channel::<WebWorkerHandle>(1);
let join_handle = std::thread::spawn(move || { let join_handle = std::thread::spawn(move || {
let mut worker = create_test_web_worker(); let mut worker = create_test_web_worker();
worker.execute("onmessage = () => { close(); }").unwrap(); worker.execute("onmessage = () => { close(); }").unwrap();
let handle = worker.thread_safe_handle(); let handle = worker.thread_safe_handle();
handle_sender.send(handle).unwrap(); handle_sender.send(handle).unwrap();
let r = tokio_util::run_basic(worker.run_event_loop()); let r = tokio_util::run_basic(worker.run_event_loop(false));
assert!(r.is_ok()) assert!(r.is_ok())
}); });
let mut handle = handle_receiver.recv().unwrap(); let mut handle = handle_receiver.recv().unwrap();
// TODO(Inteon): use Deno.core.serialize() instead of hardcoded encoded valu e // TODO(Inteon): use Deno.core.serialize() instead of hardcoded encoded valu e
let msg = vec![34, 2, 104, 105].into_boxed_slice(); // "hi" encoded let msg = vec![34, 2, 104, 105].into_boxed_slice(); // "hi" encoded
let r = handle.post_message(msg.clone().into()); let r = handle.post_message(msg.clone().into());
assert!(r.is_ok()); assert!(r.is_ok());
let event = handle.get_event().await.unwrap(); let event = handle.get_event().await.unwrap();
 End of changes. 16 change blocks. 
29 lines changed or deleted 27 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)