#![cfg_attr(feature = "fail-on-warnings", deny(warnings))]
#![warn(clippy::all, clippy::pedantic)]
pub mod execution;
#[cfg(unix)]
mod host;
use bmux_application_resurrection_plugin_api::{resurrection_host_v1, resurrection_launch_v1};
use bmux_plugin_sdk::{
NativeLifecycleContext, NativeServiceContext, PluginCommandError, RustPlugin, ServiceResponse,
};
#[derive(Default)]
pub struct ApplicationResurrectionPlugin {
#[cfg(unix)]
host: Option<host::Host>,
}
impl RustPlugin for ApplicationResurrectionPlugin {
type Contract = bmux_application_resurrection_plugin_api::Contract;
fn activate(&mut self, context: NativeLifecycleContext) -> Result<i32, PluginCommandError> {
#[cfg(unix)]
{
self.host = Some(
host::Host::new(
std::path::PathBuf::from(&context.connection.state_dir)
.join("application-resurrection"),
)
.map_err(PluginCommandError::failed)?,
);
}
Ok(bmux_plugin_sdk::EXIT_OK)
}
fn deactivate(&mut self, _context: NativeLifecycleContext) -> Result<i32, PluginCommandError> {
#[cfg(unix)]
{
self.host = None;
}
Ok(bmux_plugin_sdk::EXIT_OK)
}
fn invoke_service(&self, context: NativeServiceContext) -> ServiceResponse {
#[cfg(unix)]
{
let host = self.host.as_ref();
let unavailable = || resurrection_launch_v1::HostError::Failed {
message: "host unavailable".into(),
};
bmux_plugin_sdk::route_service!(context, {
resurrection_host_v1::client::StatusEndpoint => |_request, _context| {
Ok(resurrection_host_v1::HostStatus { protocol: "application-resurrection/1".into(), available: host.is_some(), reason: None })
},
resurrection_launch_v1::client::PrepareEndpoint => |request, _context| {
Ok(host.ok_or_else(unavailable).and_then(|host| host.prepare(&request.key, request.restored, request.shell, request.replay).map_err(host_error)))
},
bmux_application_resurrection_plugin_api::resurrection_launch_v2::client::PrepareEndpoint => |request, _context| {
Ok(host.ok_or_else(unavailable).and_then(|host| host.prepare_checked(&request.key, request.restored, request.shell, request.replay, host::IdentityCheck::Expected(request.expected_invocation.as_deref())).map_err(host_error)))
},
bmux_application_resurrection_plugin_api::resurrection_launch_v2::client::BoundaryEndpoint => |request, _context| {
Ok(host.ok_or_else(unavailable).and_then(|host| host.boundary_identity(&request.key, &request.endpoint, request.prompt).map_err(host_error)))
},
resurrection_launch_v1::client::BindEndpoint => |request, _context| {
Ok(host.ok_or_else(unavailable).and_then(|host| host.bind(&request.key, &request.endpoint, request.pid).map_err(host_error)))
},
resurrection_launch_v1::client::BoundaryEndpoint => |request, _context| {
Ok(host.ok_or_else(unavailable).and_then(|host| host.boundary(&request.key, &request.endpoint, request.prompt).map_err(host_error)))
},
resurrection_launch_v1::client::CloseEndpoint => |request, _context| {
Ok(host.ok_or_else(unavailable).and_then(|host| host.close(&request.key, &request.endpoint).map_err(host_error)))
},
})
}
#[cfg(not(unix))]
{
let _ = context;
ServiceResponse::error("unsupported", "local transport unavailable")
}
}
}
fn host_error(message: String) -> resurrection_launch_v1::HostError {
resurrection_launch_v1::HostError::Failed { message }
}
bmux_plugin_sdk::export_plugin!(
ApplicationResurrectionPlugin,
include_str!("../plugin.toml")
);