use bmux_plugin_sdk::{
CORE_CLI_COMMAND_CAPABILITY, CORE_CLI_COMMAND_INTERFACE_V1,
CORE_CLI_COMMAND_RUN_PATH_OPERATION_V1, CORE_CLI_COMMAND_RUN_PLUGIN_OPERATION_V1,
CoreCliCommandRequest, CoreCliCommandResponse, LogWriteRequest, PluginCliCommandRequest,
PluginCliCommandResponse, RecordingWriteEventRequest, RecordingWriteEventResponse, Result,
ServiceKind, StorageGetRequest, StorageGetResponse, StorageSetRequest,
};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
const RECORDING_WRITE_CAPABILITY: &str = "bmux.recording.write";
const RECORDING_COMMANDS_INTERFACE: &str = "recording-commands";
const RECORDING_WRITE_CUSTOM_EVENT_OPERATION: &str = "write-custom-event";
#[derive(Serialize)]
struct RecordingWriteCustomEventWireRequest {
session_id: Option<uuid::Uuid>,
pane_id: Option<uuid::Uuid>,
source: String,
name: String,
#[serde(with = "bmux_codec::serde_bytes_vec")]
payload: Vec<u8>,
}
#[derive(Deserialize)]
enum RecordingWriteCustomEventWireError {
NoActive,
Unavailable,
Failed { reason: String },
}
impl RecordingWriteCustomEventWireError {
fn into_reason(self) -> Option<String> {
match self {
Self::NoActive | Self::Unavailable => None,
Self::Failed { reason } => Some(reason),
}
}
}
pub trait ServiceCaller {
fn call_service_raw(
&self,
capability: &str,
kind: ServiceKind,
interface_id: &str,
operation: &str,
payload: Vec<u8>,
) -> Result<Vec<u8>>;
fn call_service<Request, Response>(
&self,
capability: &str,
kind: ServiceKind,
interface_id: &str,
operation: &str,
request: &Request,
) -> Result<Response>
where
Request: Serialize,
Response: DeserializeOwned,
{
let payload = bmux_plugin_sdk::encode_service_message(request)?;
let response = self.call_service_raw(capability, kind, interface_id, operation, payload)?;
bmux_plugin_sdk::decode_service_message(&response)
}
fn execute_kernel_request(
&self,
request: bmux_ipc::Request,
) -> Result<bmux_ipc::ResponsePayload>;
}
pub trait HostRuntimeApi: ServiceCaller {
fn core_cli_command_run_path(
&self,
request: &CoreCliCommandRequest,
) -> Result<CoreCliCommandResponse> {
self.call_service(
CORE_CLI_COMMAND_CAPABILITY,
ServiceKind::Command,
CORE_CLI_COMMAND_INTERFACE_V1,
CORE_CLI_COMMAND_RUN_PATH_OPERATION_V1,
request,
)
}
fn plugin_command_run(
&self,
request: &PluginCliCommandRequest,
) -> Result<PluginCliCommandResponse> {
self.call_service(
CORE_CLI_COMMAND_CAPABILITY,
ServiceKind::Command,
CORE_CLI_COMMAND_INTERFACE_V1,
CORE_CLI_COMMAND_RUN_PLUGIN_OPERATION_V1,
request,
)
}
fn storage_get(&self, request: &StorageGetRequest) -> Result<StorageGetResponse> {
self.call_service(
"bmux.storage",
ServiceKind::Query,
"storage-query/v1",
"get",
request,
)
}
fn storage_set(&self, request: &StorageSetRequest) -> Result<()> {
self.call_service(
"bmux.storage",
ServiceKind::Command,
"storage-command/v1",
"set",
request,
)
}
fn log_write(&self, request: &LogWriteRequest) -> Result<()> {
self.call_service(
"bmux.logs.write",
ServiceKind::Command,
"logging-command/v1",
"write",
request,
)
}
fn recording_write_event(
&self,
request: &RecordingWriteEventRequest,
) -> Result<RecordingWriteEventResponse> {
let recording_request = RecordingWriteCustomEventWireRequest {
session_id: recording_attribute_uuid(request, "bmux.session_id"),
pane_id: recording_attribute_uuid(request, "bmux.pane_id"),
source: String::new(),
name: request.name.clone(),
payload: serde_json::to_vec(&request.payload).unwrap_or_default(),
};
let response: std::result::Result<(), RecordingWriteCustomEventWireError> = self
.call_service(
RECORDING_WRITE_CAPABILITY,
ServiceKind::Command,
RECORDING_COMMANDS_INTERFACE,
RECORDING_WRITE_CUSTOM_EVENT_OPERATION,
&recording_request,
)?;
match response {
Ok(()) => Ok(RecordingWriteEventResponse { accepted: true }),
Err(err) => {
let _ = err.into_reason();
Ok(RecordingWriteEventResponse { accepted: false })
}
}
}
}
impl<T> HostRuntimeApi for T where T: ServiceCaller + ?Sized {}
fn recording_attribute_uuid(request: &RecordingWriteEventRequest, key: &str) -> Option<uuid::Uuid> {
request
.attributes
.get(key)
.and_then(|value| uuid::Uuid::parse_str(value).ok())
}