-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding support for
uncaughtException
and unhandledRejection
events (
#213) * Centralizing uncaught exception reporting * Adding uncaught_exception_monitor_callback pre-hook for exceptions * Connecting exception capture callbacks with process events * Running uncaught_exception capture callback on exceptions (WIP) * Fixing REPL output when a capture is in place * Using unhandledRejection capture callback for uncaught promises * Handling multiple promise rejections * Fixing double capture execution on errored module * Refactoring * Fixing duplicate error capturing on errored modules * Fixing borrow panics when running capture callbacks * Adding documentation to README.md * Updating the the-runtime.md documentation
- Loading branch information
Showing
13 changed files
with
420 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
use crate::bindings::set_function_to; | ||
use crate::runtime::JsRuntime; | ||
use std::collections::HashMap; | ||
|
||
pub struct ExceptionState { | ||
/// Holds the current uncaught exception. | ||
pub exception: Option<v8::Global<v8::Value>>, | ||
/// Holds uncaught promise rejections. | ||
pub promise_rejections: HashMap<v8::Global<v8::Promise>, v8::Global<v8::Value>>, | ||
/// Hook to run on an uncaught exception. | ||
pub uncaught_exception_cb: Option<v8::Global<v8::Function>>, | ||
/// Hook to run on an uncaught promise rejection. | ||
pub unhandled_rejection_cb: Option<v8::Global<v8::Function>>, | ||
} | ||
|
||
impl ExceptionState { | ||
/// Creates a new store with given report policy. | ||
pub fn new() -> Self { | ||
ExceptionState { | ||
exception: None, | ||
promise_rejections: HashMap::new(), | ||
uncaught_exception_cb: None, | ||
unhandled_rejection_cb: None, | ||
} | ||
} | ||
|
||
/// Registers the uncaught exception. | ||
pub fn capture_exception(&mut self, exception: v8::Global<v8::Value>) { | ||
if self.exception.is_none() { | ||
self.exception = Some(exception); | ||
} | ||
} | ||
|
||
/// Registers a promise rejection to the store. | ||
pub fn capture_promise_rejection( | ||
&mut self, | ||
promise: v8::Global<v8::Promise>, | ||
reason: v8::Global<v8::Value>, | ||
) { | ||
self.promise_rejections.insert(promise, reason); | ||
} | ||
|
||
pub fn has_promise_rejection(&self) -> bool { | ||
!self.promise_rejections.is_empty() | ||
} | ||
|
||
pub fn remove_promise_rejection(&mut self, promise: &v8::Global<v8::Promise>) { | ||
self.promise_rejections.remove(promise); | ||
} | ||
|
||
pub fn remove_promise_rejection_entry(&mut self, exception: &v8::Global<v8::Value>) { | ||
// Find the correct entry to remove. | ||
let mut key_to_remove = None; | ||
for (key, value) in self.promise_rejections.iter() { | ||
if value == exception { | ||
key_to_remove = Some(key.clone()); | ||
break; | ||
} | ||
} | ||
|
||
if let Some(promise) = key_to_remove { | ||
self.promise_rejections.remove(&promise); | ||
} | ||
} | ||
|
||
pub fn set_uncaught_exception_callback(&mut self, callback: Option<v8::Global<v8::Function>>) { | ||
self.uncaught_exception_cb = callback; | ||
} | ||
|
||
pub fn set_unhandled_rejection_callback(&mut self, callback: Option<v8::Global<v8::Function>>) { | ||
self.unhandled_rejection_cb = callback; | ||
} | ||
} | ||
|
||
pub fn initialize(scope: &mut v8::HandleScope) -> v8::Global<v8::Object> { | ||
// Create local JS object. | ||
let target = v8::Object::new(scope); | ||
|
||
set_function_to( | ||
scope, | ||
target, | ||
"setUncaughtExceptionCallback", | ||
set_uncaught_exception_callback, | ||
); | ||
|
||
set_function_to( | ||
scope, | ||
target, | ||
"setUnhandledRejectionCallback", | ||
set_unhandled_rejection_callback, | ||
); | ||
|
||
// Return v8 global handle. | ||
v8::Global::new(scope, target) | ||
} | ||
|
||
/// Setting the `uncaught_exception_callback` from JavaScript. | ||
fn set_uncaught_exception_callback( | ||
scope: &mut v8::HandleScope, | ||
args: v8::FunctionCallbackArguments, | ||
mut rv: v8::ReturnValue, | ||
) { | ||
// Note: Passing `null` from JavaScript essentially will unset the defined callback. | ||
let callback = match v8::Local::<v8::Function>::try_from(args.get(0)) { | ||
Ok(callback) => Some(v8::Global::new(scope, callback)), | ||
Err(_) => None, | ||
}; | ||
|
||
let state_rc = JsRuntime::state(scope); | ||
let mut state = state_rc.borrow_mut(); | ||
|
||
state.exceptions.set_uncaught_exception_callback(callback); | ||
|
||
rv.set(v8::Boolean::new(scope, true).into()); | ||
} | ||
|
||
/// Setting the `unhandled_rejection_callback` from JavaScript. | ||
fn set_unhandled_rejection_callback( | ||
scope: &mut v8::HandleScope, | ||
args: v8::FunctionCallbackArguments, | ||
mut rv: v8::ReturnValue, | ||
) { | ||
// Note: Passing `null` from JavaScript essentially will unset the defined callback. | ||
let callback = match v8::Local::<v8::Function>::try_from(args.get(0)) { | ||
Ok(callback) => Some(v8::Global::new(scope, callback)), | ||
Err(_) => None, | ||
}; | ||
|
||
let state_rc = JsRuntime::state(scope); | ||
let mut state = state_rc.borrow_mut(); | ||
|
||
state.exceptions.set_unhandled_rejection_callback(callback); | ||
|
||
rv.set(v8::Boolean::new(scope, true).into()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ mod cli; | |
mod dns; | ||
mod dotenv; | ||
mod errors; | ||
mod exceptions; | ||
mod file; | ||
mod hooks; | ||
mod http_parser; | ||
|
Oops, something went wrong.