use serde_json::Value;
use std::{future::Future, time::Duration};
#[derive(Clone)]
pub struct Error {
pub code: String,
pub message: String,
pub host_message: Option<Box<str>>,
pub details: Option<Box<Value>>,
pub operation_id: Option<Box<str>>,
pub rpc_code: Option<i64>,
pub exit_code: Option<Box<i64>>,
pub outcome_unknown: bool,
}
impl Error {
pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
Self {
code: code.into(),
message: message.into(),
host_message: None,
details: None,
operation_id: None,
rpc_code: None,
exit_code: None,
outcome_unknown: false,
}
}
pub fn decode(cause: serde_json::Error) -> Self {
let mut error = Self::new(
"HOST_PROTOCOL_ERROR",
"Host result does not match its declared response type",
);
error.details = Some(Box::new(
serde_json::json!({"decodeError":cause.to_string()}),
));
error
}
}
impl std::fmt::Display for Error {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(formatter, "{}: {}", self.code, self.message)
}
}
impl std::error::Error for Error {}
impl std::fmt::Debug for Error {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("Error")
.field("code", &self.code)
.field("operation_id", &self.operation_id)
.field("rpc_code", &self.rpc_code)
.field("exit_code", &self.exit_code)
.field("outcome_unknown", &self.outcome_unknown)
.finish_non_exhaustive()
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Default)]
pub struct InvokeOptions {
pub timeout: Option<Duration>,
pub expected_revision: Option<String>,
pub change_mode: Option<String>,
pub dry_run: Option<bool>,
pub stdin_bytes: Option<Vec<u8>>,
}
impl std::fmt::Debug for InvokeOptions {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("InvokeOptions")
.field("timeout", &self.timeout)
.field("has_stdin", &self.stdin_bytes.is_some())
.finish_non_exhaustive()
}
}
pub trait Invoker: Sync {
fn handle_decode_error(&self, error: Error) -> Error {
error
}
fn invoke(
&self,
operation_id: &str,
params: Value,
options: InvokeOptions,
) -> impl Future<Output = Result<Value>> + Send;
}