Files
moli/moli-protocol-server/src/protocol_server/instance_control.rs
T
ldm0 9464659788 refactor(server): route browser shutdown through instance control
Expose protocol-independent InstanceCommand and BrowserInstanceControl with a
native serve_with_control entry. Keep shutdown coordination in the server and
CDP session validation and response flush in a dedicated adapter, bypassing
renderer work without creating another actor or shutdown state.

Parse each CDP envelope once and check live frontend-owned session routes
through a weak registry view. Match Chromium Browser.close on browser, page,
tab, and worker sessions; ignore params and reject null or foreign session IDs.
Update optional-session test requests to omit absent routes.

Add native and pending-promise lifecycle regressions and cross-engine smoke
coverage for acknowledgment ordering, natural process exit, and isolation.
2026-10-20 20:47:16 +08:00

47 lines
1.4 KiB
Rust

use super::instance_shutdown::{InstanceConnection, InstanceShutdown};
/// An operation on the entire running browser instance, independent of a
/// protocol session or renderer's command queue.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum InstanceCommand {
Shutdown,
}
/// A thread-safe control handle for one invocation of
/// [`super::ProtocolServer::serve_with_control`].
///
/// The server owns shutdown and resource cleanup. Adapters and native callers
/// only request it; cloning this handle neither creates a task nor keeps a
/// protocol session or renderer alive.
#[derive(Clone, Debug, Default)]
pub struct BrowserInstanceControl {
shutdown: InstanceShutdown,
}
impl BrowserInstanceControl {
pub fn new() -> Self {
Self::default()
}
/// Submit an idempotent lifecycle command without waiting for page work.
/// Wait for the server's serving future to finish to observe cleanup.
pub fn request(&self, command: InstanceCommand) {
match command {
InstanceCommand::Shutdown => self.shutdown.request(),
}
}
/// Observe shutdown, including a request made before this call.
pub async fn shutdown_requested(&self) {
self.shutdown.requested().await;
}
pub(super) fn connection(&self) -> Option<InstanceConnection> {
self.shutdown.connection()
}
pub(super) async fn drained(&self) {
self.shutdown.drained().await;
}
}