mirror of
https://github.com/CloudNebulaProject/wayray.git
synced 2026-04-10 13:10:41 +00:00
Add doors IPC transport for illumos, simplify client binaries
Add platform-aware IPC transport layer for the launcher protocol: - transport module: send_request_sync() auto-selects doors (illumos) or Unix sockets (Linux) at compile time - doors_transport: uses doors::Client for high-speed synchronous RPC, gated behind cfg(target_os = "illumos") + "doors" feature flag - unix_transport: blocking Unix socket client for all platforms Simplify client binaries to use the sync transport: - wradm: drops tokio dependency entirely, now fully synchronous - wrlogin: drops tokio dependency, uses sync transport - wrsessd: uses shared default_ipc_path() for consistency The doors crate (0.8.1) is an optional illumos-only dependency. On Linux, all code compiles and tests pass with Unix socket transport.
This commit is contained in:
parent
f6b9ea56ba
commit
70859175c0
9 changed files with 208 additions and 145 deletions
83
Cargo.lock
generated
83
Cargo.lock
generated
|
|
@ -330,7 +330,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -621,6 +621,26 @@ dependencies = [
|
||||||
"litrs",
|
"litrs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "door-macros"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78929f3574c3a17e7a7a844bcb1cbcbf165d3e366432f81cef4e8cb6e8c2a715"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doors"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "571031accecc9496ab74c0ce6d9d99ef779a7344dd27f504e1574edd344cd479"
|
||||||
|
dependencies = [
|
||||||
|
"door-macros",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "downcast-rs"
|
name = "downcast-rs"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
|
|
@ -738,7 +758,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1033,7 +1053,7 @@ checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1079,7 +1099,7 @@ dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"simd_cesu8",
|
"simd_cesu8",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1107,7 +1127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
|
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1309,7 +1329,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1448,7 +1468,7 @@ dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1795,7 +1815,7 @@ checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1910,7 +1930,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1947,7 +1967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
|
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2399,7 +2419,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2641,7 +2661,7 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2671,6 +2691,17 @@ version = "3.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
|
checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.117"
|
version = "2.0.117"
|
||||||
|
|
@ -2750,7 +2781,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2761,7 +2792,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2856,7 +2887,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2950,7 +2981,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3140,7 +3171,7 @@ dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -3338,6 +3369,7 @@ dependencies = [
|
||||||
name = "wayray-protocol"
|
name = "wayray-protocol"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"doors",
|
||||||
"postcard",
|
"postcard",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -3535,7 +3567,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3546,7 +3578,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3831,7 +3863,7 @@ dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"wasm-metadata",
|
"wasm-metadata",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-component",
|
"wit-component",
|
||||||
|
|
@ -3847,7 +3879,7 @@ dependencies = [
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-bindgen-rust",
|
"wit-bindgen-rust",
|
||||||
]
|
]
|
||||||
|
|
@ -3904,10 +3936,6 @@ name = "wradm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"miette",
|
"miette",
|
||||||
"serde_json",
|
|
||||||
"tokio",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
"wayray-protocol",
|
"wayray-protocol",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -3936,9 +3964,6 @@ name = "wrlogin"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"miette",
|
"miette",
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tokio",
|
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"wayray-protocol",
|
"wayray-protocol",
|
||||||
|
|
@ -4076,7 +4101,7 @@ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@ edition.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
doors = ["dep:doors"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
postcard.workspace = true
|
postcard.workspace = true
|
||||||
|
|
@ -12,3 +16,6 @@ tracing.workspace = true
|
||||||
zstd.workspace = true
|
zstd.workspace = true
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "illumos")'.dependencies]
|
||||||
|
doors = { version = "0.8", optional = true }
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ pub mod encoding;
|
||||||
pub mod launcher;
|
pub mod launcher;
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod session_config;
|
pub mod session_config;
|
||||||
|
pub mod transport;
|
||||||
|
|
||||||
/// Current protocol version. Incremented on breaking changes.
|
/// Current protocol version. Incremented on breaking changes.
|
||||||
pub const PROTOCOL_VERSION: u32 = 1;
|
pub const PROTOCOL_VERSION: u32 = 1;
|
||||||
|
|
|
||||||
114
crates/wayray-protocol/src/transport.rs
Normal file
114
crates/wayray-protocol/src/transport.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
//! IPC transport abstraction for the launcher protocol.
|
||||||
|
//!
|
||||||
|
//! Provides platform-specific transports for request/response communication
|
||||||
|
//! between WayRay components (wrsessd, wradm, wrlogin, wrsrvd).
|
||||||
|
//!
|
||||||
|
//! - **Linux**: Unix domain sockets (async, via tokio)
|
||||||
|
//! - **illumos**: Doors IPC (sync, high-speed RPC) with Unix socket fallback
|
||||||
|
//!
|
||||||
|
//! The transport moves JSON bytes — serialization is handled by the caller
|
||||||
|
//! using [`LauncherRequest`] and [`LauncherResponse`].
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use crate::launcher::{LauncherRequest, LauncherResponse};
|
||||||
|
|
||||||
|
/// Default IPC endpoint path.
|
||||||
|
///
|
||||||
|
/// On illumos with doors enabled, this is a door file.
|
||||||
|
/// On Linux, this is a Unix socket.
|
||||||
|
pub fn default_ipc_path() -> PathBuf {
|
||||||
|
let runtime_dir = std::env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp".to_string());
|
||||||
|
PathBuf::from(runtime_dir).join("wayray-launcher.sock")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send a request and receive a response (synchronous, blocking).
|
||||||
|
///
|
||||||
|
/// Automatically selects the transport based on the platform:
|
||||||
|
/// - illumos with `doors` feature: uses doors IPC
|
||||||
|
/// - everywhere else: uses Unix socket with blocking I/O
|
||||||
|
pub fn send_request_sync(path: &Path, request: &LauncherRequest) -> io::Result<LauncherResponse> {
|
||||||
|
#[cfg(all(target_os = "illumos", feature = "doors"))]
|
||||||
|
{
|
||||||
|
doors_transport::send_request(path, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(all(target_os = "illumos", feature = "doors")))]
|
||||||
|
{
|
||||||
|
unix_transport::send_request(path, request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Unix socket transport (all platforms, used as default)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
pub mod unix_transport {
|
||||||
|
use std::io::{self, BufRead, BufReader, Write};
|
||||||
|
use std::os::unix::net::UnixStream;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use crate::launcher::{LauncherRequest, LauncherResponse};
|
||||||
|
|
||||||
|
/// Send a request over a Unix socket and read the response.
|
||||||
|
pub fn send_request(path: &Path, request: &LauncherRequest) -> io::Result<LauncherResponse> {
|
||||||
|
let stream = UnixStream::connect(path)?;
|
||||||
|
let mut writer = io::BufWriter::new(&stream);
|
||||||
|
let mut reader = BufReader::new(&stream);
|
||||||
|
|
||||||
|
let mut json = serde_json::to_string(request)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
|
json.push('\n');
|
||||||
|
writer.write_all(json.as_bytes())?;
|
||||||
|
writer.flush()?;
|
||||||
|
|
||||||
|
let mut response_line = String::new();
|
||||||
|
reader.read_line(&mut response_line)?;
|
||||||
|
|
||||||
|
serde_json::from_str(response_line.trim())
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Doors transport (illumos only)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "illumos", feature = "doors"))]
|
||||||
|
pub mod doors_transport {
|
||||||
|
use std::io;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use crate::launcher::{LauncherRequest, LauncherResponse};
|
||||||
|
|
||||||
|
/// Send a request via illumos doors IPC.
|
||||||
|
///
|
||||||
|
/// Doors are synchronous RPC: call_with_data sends bytes and blocks
|
||||||
|
/// until the server procedure returns a response.
|
||||||
|
pub fn send_request(path: &Path, request: &LauncherRequest) -> io::Result<LauncherResponse> {
|
||||||
|
let json = serde_json::to_vec(request)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
|
|
||||||
|
let client = doors::Client::open(path)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::ConnectionRefused, format!("{e:?}")))?;
|
||||||
|
|
||||||
|
let response_bytes = client
|
||||||
|
.call_with_data(&json)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{e:?}")))?;
|
||||||
|
|
||||||
|
serde_json::from_slice(&response_bytes)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_path_is_reasonable() {
|
||||||
|
let path = default_ipc_path();
|
||||||
|
assert!(path.to_str().unwrap().contains("wayray-launcher"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,8 +6,4 @@ license.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wayray-protocol.workspace = true
|
wayray-protocol.workspace = true
|
||||||
tracing.workspace = true
|
|
||||||
tracing-subscriber.workspace = true
|
|
||||||
miette.workspace = true
|
miette.workspace = true
|
||||||
serde_json = "1"
|
|
||||||
tokio = { workspace = true, features = ["rt", "net", "io-util", "macros"] }
|
|
||||||
|
|
|
||||||
|
|
@ -1,61 +1,33 @@
|
||||||
//! wradm -- WayRay administration CLI.
|
//! wradm -- WayRay administration CLI.
|
||||||
//!
|
//!
|
||||||
//! Provides session management commands following the illumos `zoneadm`/`svcadm`
|
//! Provides session management commands following the illumos `zoneadm`/`svcadm`
|
||||||
//! pattern. Communicates with the session launcher (wrsessd) via Unix socket.
|
//! pattern. Communicates with the session launcher (wrsessd) via the platform
|
||||||
|
//! IPC transport (Unix sockets on Linux, doors on illumos).
|
||||||
//!
|
//!
|
||||||
//! ## Commands
|
//! ## Commands
|
||||||
//!
|
//!
|
||||||
//! - `wradm list` — List all managed sessions
|
//! - `wradm list` — List all managed sessions
|
||||||
//! - `wradm kill <token>` — Kill a session by token
|
//! - `wradm kill <token>` — Kill a session by token
|
||||||
//! - `wradm show <token>` — Show details for a session
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use miette::Result;
|
use miette::Result;
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
|
||||||
use tokio::net::UnixStream;
|
|
||||||
use wayray_protocol::launcher::{LauncherRequest, LauncherResponse};
|
use wayray_protocol::launcher::{LauncherRequest, LauncherResponse};
|
||||||
|
use wayray_protocol::transport;
|
||||||
|
|
||||||
/// Default launcher socket path.
|
fn ipc_path() -> PathBuf {
|
||||||
fn default_socket_path() -> PathBuf {
|
std::env::var("WAYRAY_LAUNCHER_SOCKET")
|
||||||
let runtime_dir = std::env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp".to_string());
|
.map(PathBuf::from)
|
||||||
PathBuf::from(runtime_dir).join("wayray-launcher.sock")
|
.unwrap_or_else(|_| transport::default_ipc_path())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a request to the launcher and read the response.
|
fn send(request: &LauncherRequest) -> Result<LauncherResponse> {
|
||||||
async fn send_request(request: &LauncherRequest) -> Result<LauncherResponse> {
|
transport::send_request_sync(&ipc_path(), request).map_err(|e| {
|
||||||
let socket_path = std::env::var("WAYRAY_LAUNCHER_SOCKET")
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|_| default_socket_path());
|
|
||||||
|
|
||||||
let stream = UnixStream::connect(&socket_path).await.map_err(|e| {
|
|
||||||
miette::miette!(
|
miette::miette!(
|
||||||
"failed to connect to launcher at {}: {}\n\nIs wrsessd running?",
|
"launcher communication failed: {}\n\nIs wrsessd running?",
|
||||||
socket_path.display(),
|
|
||||||
e
|
e
|
||||||
)
|
)
|
||||||
})?;
|
})
|
||||||
|
|
||||||
let (reader, mut writer) = stream.into_split();
|
|
||||||
|
|
||||||
let mut json = serde_json::to_string(request)
|
|
||||||
.map_err(|e| miette::miette!("serialization error: {}", e))?;
|
|
||||||
json.push('\n');
|
|
||||||
|
|
||||||
writer
|
|
||||||
.write_all(json.as_bytes())
|
|
||||||
.await
|
|
||||||
.map_err(|e| miette::miette!("failed to send request: {}", e))?;
|
|
||||||
|
|
||||||
let mut reader = BufReader::new(reader);
|
|
||||||
let mut response_line = String::new();
|
|
||||||
reader
|
|
||||||
.read_line(&mut response_line)
|
|
||||||
.await
|
|
||||||
.map_err(|e| miette::miette!("failed to read response: {}", e))?;
|
|
||||||
|
|
||||||
serde_json::from_str(response_line.trim())
|
|
||||||
.map_err(|e| miette::miette!("failed to parse response: {}", e))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_usage() {
|
fn print_usage() {
|
||||||
|
|
@ -66,15 +38,7 @@ fn print_usage() {
|
||||||
eprintln!(" kill <token> Kill a session by token");
|
eprintln!(" kill <token> Kill a session by token");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
fn main() -> Result<()> {
|
||||||
async fn main() -> Result<()> {
|
|
||||||
tracing_subscriber::fmt()
|
|
||||||
.with_env_filter(
|
|
||||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
|
||||||
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn")),
|
|
||||||
)
|
|
||||||
.init();
|
|
||||||
|
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
|
||||||
let command = args.get(1).map(String::as_str).unwrap_or_else(|| {
|
let command = args.get(1).map(String::as_str).unwrap_or_else(|| {
|
||||||
|
|
@ -84,7 +48,7 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
"list" => {
|
"list" => {
|
||||||
let response = send_request(&LauncherRequest::ListSessions).await?;
|
let response = send(&LauncherRequest::ListSessions)?;
|
||||||
match response {
|
match response {
|
||||||
LauncherResponse::SessionList { sessions } => {
|
LauncherResponse::SessionList { sessions } => {
|
||||||
if sessions.is_empty() {
|
if sessions.is_empty() {
|
||||||
|
|
@ -110,10 +74,9 @@ async fn main() -> Result<()> {
|
||||||
let token = args
|
let token = args
|
||||||
.get(2)
|
.get(2)
|
||||||
.ok_or_else(|| miette::miette!("Usage: wradm kill <token>"))?;
|
.ok_or_else(|| miette::miette!("Usage: wradm kill <token>"))?;
|
||||||
let response = send_request(&LauncherRequest::KillSession {
|
let response = send(&LauncherRequest::KillSession {
|
||||||
token: token.clone(),
|
token: token.clone(),
|
||||||
})
|
})?;
|
||||||
.await?;
|
|
||||||
match response {
|
match response {
|
||||||
LauncherResponse::SessionKilled { token } => {
|
LauncherResponse::SessionKilled { token } => {
|
||||||
println!("Session {token} killed.");
|
println!("Session {token} killed.");
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,3 @@ wayray-protocol.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
miette.workspace = true
|
miette.workspace = true
|
||||||
serde.workspace = true
|
|
||||||
serde_json = "1"
|
|
||||||
tokio = { workspace = true, features = ["rt", "net", "io-util", "macros"] }
|
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,16 @@
|
||||||
//! The session launcher (wrsessd) starts wrlogin as the first client
|
//! The session launcher (wrsessd) starts wrlogin as the first client
|
||||||
//! in a new session. wrlogin:
|
//! in a new session. wrlogin:
|
||||||
//! 1. Prompts for username and password on the terminal
|
//! 1. Prompts for username and password on the terminal
|
||||||
//! 2. Sends `session_authenticated` to wrsessd via the launcher socket
|
//! 2. Sends `session_authenticated` to wrsessd via the launcher IPC
|
||||||
//! 3. Exits on success, allowing the desktop to start
|
//! 3. Exits on success, allowing the desktop to start
|
||||||
|
|
||||||
use std::io::{self, BufRead, Write};
|
use std::io::{self, BufRead, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use miette::Result;
|
use miette::Result;
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt};
|
|
||||||
use tokio::net::UnixStream;
|
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use wayray_protocol::launcher::{LauncherRequest, LauncherResponse};
|
use wayray_protocol::launcher::{LauncherRequest, LauncherResponse};
|
||||||
|
use wayray_protocol::transport;
|
||||||
|
|
||||||
/// Read a line from stdin with a prompt.
|
/// Read a line from stdin with a prompt.
|
||||||
fn prompt(message: &str) -> io::Result<String> {
|
fn prompt(message: &str) -> io::Result<String> {
|
||||||
|
|
@ -36,53 +35,13 @@ fn prompt(message: &str) -> io::Result<String> {
|
||||||
Ok(line.trim().to_string())
|
Ok(line.trim().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send an authentication request to the session launcher.
|
fn ipc_path() -> PathBuf {
|
||||||
async fn authenticate(socket_path: &PathBuf, token: &str, user: &str) -> Result<LauncherResponse> {
|
std::env::var("WAYRAY_LAUNCHER_SOCKET")
|
||||||
let stream = UnixStream::connect(socket_path).await.map_err(|e| {
|
.map(PathBuf::from)
|
||||||
miette::miette!(
|
.unwrap_or_else(|_| transport::default_ipc_path())
|
||||||
"failed to connect to launcher at {}: {}",
|
|
||||||
socket_path.display(),
|
|
||||||
e
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let (reader, mut writer) = stream.into_split();
|
|
||||||
|
|
||||||
let request = LauncherRequest::SessionAuthenticated {
|
|
||||||
token: token.to_string(),
|
|
||||||
user: user.to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut json = serde_json::to_string(&request)
|
|
||||||
.map_err(|e| miette::miette!("failed to serialize request: {}", e))?;
|
|
||||||
json.push('\n');
|
|
||||||
|
|
||||||
writer
|
|
||||||
.write_all(json.as_bytes())
|
|
||||||
.await
|
|
||||||
.map_err(|e| miette::miette!("failed to send to launcher: {}", e))?;
|
|
||||||
|
|
||||||
let mut reader = tokio::io::BufReader::new(reader);
|
|
||||||
let mut response_line = String::new();
|
|
||||||
reader
|
|
||||||
.read_line(&mut response_line)
|
|
||||||
.await
|
|
||||||
.map_err(|e| miette::miette!("failed to read launcher response: {}", e))?;
|
|
||||||
|
|
||||||
let response: LauncherResponse = serde_json::from_str(response_line.trim())
|
|
||||||
.map_err(|e| miette::miette!("failed to parse launcher response: {}", e))?;
|
|
||||||
|
|
||||||
Ok(response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default launcher socket path.
|
fn main() -> Result<()> {
|
||||||
fn default_socket_path() -> PathBuf {
|
|
||||||
let runtime_dir = std::env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp".to_string());
|
|
||||||
PathBuf::from(runtime_dir).join("wayray-launcher.sock")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() -> Result<()> {
|
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(
|
.with_env_filter(
|
||||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||||
|
|
@ -90,10 +49,6 @@ async fn main() -> Result<()> {
|
||||||
)
|
)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let socket_path = std::env::var("WAYRAY_LAUNCHER_SOCKET")
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|_| default_socket_path());
|
|
||||||
|
|
||||||
// The session token is passed via environment variable by the launcher.
|
// The session token is passed via environment variable by the launcher.
|
||||||
let token = std::env::var("WAYRAY_SESSION_TOKEN").unwrap_or_else(|_| {
|
let token = std::env::var("WAYRAY_SESSION_TOKEN").unwrap_or_else(|_| {
|
||||||
eprintln!("warning: WAYRAY_SESSION_TOKEN not set, using 'unknown'");
|
eprintln!("warning: WAYRAY_SESSION_TOKEN not set, using 'unknown'");
|
||||||
|
|
@ -105,6 +60,8 @@ async fn main() -> Result<()> {
|
||||||
println!(" ============");
|
println!(" ============");
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
|
let path = ipc_path();
|
||||||
|
|
||||||
// Simple login loop.
|
// Simple login loop.
|
||||||
loop {
|
loop {
|
||||||
let user = prompt(" Username: ").map_err(|e| miette::miette!("input error: {}", e))?;
|
let user = prompt(" Username: ").map_err(|e| miette::miette!("input error: {}", e))?;
|
||||||
|
|
@ -121,11 +78,15 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
info!(%user, "authenticating with session launcher");
|
info!(%user, "authenticating with session launcher");
|
||||||
|
|
||||||
match authenticate(&socket_path, &token, &user).await {
|
let request = LauncherRequest::SessionAuthenticated {
|
||||||
|
token: token.clone(),
|
||||||
|
user: user.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match transport::send_request_sync(&path, &request) {
|
||||||
Ok(LauncherResponse::DesktopStarted { user, .. }) => {
|
Ok(LauncherResponse::DesktopStarted { user, .. }) => {
|
||||||
println!(" Welcome, {user}! Starting desktop...");
|
println!(" Welcome, {user}! Starting desktop...");
|
||||||
println!();
|
println!();
|
||||||
// Exit — the launcher starts the desktop components.
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Ok(LauncherResponse::Error { message, .. }) => {
|
Ok(LauncherResponse::Error { message, .. }) => {
|
||||||
|
|
|
||||||
|
|
@ -169,10 +169,9 @@ impl Launcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default socket path for the launcher.
|
/// Default IPC path for the launcher (uses shared transport default).
|
||||||
fn default_socket_path() -> PathBuf {
|
fn default_socket_path() -> PathBuf {
|
||||||
let runtime_dir = std::env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp".to_string());
|
wayray_protocol::transport::default_ipc_path()
|
||||||
PathBuf::from(runtime_dir).join("wayray-launcher.sock")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue