use std::path::Path;
#[cfg(target_os = "linux")]
use std::path::PathBuf;
use tokio::process::Child;
use tokio::task::JoinHandle;
use tracing::warn;
#[derive(Debug)]
pub struct ProxyHandle {
pub port: u16,
inner: Inner,
#[cfg(target_os = "linux")]
uds_bridge: Option<UdsBridge>,
}
#[cfg(target_os = "linux")]
#[derive(Debug)]
struct UdsBridge {
path: PathBuf,
task: JoinHandle<()>,
}
#[derive(Debug)]
enum Inner {
External(Option<Child>),
BuiltIn(Option<JoinHandle<()>>),
}
impl ProxyHandle {
pub(crate) fn from_child(port: u16, child: Child) -> Self {
Self {
port,
inner: Inner::External(Some(child)),
#[cfg(target_os = "linux")]
uds_bridge: None,
}
}
pub(crate) fn from_task(port: u16, task: JoinHandle<()>) -> Self {
Self {
port,
inner: Inner::BuiltIn(Some(task)),
#[cfg(target_os = "linux")]
uds_bridge: None,
}
}
#[cfg(target_os = "linux")]
pub(crate) fn with_uds_bridge(mut self, path: PathBuf, task: JoinHandle<()>) -> Self {
self.uds_bridge = Some(UdsBridge { path, task });
self
}
#[cfg(target_os = "linux")]
pub fn uds_path(&self) -> Option<&Path> {
self.uds_bridge.as_ref().map(|b| b.path.as_path())
}
pub fn ca_bundle(&self) -> Option<&Path> {
match &self.inner {
Inner::External(_) | Inner::BuiltIn(_) => None,
}
}
pub fn shutdown(&mut self) {
match &mut self.inner {
Inner::External(slot) => {
if let Some(mut child) = slot.take() {
if let Err(e) = child.start_kill() {
warn!("external proxy SIGKILL failed: {e}");
}
}
}
Inner::BuiltIn(slot) => {
if let Some(task) = slot.take() {
task.abort();
}
}
}
#[cfg(target_os = "linux")]
if let Some(bridge) = self.uds_bridge.take() {
bridge.task.abort();
crate::bwrap_proxy::cleanup_uds_path(&bridge.path);
}
}
}
impl Drop for ProxyHandle {
fn drop(&mut self) {
self.shutdown();
}
}