mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 14:28:17 +03:00
nodeipc: test send/recv stdio
Summary: Tested variations mentioned in the added README, especially the nodejs -> parent -> child case: Windows: $ node hello_parent.js [Parent] Got message from child: HELLO FROM CHILD [Child] Got message from parent: String("HELLO FROM PARENT 1") [Parent] Got message from child: [ 'Echo from child', 'HELLO FROM PARENT 1' ] [Child] Got message from parent: String("HELLO FROM PARENT 2") [Parent] Got message from child: [ 'Echo from child', 'HELLO FROM PARENT 2' ] [Child] Got message from parent: String("BYE") [Parent] Child process has exited $ cargo run --example spawn_sendfd Parent: spawning child Parent: sending hello Parent: sending a.txt file descriptor Parent: sending stdio Parent: waiting for child to exit Child: started with IPC handle 100 Child: got message Some("hello") Child: got sendfd payload SendFdPayload { pid: 41528, raw_fds: [0x118] } Child: writing "something\n" to fd 0x118 Child: got stdio Child: write to stderr Child: no IPC singleton $ node hello_parent.js spawn_sendfd Parent: spawning child Parent: sending hello Parent: sending a.txt file descriptor Parent: sending stdio Parent: waiting for child to exit Child: started with IPC handle 100 Child: got message Some("hello") Child: got sendfd payload SendFdPayload { pid: 49952, raw_fds: [0x118] } Child: writing "something\n" to fd 0x118 Child: got stdio Child: write to stderr Child: has IPC singleton [Parent] Got message from child: HELLO FROM CHILD Child: Got message: String("HELLO FROM PARENT 1") [Parent] Got message from child: [ 'Echo from child', 'HELLO FROM PARENT 1' ] Child: Got message: String("HELLO FROM PARENT 2") [Parent] Got message from child: [ 'Echo from child', 'HELLO FROM PARENT 2' ] Child: Got message: String("BYE") [Parent] Child process has exited Linux: % node hello_parent.js [Parent] Got message from child: HELLO FROM CHILD [Child] Got message from parent: String("HELLO FROM PARENT 1") [Parent] Got message from child: [ 'Echo from child', 'HELLO FROM PARENT 1' ] [Child] Got message from parent: String("HELLO FROM PARENT 2") [Parent] Got message from child: [ 'Echo from child', 'HELLO FROM PARENT 2' ] [Child] Got message from parent: String("BYE") [Parent] Child process has exited % cargo run --example spawn_sendfd Parent: spawning child Parent: sending hello Parent: sending a.txt file descriptor Parent: sending stdio Parent: waiting for child to exit Child: started with IPC handle 4 Child: got message Some("hello") Child: got sendfd payload SendFdPayload { raw_fds: [3] } Child: writing "something\n" to fd 3 Child: got stdio Child: write to stderr Child: no IPC singleton % node hello_parent.js spawn_sendfd Parent: spawning child Parent: sending hello Parent: sending a.txt file descriptor Parent: sending stdio Parent: waiting for child to exit Child: started with IPC handle 5 Child: got message Some("hello") Child: got sendfd payload SendFdPayload { raw_fds: [4] } Child: writing "something\n" to fd 4 Child: got stdio Child: write to stderr Child: has IPC singleton [Parent] Got message from child: HELLO FROM CHILD Child: Got message: String("HELLO FROM PARENT 1") [Parent] Got message from child: [ 'Echo from child', 'HELLO FROM PARENT 1' ] Child: Got message: String("HELLO FROM PARENT 2") [Parent] Got message from child: [ 'Echo from child', 'HELLO FROM PARENT 2' ] Child: Got message: String("BYE") [Parent] Child process has exited Reviewed By: muirdm Differential Revision: D46811170 fbshipit-source-id: 96b2d4a7a3c5f8599058faea949ea3ee7be962be
This commit is contained in:
parent
633dfd6ab6
commit
60ae5c218a
24
eden/scm/lib/util/nodeipc/examples/README
Normal file
24
eden/scm/lib/util/nodeipc/examples/README
Normal file
@ -0,0 +1,24 @@
|
||||
Examples serve as tests.
|
||||
|
||||
NodeIpc has multiple features:
|
||||
A. Integrate to nodejs as a child process (singleton).
|
||||
B. Send/receive messages (native, or compatible with nodejs).
|
||||
C. Send/receive file descriptors (incompatible with nodejs).
|
||||
D. Send/receive stdio (console) and nodejs IPC channel.
|
||||
|
||||
Different example combinations exercise different features:
|
||||
- hello_parent.js + hello_child.rs exercises feature A + B
|
||||
Run (hello_parent.js calls cargo build):
|
||||
node hello_parent.js
|
||||
- spawn_sendfd.rs exercises feature B + C + D
|
||||
Run:
|
||||
cargo run --example spawn_sendfd
|
||||
cargo run --example spawn_sendfd 1>b.txt
|
||||
- hello_parent.js + hello_child.rs + spawn_sendfd.rs exercises feature A + B + C + D
|
||||
Run:
|
||||
node hello_parent.js spawn_sendfd
|
||||
|
||||
Panic or error messages indicate something went wrong.
|
||||
|
||||
Windows and Unix are significantly different so the commands should be checked
|
||||
on both platforms.
|
@ -7,7 +7,8 @@
|
||||
|
||||
const {spawn, spawnSync} = require('child_process');
|
||||
|
||||
const build = spawnSync('cargo', ['build', '--message-format=json', '--release', '--example', 'hello_child'], {stdio: [0, 'pipe', 2]});
|
||||
const example = process.argv[2] ?? 'hello_child';
|
||||
const build = spawnSync('cargo', ['build', '--message-format=json', '--release', '--example', example], {stdio: [0, 'pipe', 2]});
|
||||
const output = build.stdout.toString();
|
||||
|
||||
let executable = null;
|
||||
|
@ -15,6 +15,8 @@ use filedescriptor::FileDescriptor;
|
||||
use filedescriptor::FromRawFileDescriptor;
|
||||
use filedescriptor::RawFileDescriptor;
|
||||
use nodeipc::NodeIpc;
|
||||
use serde_json::json;
|
||||
use serde_json::Value;
|
||||
|
||||
fn main() {
|
||||
let is_child = env::args().nth(1).as_deref() == Some("child");
|
||||
@ -53,6 +55,25 @@ fn child_main() {
|
||||
// Do not make FileDescriptor close the handle. We might still need it for `println!`.
|
||||
mem::forget(fd);
|
||||
}
|
||||
|
||||
ipc.recv_stdio().unwrap();
|
||||
println!("Child: got stdio");
|
||||
eprintln!("Child: write to stderr");
|
||||
|
||||
if let Some(ipc) = nodeipc::get_singleton() {
|
||||
println!("Child: has IPC singleton");
|
||||
ipc.send("HELLO FROM CHILD").unwrap();
|
||||
while let Some(message) = ipc.recv::<Value>().unwrap() {
|
||||
println!("Child: Got message: {:?}", message);
|
||||
if message.as_str() == Some("BYE") {
|
||||
break;
|
||||
} else {
|
||||
ipc.send(json!(["Echo from child", message])).unwrap();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("Child: no IPC singleton");
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_main() {
|
||||
@ -88,16 +109,18 @@ fn parent_main() {
|
||||
println!("Parent: sending hello");
|
||||
ipc.send("hello").unwrap();
|
||||
|
||||
println!("Parent: sending stdio and a.txt file descriptors");
|
||||
let mut fds = stdio_fd_vec();
|
||||
println!("Parent: sending a.txt file descriptor");
|
||||
let file = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open("a.txt")
|
||||
.unwrap();
|
||||
fds.push(file.as_raw_file_descriptor());
|
||||
let fds = [file.as_raw_file_descriptor()];
|
||||
ipc.send_fd_vec(&fds).unwrap();
|
||||
|
||||
println!("Parent: sending stdio");
|
||||
ipc.send_stdio().unwrap();
|
||||
|
||||
println!("Parent: waiting for child to exit");
|
||||
child.wait().unwrap();
|
||||
}
|
||||
@ -116,28 +139,3 @@ fn maybe_init_winsock() {
|
||||
assert_eq!(ret, 0, "failed to initialize winsock");
|
||||
}
|
||||
}
|
||||
|
||||
fn stdio_fd_vec() -> Vec<RawFileDescriptor> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
use winapi::um::processenv::GetStdHandle;
|
||||
use winapi::um::winbase::STD_ERROR_HANDLE;
|
||||
use winapi::um::winbase::STD_INPUT_HANDLE;
|
||||
use winapi::um::winbase::STD_OUTPUT_HANDLE;
|
||||
|
||||
result.push(GetStdHandle(STD_INPUT_HANDLE) as _);
|
||||
result.push(GetStdHandle(STD_OUTPUT_HANDLE) as _);
|
||||
result.push(GetStdHandle(STD_ERROR_HANDLE) as _);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
result.push(libc::STDIN_FILENO);
|
||||
result.push(libc::STDOUT_FILENO);
|
||||
result.push(libc::STDERR_FILENO);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user