2022-04-15 08:24:41 -04:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::io::Read;
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
2021-08-26 15:21:58 -04:00
|
|
|
use crate::tools::test::TestEvent;
|
2022-04-15 08:24:41 -04:00
|
|
|
use crate::tools::test::TestOutput;
|
2021-04-25 17:38:59 -04:00
|
|
|
use deno_core::error::generic_error;
|
|
|
|
use deno_core::error::AnyError;
|
2022-03-14 13:44:15 -04:00
|
|
|
use deno_core::op;
|
2021-12-29 08:30:08 -05:00
|
|
|
use deno_core::Extension;
|
2021-04-30 11:56:47 -04:00
|
|
|
use deno_core::ModuleSpecifier;
|
2021-04-25 17:38:59 -04:00
|
|
|
use deno_core::OpState;
|
2022-04-15 08:24:41 -04:00
|
|
|
use deno_runtime::ops::io::StdFileResource;
|
2021-10-13 13:04:44 -04:00
|
|
|
use deno_runtime::permissions::create_child_permissions;
|
|
|
|
use deno_runtime::permissions::ChildPermissionsArg;
|
2021-04-25 17:38:59 -04:00
|
|
|
use deno_runtime::permissions::Permissions;
|
2022-03-08 19:34:31 -05:00
|
|
|
use tokio::sync::mpsc::UnboundedSender;
|
2021-04-25 17:38:59 -04:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
2022-04-15 08:24:41 -04:00
|
|
|
pub fn init(
|
|
|
|
sender: UnboundedSender<TestEvent>,
|
|
|
|
stdout_writer: os_pipe::PipeWriter,
|
|
|
|
stderr_writer: os_pipe::PipeWriter,
|
|
|
|
) -> Extension {
|
|
|
|
// todo(dsheret): don't do this? Taking out the writers was necessary to prevent invalid handle panics
|
|
|
|
let stdout_writer = Rc::new(RefCell::new(Some(stdout_writer)));
|
|
|
|
let stderr_writer = Rc::new(RefCell::new(Some(stderr_writer)));
|
|
|
|
|
2021-12-29 08:30:08 -05:00
|
|
|
Extension::builder()
|
|
|
|
.ops(vec![
|
2022-03-14 13:44:15 -04:00
|
|
|
op_pledge_test_permissions::decl(),
|
|
|
|
op_restore_test_permissions::decl(),
|
|
|
|
op_get_test_origin::decl(),
|
|
|
|
op_dispatch_test_event::decl(),
|
2021-12-29 08:30:08 -05:00
|
|
|
])
|
2022-04-15 08:24:41 -04:00
|
|
|
.middleware(|op| match op.name {
|
|
|
|
"op_print" => op_print::decl(),
|
|
|
|
_ => op,
|
|
|
|
})
|
2021-12-29 08:30:08 -05:00
|
|
|
.state(move |state| {
|
2022-04-15 08:24:41 -04:00
|
|
|
state.resource_table.replace(
|
|
|
|
1,
|
|
|
|
StdFileResource::stdio(
|
|
|
|
&pipe_writer_to_file(&stdout_writer.borrow_mut().take().unwrap()),
|
|
|
|
"stdout",
|
|
|
|
),
|
|
|
|
);
|
|
|
|
state.resource_table.replace(
|
|
|
|
2,
|
|
|
|
StdFileResource::stdio(
|
|
|
|
&pipe_writer_to_file(&stderr_writer.borrow_mut().take().unwrap()),
|
|
|
|
"stderr",
|
|
|
|
),
|
|
|
|
);
|
2021-12-29 08:30:08 -05:00
|
|
|
state.put(sender.clone());
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
.build()
|
2021-04-25 17:38:59 -04:00
|
|
|
}
|
|
|
|
|
2022-04-15 08:24:41 -04:00
|
|
|
#[cfg(windows)]
|
|
|
|
fn pipe_writer_to_file(writer: &os_pipe::PipeWriter) -> std::fs::File {
|
|
|
|
use std::os::windows::prelude::AsRawHandle;
|
|
|
|
use std::os::windows::prelude::FromRawHandle;
|
|
|
|
unsafe { std::fs::File::from_raw_handle(writer.as_raw_handle()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
fn pipe_writer_to_file(writer: &os_pipe::PipeWriter) -> std::fs::File {
|
|
|
|
use std::os::unix::io::AsRawFd;
|
|
|
|
use std::os::unix::io::FromRawFd;
|
|
|
|
unsafe { std::fs::File::from_raw_fd(writer.as_raw_fd()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates the stdout and stderr pipes and returns the writers for stdout and stderr.
|
|
|
|
pub fn create_stdout_stderr_pipes(
|
|
|
|
sender: UnboundedSender<TestEvent>,
|
|
|
|
) -> (os_pipe::PipeWriter, os_pipe::PipeWriter) {
|
|
|
|
let (stdout_reader, stdout_writer) = os_pipe::pipe().unwrap();
|
|
|
|
let (stderr_reader, stderr_writer) = os_pipe::pipe().unwrap();
|
|
|
|
|
|
|
|
start_output_redirect_thread(stdout_reader, sender.clone(), |bytes| {
|
|
|
|
TestOutput::Stdout(bytes)
|
|
|
|
});
|
|
|
|
start_output_redirect_thread(stderr_reader, sender, |bytes| {
|
|
|
|
TestOutput::Stderr(bytes)
|
|
|
|
});
|
|
|
|
|
|
|
|
(stdout_writer, stderr_writer)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn start_output_redirect_thread(
|
|
|
|
mut pipe_reader: os_pipe::PipeReader,
|
|
|
|
sender: UnboundedSender<TestEvent>,
|
|
|
|
map_test_output: impl Fn(Vec<u8>) -> TestOutput + Send + 'static,
|
|
|
|
) {
|
|
|
|
tokio::task::spawn_blocking(move || loop {
|
|
|
|
let mut buffer = [0; 512];
|
|
|
|
let size = match pipe_reader.read(&mut buffer) {
|
|
|
|
Ok(0) | Err(_) => break,
|
|
|
|
Ok(size) => size,
|
|
|
|
};
|
|
|
|
if sender
|
|
|
|
.send(TestEvent::Output(map_test_output(buffer[0..size].to_vec())))
|
|
|
|
.is_err()
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-04-25 17:38:59 -04:00
|
|
|
#[derive(Clone)]
|
|
|
|
struct PermissionsHolder(Uuid, Permissions);
|
|
|
|
|
2022-03-14 13:44:15 -04:00
|
|
|
#[op]
|
2021-04-25 17:38:59 -04:00
|
|
|
pub fn op_pledge_test_permissions(
|
|
|
|
state: &mut OpState,
|
2021-10-13 13:04:44 -04:00
|
|
|
args: ChildPermissionsArg,
|
2021-04-25 17:38:59 -04:00
|
|
|
) -> Result<Uuid, AnyError> {
|
|
|
|
let token = Uuid::new_v4();
|
2021-10-13 13:04:44 -04:00
|
|
|
let parent_permissions = state.borrow_mut::<Permissions>();
|
|
|
|
let worker_permissions = create_child_permissions(parent_permissions, args)?;
|
|
|
|
let parent_permissions = parent_permissions.clone();
|
2021-04-25 17:38:59 -04:00
|
|
|
|
2022-04-17 11:47:24 -04:00
|
|
|
if state.try_take::<PermissionsHolder>().is_some() {
|
|
|
|
panic!("pledge test permissions called before restoring previous pledge");
|
|
|
|
}
|
2021-04-25 17:38:59 -04:00
|
|
|
state.put::<PermissionsHolder>(PermissionsHolder(token, parent_permissions));
|
|
|
|
|
|
|
|
// NOTE: This call overrides current permission set for the worker
|
|
|
|
state.put::<Permissions>(worker_permissions);
|
|
|
|
|
|
|
|
Ok(token)
|
|
|
|
}
|
|
|
|
|
2022-03-14 13:44:15 -04:00
|
|
|
#[op]
|
2021-04-25 17:38:59 -04:00
|
|
|
pub fn op_restore_test_permissions(
|
|
|
|
state: &mut OpState,
|
|
|
|
token: Uuid,
|
|
|
|
) -> Result<(), AnyError> {
|
|
|
|
if let Some(permissions_holder) = state.try_take::<PermissionsHolder>() {
|
|
|
|
if token != permissions_holder.0 {
|
|
|
|
panic!("restore test permissions token does not match the stored token");
|
|
|
|
}
|
|
|
|
|
|
|
|
let permissions = permissions_holder.1;
|
|
|
|
state.put::<Permissions>(permissions);
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(generic_error("no permissions to restore"))
|
|
|
|
}
|
|
|
|
}
|
2021-04-28 14:17:04 -04:00
|
|
|
|
2022-03-14 13:44:15 -04:00
|
|
|
#[op]
|
2022-03-14 18:38:53 -04:00
|
|
|
fn op_get_test_origin(state: &mut OpState) -> Result<String, AnyError> {
|
2021-07-14 15:05:16 -04:00
|
|
|
Ok(state.borrow::<ModuleSpecifier>().to_string())
|
2021-04-28 14:17:04 -04:00
|
|
|
}
|
|
|
|
|
2022-03-14 13:44:15 -04:00
|
|
|
#[op]
|
2021-07-14 15:05:16 -04:00
|
|
|
fn op_dispatch_test_event(
|
2021-04-28 14:17:04 -04:00
|
|
|
state: &mut OpState,
|
2021-07-14 15:05:16 -04:00
|
|
|
event: TestEvent,
|
|
|
|
) -> Result<(), AnyError> {
|
2022-03-08 19:34:31 -05:00
|
|
|
let sender = state.borrow::<UnboundedSender<TestEvent>>().clone();
|
2021-07-14 15:05:16 -04:00
|
|
|
sender.send(event).ok();
|
2022-04-15 08:24:41 -04:00
|
|
|
Ok(())
|
|
|
|
}
|
2021-04-30 11:56:47 -04:00
|
|
|
|
2022-04-15 08:24:41 -04:00
|
|
|
#[op]
|
|
|
|
pub fn op_print(
|
|
|
|
state: &mut OpState,
|
|
|
|
msg: String,
|
|
|
|
is_err: bool,
|
|
|
|
) -> Result<(), AnyError> {
|
|
|
|
let sender = state.borrow::<UnboundedSender<TestEvent>>().clone();
|
|
|
|
let msg = if is_err {
|
|
|
|
TestOutput::PrintStderr(msg)
|
|
|
|
} else {
|
|
|
|
TestOutput::PrintStdout(msg)
|
|
|
|
};
|
|
|
|
sender.send(TestEvent::Output(msg)).ok();
|
2021-07-14 15:05:16 -04:00
|
|
|
Ok(())
|
2021-04-28 14:17:04 -04:00
|
|
|
}
|