feat(host): add headless op-host-web-server binary (Phase 6, Task 6.1)
A thin binary linking ONLY op-web-daemon — no winit/glutin/muda/accesskit-adapters/skia-GL.
Routes --serve-web/--mcp/--mcp-http argv to op_web_daemon::web_canvas_server::run_web_canvas +
op_web_daemon::mcp_serve::{run,run_http} (mirrors the desktop dispatcher, headless-only — no GUI
fallback). Added to root default-members. VERIFIED via cargo tree: 0 winit/glutin/casement/muda/
accesskit-adapters + skia-safe without gl (raster) — the web-server image now excludes all
desktop/GL code, answering the original question. (Lock also drops the actor-removed op-app crate.)
This commit is contained in:
parent
c6743453b6
commit
f198cdf76a
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -3088,15 +3088,6 @@ dependencies = [
|
|||
"include_dir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "op-app"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"op-editor-ui",
|
||||
"op-host-native",
|
||||
"op-host-web",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "op-cli"
|
||||
version = "0.8.0"
|
||||
|
|
@ -3307,6 +3298,13 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "op-host-web-server"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"op-web-daemon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "op-i18n"
|
||||
version = "0.8.0"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ exclude = [
|
|||
# is always `cargo build -p op-host-web --target wasm32-unknown-unknown`. CI and
|
||||
# the `package.json` cargo:* scripts are unaffected: they all pass `--workspace`
|
||||
# explicitly, which overrides `default-members`.
|
||||
default-members = ["crates/op-host-desktop", "crates/op-cli"]
|
||||
default-members = ["crates/op-host-desktop", "crates/op-cli", "crates/op-host-web-server"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.0"
|
||||
|
|
|
|||
14
crates/op-host-web-server/Cargo.toml
Normal file
14
crates/op-host-web-server/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "op-host-web-server"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
description = "OpenPencil headless web/MCP server binary — links op-web-daemon only, no winit/skia-GL"
|
||||
|
||||
[[bin]]
|
||||
name = "op-host-web-server"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
op-web-daemon = { path = "../op-web-daemon" }
|
||||
78
crates/op-host-web-server/src/main.rs
Normal file
78
crates/op-host-web-server/src/main.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
//! Headless OpenPencil web / MCP server binary.
|
||||
//!
|
||||
//! Links only `op-web-daemon` (the extracted headless daemon) — no
|
||||
//! winit / glutin / muda / accesskit adapters / skia-GL — so the
|
||||
//! container / server image stays GUI-free. It mirrors the `--serve-web`
|
||||
//! / `--mcp` / `--mcp-http` argv arms the desktop binary's
|
||||
//! `run_cli_if_requested` dispatcher routes, but here that IS the whole
|
||||
//! program: there is no GUI fallback, so an unknown / missing mode is a
|
||||
//! usage error rather than "open the editor window".
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::process::exit;
|
||||
|
||||
fn main() {
|
||||
let mut args = std::env::args().skip(1);
|
||||
let Some(first) = args.next() else {
|
||||
eprintln!(
|
||||
"op-host-web-server: missing mode. Usage:\n \
|
||||
--serve-web <port> [doc] [--host <addr>] headless web-canvas daemon\n \
|
||||
--mcp <path> JSON-RPC stdio MCP server\n \
|
||||
--mcp-http <port> <path> Streamable-HTTP MCP server"
|
||||
);
|
||||
exit(2);
|
||||
};
|
||||
match first.as_str() {
|
||||
"--serve-web" => {
|
||||
// `--serve-web <port> [doc] [--host <addr>]`: doc optional
|
||||
// (empty document otherwise); `--host` opts in to a
|
||||
// non-loopback bind.
|
||||
let (port, path, host) = op_web_daemon::web_canvas_server::parse_serve_web_args(args)
|
||||
.unwrap_or_else(|e| {
|
||||
eprintln!("op-host-web-server --serve-web: {e}");
|
||||
exit(2);
|
||||
});
|
||||
if let Err(e) = op_web_daemon::web_canvas_server::run_web_canvas(path, port, &host) {
|
||||
eprintln!("op-host-web-server --serve-web: {e}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
"--mcp" => {
|
||||
let Some(path) = args.next() else {
|
||||
eprintln!("op-host-web-server --mcp: missing <path> arg");
|
||||
exit(2);
|
||||
};
|
||||
if let Err(e) = op_web_daemon::mcp_serve::run(PathBuf::from(path)) {
|
||||
eprintln!("op-host-web-server --mcp: {e}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
"--mcp-http" => {
|
||||
let Some(port_arg) = args.next() else {
|
||||
eprintln!("op-host-web-server --mcp-http: missing <port> arg");
|
||||
exit(2);
|
||||
};
|
||||
let Ok(port) = port_arg.parse::<u16>() else {
|
||||
eprintln!(
|
||||
"op-host-web-server --mcp-http: <port> must be a u16, got {port_arg:?}"
|
||||
);
|
||||
exit(2);
|
||||
};
|
||||
let Some(path) = args.next() else {
|
||||
eprintln!("op-host-web-server --mcp-http: missing <path> arg");
|
||||
exit(2);
|
||||
};
|
||||
if let Err(e) = op_web_daemon::mcp_serve::run_http(PathBuf::from(path), port) {
|
||||
eprintln!("op-host-web-server --mcp-http: {e}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
other => {
|
||||
eprintln!(
|
||||
"op-host-web-server: unknown mode {other:?} \
|
||||
(expected --serve-web / --mcp / --mcp-http)"
|
||||
);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue