use std::path::Path;
use std::sync::Arc;
use micromux::{CancellationToken, Handles};
use micromux_control::{
CanonicalConfigPath, ControlServer, SessionIdentity, bind, endpoint_for, runtime_dir,
};
fn session_name(configured: Option<String>, working_dir: &Path) -> String {
configured.unwrap_or_else(|| {
working_dir
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| "micromux".to_string())
})
}
pub fn spawn(
handles: &Handles,
config_path: &CanonicalConfigPath,
working_dir: &Path,
name: Option<String>,
shutdown: CancellationToken,
) -> bool {
if !micromux_control::transport_supported() {
tracing::warn!("control plane disabled: unsupported platform");
return false;
}
let Some(runtime_dir) = runtime_dir() else {
tracing::warn!("control plane disabled: no runtime directory could be resolved");
return false;
};
let endpoint = endpoint_for(&runtime_dir, config_path);
let guard = match bind(&endpoint) {
Ok(Some(guard)) => guard,
Ok(None) => {
tracing::warn!(
"control plane disabled: another micromux already owns this project's endpoint"
);
return false;
}
Err(err) => {
tracing::warn!(?err, "control plane disabled");
return false;
}
};
let identity = SessionIdentity::new(session_name(name, working_dir), working_dir, config_path);
let server = Arc::new(ControlServer::new(
handles.reader.clone(),
handles.service_control(),
identity,
handles.dynamic_services.clone(),
));
tracing::info!(endpoint = ?endpoint, "control plane listening");
tokio::spawn(async move {
if let Err(err) = server.serve(guard, shutdown).await {
tracing::warn!(?err, "control server exited with an error");
}
});
true
}
pub async fn resolve_config_path(
explicit: Option<&Path>,
working_dir: &Path,
) -> Result<CanonicalConfigPath, crate::Error> {
let config_path = match explicit {
Some(path) => Some(path.to_path_buf()),
None => micromux::find_config_file(working_dir).await?,
};
let config_path =
config_path.ok_or_else(|| crate::Error::Message("missing config file".to_string()))?;
Ok(CanonicalConfigPath::new(config_path)?)
}