1use serde_json::Value;
4use std::{future::Future, time::Duration};
5
6#[derive(Clone)]
8pub struct Error {
9 pub code: String,
10 pub message: String,
11 pub host_message: Option<Box<str>>,
14 pub details: Option<Box<Value>>,
15 pub operation_id: Option<String>,
16 pub rpc_code: Option<i64>,
17 pub outcome_unknown: bool,
19}
20
21impl Error {
22 pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
23 Self {
24 code: code.into(),
25 message: message.into(),
26 host_message: None,
27 details: None,
28 operation_id: None,
29 rpc_code: None,
30 outcome_unknown: false,
31 }
32 }
33
34 pub fn decode(cause: serde_json::Error) -> Self {
35 let mut error = Self::new(
36 "HOST_PROTOCOL_ERROR",
37 "Host result does not match its declared response type",
38 );
39 error.details = Some(Box::new(
40 serde_json::json!({"decodeError":cause.to_string()}),
41 ));
42 error
43 }
44}
45
46impl std::fmt::Display for Error {
47 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 write!(formatter, "{}: {}", self.code, self.message)
49 }
50}
51impl std::error::Error for Error {}
52
53impl std::fmt::Debug for Error {
54 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 formatter
56 .debug_struct("Error")
57 .field("code", &self.code)
58 .field("operation_id", &self.operation_id)
59 .field("rpc_code", &self.rpc_code)
60 .field("outcome_unknown", &self.outcome_unknown)
61 .finish_non_exhaustive()
62 }
63}
64
65pub type Result<T> = std::result::Result<T, Error>;
66
67#[derive(Clone, Default)]
70pub struct InvokeOptions {
71 pub timeout: Option<Duration>,
72 pub expected_revision: Option<String>,
73 pub change_mode: Option<String>,
74 pub dry_run: Option<bool>,
75 pub stdin_bytes: Option<Vec<u8>>,
76}
77
78impl std::fmt::Debug for InvokeOptions {
79 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 formatter
81 .debug_struct("InvokeOptions")
82 .field("timeout", &self.timeout)
83 .field("has_stdin", &self.stdin_bytes.is_some())
84 .finish_non_exhaustive()
85 }
86}
87
88pub trait Invoker: Sync {
91 fn invoke(
92 &self,
93 operation_id: &str,
94 params: Value,
95 options: InvokeOptions,
96 ) -> impl Future<Output = Result<Value>> + Send;
97}