1use super::error::ConductorApiError;
4use super::error::ConductorApiResult;
5use crate::conductor::error::ConductorResult;
6use crate::conductor::ConductorHandle;
7use crate::core::ribosome::guest_callback::post_commit::PostCommitArgs;
8use crate::core::ribosome::Ribosome;
9use crate::core::workflow::ZomeCallResult;
10use async_trait::async_trait;
11use holochain_keystore::MetaLairClient;
12use holochain_p2p::HolochainP2pResult;
13use holochain_state::conductor::WitnessNonceResult;
14use holochain_state::host_fn_workspace::SourceChainWorkspace;
15use holochain_types::prelude::*;
16use holochain_zome_types::block::Block;
17use holochain_zome_types::block::BlockTargetId;
18use std::sync::Arc;
19use tokio::sync::mpsc::error::SendError;
20use tokio::sync::mpsc::OwnedPermit;
21
22#[derive(Clone)]
25pub struct CellConductorApi {
26 conductor_handle: ConductorHandle,
27 cell_id: CellId,
28}
29
30pub type CellConductorHandle = Arc<dyn CellConductorApiT + Send + 'static>;
32
33pub type CellConductorReadHandle = Arc<dyn CellConductorReadHandleT + Send + 'static>;
36
37impl CellConductorApi {
38 pub fn new(conductor_handle: ConductorHandle, cell_id: CellId) -> Self {
41 Self {
42 conductor_handle,
43 cell_id,
44 }
45 }
46}
47
48#[async_trait]
49impl CellConductorApiT for CellConductorApi {
50 fn cell_id(&self) -> &CellId {
51 &self.cell_id
52 }
53
54 fn keystore(&self) -> &MetaLairClient {
55 self.conductor_handle.keystore()
56 }
57
58 fn get_dna_def(&self, cell_id: &CellId) -> Option<DnaDef> {
59 self.conductor_handle
60 .get_dna_def(cell_id)
61 .map(|d| d.content)
62 }
63
64 fn get_this_ribosome(&self) -> ConductorApiResult<Ribosome> {
65 Ok(self.conductor_handle.get_ribosome(&self.cell_id)?)
66 }
67
68 #[cfg_attr(feature = "instrument", tracing::instrument(skip(self)))]
69 fn get_zome(&self, cell_id: &CellId, zome_name: &ZomeName) -> ConductorApiResult<Zome> {
70 let dna = self
71 .get_dna_def(cell_id)
72 .ok_or_else(|| ConductorApiError::CellMissing(cell_id.clone()))?;
73 Ok(dna.get_zome(zome_name)?)
74 }
75
76 fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef> {
77 self.conductor_handle.get_entry_def(key)
78 }
79
80 fn into_call_zome_handle(self) -> CellConductorReadHandle {
81 Arc::new(self)
82 }
83
84 async fn post_commit_permit(&self) -> Result<OwnedPermit<PostCommitArgs>, SendError<()>> {
85 self.conductor_handle.post_commit_permit().await
86 }
87}
88
89#[async_trait]
91#[cfg_attr(feature = "test_utils", mockall::automock)]
92pub trait CellConductorApiT: Send + Sync {
93 fn cell_id(&self) -> &CellId;
95
96 fn keystore(&self) -> &MetaLairClient;
98
99 fn get_dna_def(&self, cell_id: &CellId) -> Option<DnaDef>;
101
102 fn get_this_ribosome(&self) -> ConductorApiResult<Ribosome>;
104
105 fn get_zome(&self, cell_id: &CellId, zome_name: &ZomeName) -> ConductorApiResult<Zome>;
107
108 fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef>;
110
111 fn into_call_zome_handle(self) -> CellConductorReadHandle;
113
114 async fn post_commit_permit(&self) -> Result<OwnedPermit<PostCommitArgs>, SendError<()>>;
116}
117
118#[async_trait]
121#[cfg_attr(feature = "test_utils", mockall::automock)]
122pub trait CellConductorReadHandleT: Send + Sync {
123 fn cell_id(&self) -> &CellId;
125
126 async fn call_zome(&self, params: ZomeCallParams) -> ConductorApiResult<ZomeCallResult>;
128
129 async fn call_zome_with_workspace(
131 &self,
132 params: ZomeCallParams,
133 workspace_lock: SourceChainWorkspace,
134 ) -> ConductorApiResult<ZomeCallResult>;
135
136 fn get_zome(&self, cell_id: &CellId, zome_name: &ZomeName) -> ConductorApiResult<Zome>;
138
139 fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef>;
141
142 async fn witness_nonce_from_calling_agent(
144 &self,
145 agent: AgentPubKey,
146 nonce: Nonce256Bits,
147 expires: Timestamp,
148 ) -> ConductorApiResult<WitnessNonceResult>;
149
150 async fn find_cell_with_role_alongside_cell(
153 &self,
154 cell_id: &CellId,
155 role_name: &RoleName,
156 ) -> ConductorResult<Option<CellId>>;
157
158 async fn block(&self, input: Block) -> HolochainP2pResult<()>;
160
161 async fn is_blocked(&self, input: BlockTargetId, timestamp: Timestamp)
163 -> ConductorResult<bool>;
164
165 async fn find_app_containing_cell(
167 &self,
168 cell_id: &CellId,
169 ) -> ConductorResult<Option<InstalledApp>>;
170
171 async fn get_init_properties(&self) -> ConductorResult<Option<InitProperties>>;
173
174 async fn create_clone_cell(
176 &self,
177 installed_app_id: &InstalledAppId,
178 payload: CreateCloneCellPayload,
179 ) -> ConductorResult<ClonedCell>;
180
181 async fn disable_clone_cell(
183 &self,
184 installed_app_id: &InstalledAppId,
185 payload: DisableCloneCellPayload,
186 ) -> ConductorResult<()>;
187
188 async fn enable_clone_cell(
190 &self,
191 installed_app_id: &InstalledAppId,
192 payload: EnableCloneCellPayload,
193 ) -> ConductorResult<ClonedCell>;
194
195 async fn delete_clone_cell(&self, payload: DeleteCloneCellPayload) -> ConductorResult<()>;
197
198 #[cfg(feature = "unstable-countersigning")]
200 async fn accept_countersigning_session(
201 &self,
202 cell_id: CellId,
203 request: PreflightRequest,
204 ) -> ConductorResult<PreflightRequestAcceptance>;
205}
206
207#[async_trait]
208impl CellConductorReadHandleT for CellConductorApi {
209 fn cell_id(&self) -> &CellId {
210 &self.cell_id
211 }
212
213 async fn call_zome(&self, params: ZomeCallParams) -> ConductorApiResult<ZomeCallResult> {
214 self.conductor_handle.call_zome(params).await
215 }
216
217 async fn call_zome_with_workspace(
218 &self,
219 params: ZomeCallParams,
220 workspace_lock: SourceChainWorkspace,
221 ) -> ConductorApiResult<ZomeCallResult> {
222 if self.cell_id == params.cell_id {
223 self.conductor_handle
224 .call_zome_with_workspace(params, workspace_lock)
225 .await
226 } else {
227 self.conductor_handle.call_zome(params).await
228 }
229 }
230
231 fn get_zome(&self, cell_id: &CellId, zome_name: &ZomeName) -> ConductorApiResult<Zome> {
232 CellConductorApiT::get_zome(self, cell_id, zome_name)
233 }
234
235 fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef> {
236 CellConductorApiT::get_entry_def(self, key)
237 }
238
239 async fn witness_nonce_from_calling_agent(
240 &self,
241 agent: AgentPubKey,
242 nonce: Nonce256Bits,
243 expires: Timestamp,
244 ) -> ConductorApiResult<WitnessNonceResult> {
245 Ok(self
246 .conductor_handle
247 .witness_nonce_from_calling_agent(agent, nonce, expires)
248 .await?)
249 }
250
251 async fn find_cell_with_role_alongside_cell(
252 &self,
253 cell_id: &CellId,
254 role_name: &RoleName,
255 ) -> ConductorResult<Option<CellId>> {
256 self.conductor_handle
257 .find_cell_with_role_alongside_cell(cell_id, role_name)
258 .await
259 }
260
261 async fn block(&self, input: Block) -> HolochainP2pResult<()> {
262 self.conductor_handle.holochain_p2p().block(input).await
263 }
264
265 async fn is_blocked(
266 &self,
267 input: BlockTargetId,
268 timestamp: Timestamp,
269 ) -> ConductorResult<bool> {
270 self.conductor_handle.is_blocked(input, timestamp).await
271 }
272
273 async fn find_app_containing_cell(
274 &self,
275 cell_id: &CellId,
276 ) -> ConductorResult<Option<InstalledApp>> {
277 self.conductor_handle
278 .find_app_containing_cell(cell_id)
279 .await
280 }
281
282 async fn get_init_properties(&self) -> ConductorResult<Option<InitProperties>> {
283 self.conductor_handle
284 .get_init_properties_for_cell(&self.cell_id)
285 .await
286 }
287
288 async fn create_clone_cell(
289 &self,
290 installed_app_id: &InstalledAppId,
291 payload: CreateCloneCellPayload,
292 ) -> ConductorResult<ClonedCell> {
293 self.conductor_handle
294 .clone()
295 .create_clone_cell(installed_app_id, payload)
296 .await
297 }
298
299 async fn disable_clone_cell(
300 &self,
301 installed_app_id: &InstalledAppId,
302 payload: DisableCloneCellPayload,
303 ) -> ConductorResult<()> {
304 self.conductor_handle
305 .clone()
306 .disable_clone_cell(installed_app_id, &payload)
307 .await
308 }
309
310 async fn enable_clone_cell(
311 &self,
312 installed_app_id: &InstalledAppId,
313 payload: EnableCloneCellPayload,
314 ) -> ConductorResult<ClonedCell> {
315 self.conductor_handle
316 .clone()
317 .enable_clone_cell(installed_app_id, &payload)
318 .await
319 }
320
321 async fn delete_clone_cell(&self, payload: DeleteCloneCellPayload) -> ConductorResult<()> {
322 self.conductor_handle
323 .clone()
324 .delete_clone_cell(&payload)
325 .await
326 }
327
328 #[cfg(feature = "unstable-countersigning")]
329 async fn accept_countersigning_session(
330 &self,
331 cell_id: CellId,
332 request: PreflightRequest,
333 ) -> ConductorResult<PreflightRequestAcceptance> {
334 self.conductor_handle
335 .accept_countersigning_session(cell_id, request)
336 .await
337 }
338}