harmos_sidecar/kit/
instance.rs1use std::future::Future;
22use std::marker::PhantomData;
23
24use super::{CallError, Supervisor};
28use harmos_domain::operations::instance::{Id, Status};
29use harmos_domain::operations::lifecycle::InstanceState;
30use harmos_domain::{Message, StreamSpec};
31use harmos_sdk::operations::{CallContext, ContextError, ContextValue, Host, Instance, OperationDeclaration, Response, WireChildAction};
32
33#[must_use = "dropping an unsettled operation instance requests its cancellation"]
42pub struct OperationInstance<O> {
43 host: Supervisor,
44 id: Id,
45 released: bool,
46 _operation: PhantomData<fn() -> O>,
47}
48
49impl<O: OperationDeclaration> OperationInstance<O> {
56 pub fn id(&self) -> Id {
57 self.id
58 }
59
60 pub async fn status(&self) -> Result<Status, CallError> {
61 let bytes = self.host.child_control(self.id, WireChildAction::Status).await?;
62 decode_status(&bytes)
63 }
64
65 pub async fn cancel(&self) -> Result<(), CallError> {
66 self.host.child_control(self.id, WireChildAction::Cancel).await?;
67 Ok(())
68 }
69
70 pub async fn join(mut self) -> Result<Response<O::Response>, CallError> {
71 let joined = self.host.child_control(self.id, WireChildAction::Join).await;
72 self.released = true;
73 let bytes = joined?;
74 decode_response::<O>(&bytes)
75 }
76
77 pub async fn cancel_and_join(self) -> Result<Response<O::Response>, CallError> {
78 self.cancel().await?;
79 self.join().await
80 }
81
82 pub fn detach(mut self) -> Id {
85 self.released = true;
86 self.host.child_control_detached(self.id, WireChildAction::Detach);
87 self.id
88 }
89}
90
91impl<O> Drop for OperationInstance<O> {
92 fn drop(&mut self) {
93 if !self.released {
94 self.host.child_control_detached(self.id, WireChildAction::Release);
95 }
96 }
97}
98
99impl<O: OperationDeclaration> Instance<O> for OperationInstance<O> {
100 type Error = CallError;
101
102 fn id(&self) -> Id {
103 self.id
104 }
105
106 fn status(&self) -> impl Future<Output = Result<Status, CallError>> + Send {
107 OperationInstance::status(self)
108 }
109
110 fn cancel(&self) -> impl Future<Output = Result<(), CallError>> + Send {
111 OperationInstance::cancel(self)
112 }
113
114 fn join(self) -> impl Future<Output = Result<Response<O::Response>, CallError>> + Send {
115 OperationInstance::join(self)
116 }
117
118 fn detach(self) -> Id {
119 OperationInstance::detach(self)
120 }
121}
122
123impl Host for Supervisor {
124 type Error = CallError;
125 type Instance<O: OperationDeclaration> = OperationInstance<O>;
126
127 fn context(&self) -> &CallContext {
128 Supervisor::context(self)
129 }
130
131 fn with_value<T: ContextValue>(&self, value: T) -> Result<Self, ContextError> {
132 Supervisor::with_value(self, value)
133 }
134
135 async fn submit<O: OperationDeclaration>(&self, request: O) -> Result<OperationInstance<O>, CallError> {
136 let bytes = self.child_call::<O>(&request, true).await?;
137 let id = u64::decode(bytes.as_slice()).map_err(|error| CallError::Malformed { method: O::ID, message: error.to_string() })?;
138 Ok(OperationInstance { host: self.clone(), id: Id::new(id), released: false, _operation: PhantomData })
139 }
140
141 async fn submit_with_resources<O: OperationDeclaration<Response = ()>, R: Send + Sync + 'static>(
143 &self, _: O, _: std::sync::Arc<R>,
144 ) -> Result<OperationInstance<O>, CallError> {
145 Err(CallError::LocalResources { method: O::ID })
146 }
147
148 async fn call<O: OperationDeclaration>(&self, request: O) -> Result<Response<O::Response>, CallError> {
149 let bytes = self.child_call::<O>(&request, false).await?;
150 decode_response::<O>(&bytes)
151 }
152
153 async fn publish_on<S: StreamSpec>(&self, row: &S::Row) -> Result<(), CallError>
155 where
156 S::Row: Message,
157 {
158 self.publication::<S>(std::slice::from_ref(row), &[self.now()], None).await.map_err(|error| match error {
159 super::PublishError::Publication(error) => CallError::Publication(error),
160 super::PublishError::Call(error) => error,
161 })
162 }
163}
164
165fn decode_response<O: OperationDeclaration>(bytes: &[u8]) -> Result<Response<O::Response>, CallError> {
170 let response = O::Response::decode(bytes).map_err(|error| CallError::Malformed { method: O::ID, message: error.to_string() })?;
171 Ok(Response::new(response))
172}
173
174fn decode_status(bytes: &[u8]) -> Result<Status, CallError> {
175 let malformed = |message: String| CallError::Malformed { method: harmos_sdk::operations::CHILD_METHOD, message };
176 let state = InstanceState::decode(bytes).map_err(|error| malformed(error.to_string()))?;
177 Status::try_from(&state).map_err(|error| malformed(error.to_string()))
178}
179
180