refactor(host): move web_static to op-web-daemon (Phase 2, first leaf)
Establishes the extraction move pattern: git mv module (+ its asset subdir) -> op-web-daemon, add the op-host-desktop -> op-web-daemon dep edge, register pub mod, repoint consumers (crate::web_static -> op_web_daemon::web_static in main.rs + web_canvas_server.rs), and promote the cross-crate items pub(crate) -> pub (resolve_bundle_dir / handle_static_request / write_static_response / ICONIFY_BRANDS_JSON / StaticReply). web_static (static file serving for the --serve-web daemon) now lives in op-web-daemon. Verified: both crates build; 13 web_static tests pass. 6 more leaves + export + doc_io remain in Phase 2.
This commit is contained in:
parent
3872c90289
commit
249614aa87
|
|
@ -63,6 +63,10 @@ role = "Editor"
|
|||
# render-backend / layout scene paths resolve through op-editor-ui.
|
||||
op-editor-ui = { path = "../op-editor-ui" }
|
||||
op-host-native = { path = "../op-host-native", version = "0.8.0", features = ["gl-host"] }
|
||||
# Phase 2: the headless daemon crate. The `--serve-web` closure migrates here
|
||||
# over Phases 2-5; op-host-desktop's serve-web dispatch + GUI residuals call into
|
||||
# it via `op_web_daemon::*`.
|
||||
op-web-daemon = { path = "../op-web-daemon" }
|
||||
# Accessibility (#67) — the platform-free `accesskit` core types
|
||||
# (`TreeUpdate` / `ActionRequest` / `ActivationHandler` …) used by the
|
||||
# desktop a11y adapter (`src/a11y.rs`). The OS-specific subclassing
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ mod theme_preset_host;
|
|||
mod update_check;
|
||||
mod web_canvas_server;
|
||||
mod web_chat_standard;
|
||||
mod web_static;
|
||||
mod window_state;
|
||||
|
||||
use op_host_native::{NativeBackend, SharedSkiaContext, SharedSkiaError, WidgetHostNative};
|
||||
|
|
@ -949,7 +948,7 @@ fn main() {
|
|||
// headless `--render-shots` rasterizer below, MCP — so they resolve
|
||||
// simple-icons instead of the unknown-glyph fallback dot. Set-once /
|
||||
// idempotent.
|
||||
op_editor_ui::set_brand_catalog(web_static::ICONIFY_BRANDS_JSON);
|
||||
op_editor_ui::set_brand_catalog(op_web_daemon::web_static::ICONIFY_BRANDS_JSON);
|
||||
// `--mcp` / `--mcp-http` swap the GUI for an MCP server mode;
|
||||
// when one of those ran, exit instead of opening a window.
|
||||
if mcp_serve::run_cli_if_requested() {
|
||||
|
|
|
|||
|
|
@ -1082,7 +1082,7 @@ pub fn run_web_canvas(path: Option<PathBuf>, port: u16, host: &str) -> Result<()
|
|||
TcpListener::bind((host, port)).map_err(|e| format!("bind {host}:{port}: {e}"))?;
|
||||
let bound = listener.local_addr().map(|a| a.port()).unwrap_or(port);
|
||||
eprintln!("openpencil-desktop --serve-web: listening on {host}:{bound}");
|
||||
match crate::web_static::resolve_bundle_dir() {
|
||||
match op_web_daemon::web_static::resolve_bundle_dir() {
|
||||
Some(dir) => eprintln!(
|
||||
"openpencil-desktop --serve-web: serving web bundle from {}",
|
||||
dir.display()
|
||||
|
|
@ -1182,11 +1182,11 @@ fn serve_one<S: Read + Write>(
|
|||
// Static serving: the host page (`/`) and the wasm-bindgen bundle
|
||||
// (`/pkg/*`). Owns only those paths — everything else falls through.
|
||||
if req.method == "GET" {
|
||||
let bundle_dir = crate::web_static::resolve_bundle_dir();
|
||||
let bundle_dir = op_web_daemon::web_static::resolve_bundle_dir();
|
||||
if let Some(reply) =
|
||||
crate::web_static::handle_static_request(&req.path, bundle_dir.as_deref())
|
||||
op_web_daemon::web_static::handle_static_request(&req.path, bundle_dir.as_deref())
|
||||
{
|
||||
return crate::web_static::write_static_response(stream, &reply).map(|()| false);
|
||||
return op_web_daemon::web_static::write_static_response(stream, &reply).map(|()| false);
|
||||
}
|
||||
}
|
||||
// SSE live-update stream: the browser shell subscribes and re-syncs whenever
|
||||
|
|
|
|||
|
|
@ -12,3 +12,6 @@
|
|||
//! `openpencil-docs/superpowers/plans/2026-06-19-op-web-daemon-extraction.md`).
|
||||
//! Both `op-host-desktop` (for its `--serve-web` mode) and a thin
|
||||
//! `op-host-web-server` binary depend on this crate.
|
||||
|
||||
// Phase 2 — host-free leaf modules.
|
||||
pub mod web_static;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ const MISSING_BUNDLE_HTML: &str = include_str!("web_static/missing_bundle.html")
|
|||
/// both (a) registered with the shared icon catalog at native GUI startup and
|
||||
/// (b) served to the web client, which deliberately omits it from the wasm
|
||||
/// bundle to keep the first-load small (see `op_editor_ui::widgets::icon_catalog`).
|
||||
pub(crate) const ICONIFY_BRANDS_JSON: &str =
|
||||
pub const ICONIFY_BRANDS_JSON: &str =
|
||||
include_str!("../../op-editor-ui/assets/iconify-catalog-brands.json");
|
||||
|
||||
/// Route the web client fetches to load the brand-logo catalog at runtime.
|
||||
|
|
@ -45,7 +45,7 @@ pub(crate) const ICONIFY_BRANDS_PATH: &str = "/assets/iconify-catalog-brands.jso
|
|||
const BUNDLE_ENTRY_JS: &str = "op_host_web.js";
|
||||
|
||||
/// A fully-formed static HTTP reply (status + MIME + body bytes).
|
||||
pub(crate) struct StaticReply {
|
||||
pub struct StaticReply {
|
||||
pub(crate) status: &'static str,
|
||||
pub(crate) content_type: &'static str,
|
||||
pub(crate) body: Vec<u8>,
|
||||
|
|
@ -80,7 +80,7 @@ pub(crate) fn bundle_dir_candidates() -> Vec<PathBuf> {
|
|||
|
||||
/// First candidate directory that actually contains the wasm-bindgen JS
|
||||
/// entry (`op_host_web.js`), or `None` when no bundle is built anywhere.
|
||||
pub(crate) fn resolve_bundle_dir() -> Option<PathBuf> {
|
||||
pub fn resolve_bundle_dir() -> Option<PathBuf> {
|
||||
bundle_dir_candidates()
|
||||
.into_iter()
|
||||
.find(|dir| dir.join(BUNDLE_ENTRY_JS).is_file())
|
||||
|
|
@ -180,7 +180,7 @@ fn safe_relative_path(file: &str) -> Option<PathBuf> {
|
|||
/// (the caller falls through to REST / SSE / JSON-RPC routing). The bundle
|
||||
/// directory is a parameter (already resolved) so the routing is testable
|
||||
/// without mutating process-global env.
|
||||
pub(crate) fn handle_static_request(path: &str, bundle_dir: Option<&Path>) -> Option<StaticReply> {
|
||||
pub fn handle_static_request(path: &str, bundle_dir: Option<&Path>) -> Option<StaticReply> {
|
||||
if path == "/" || path == "/index.html" {
|
||||
return Some(match bundle_dir {
|
||||
Some(_) => StaticReply {
|
||||
|
|
@ -277,7 +277,7 @@ fn html_escape(s: &str) -> String {
|
|||
|
||||
/// Write a static reply with its own Content-Type (binary-safe body) — the
|
||||
/// JSON-only `write_mcp_http_response` cannot carry `application/wasm`.
|
||||
pub(crate) fn write_static_response<S: std::io::Write>(
|
||||
pub fn write_static_response<S: std::io::Write>(
|
||||
stream: &mut S,
|
||||
reply: &StaticReply,
|
||||
) -> Result<(), String> {
|
||||
Loading…
Reference in a new issue