portal_sdk/
lib.rs

1//! Other Resources
2//!
3//! - Source code - [github.com/holochain/portal-dna](https://github.com/holochain/portal-dna)
4//! - Cargo package - [crates.io/crates/hc_portal_sdk](https://crates.io/crates/hc_portal_sdk)
5//!
6
7pub use hdk_extensions::hdi;
8pub use hdk_extensions::holo_hash;
9pub use hdk_extensions::hdk;
10pub use hdk_extensions::hdi_extensions;
11pub use hdk_extensions;
12pub use rmpv;
13pub use hc_crud;
14pub use portal_types;
15
16use hdi_extensions::{
17    guest_error,
18};
19use hdk::prelude::*;
20use holo_hash::DnaHash;
21
22
23
24//
25// General-use Types
26//
27/// A type for de/serializing any data
28pub type Payload = rmpv::Value;
29
30
31
32//
33// Input defintions
34//
35/// Input required for a remote call
36pub type RemoteCallInput = RemoteCallDetails<String, String, Payload>;
37
38/// Input required for a remote call to a specific host
39#[derive(Debug, Deserialize, Serialize, Clone)]
40pub struct CustomRemoteCallInput {
41    pub host: AgentPubKey,
42    pub call: RemoteCallInput,
43}
44
45
46/// Properties required for selecting a viable host
47#[derive(Debug, Deserialize, Serialize, Clone)]
48pub struct DnaZomeFunction {
49    pub dna: DnaHash,
50    pub zome: ZomeName,
51    pub function: FunctionName,
52}
53
54
55// Input Structs
56/// Fields required for making a zome call
57#[derive(Debug, Serialize, Deserialize, Clone)]
58pub struct RemoteCallDetails<Z,F,I>
59where
60    Z: Into<ZomeName>,
61    F: Into<FunctionName>,
62    I: Serialize + core::fmt::Debug,
63{
64    pub dna: DnaHash,
65    pub zome: Z,
66    pub function: F,
67    pub payload: I,
68}
69
70
71
72//
73// Path creation helper
74//
75/// Path creation helper
76pub fn path<T>( base: &str, segments: T ) -> (Path, EntryHash)
77where
78    T: IntoIterator,
79    T::Item: std::fmt::Display,
80{
81    let mut components : Vec<Component> = vec![];
82
83    for seg in base.split(".") {
84        let component = Component::from( format!("{}", seg ).as_bytes().to_vec() );
85        components.push( component );
86    }
87
88    for seg in segments {
89        let component = Component::from( format!("{}", seg ).as_bytes().to_vec() );
90        components.push( component );
91    }
92
93    let path = Path::from( components );
94    let hash = path.path_entry_hash().unwrap();
95
96    ( path, hash )
97}
98
99
100
101//
102// ZomeCallResponse handler
103//
104/// Translate [`ZomeCallResponse`] into a [`Result`]
105pub fn zome_call_response_as_result(response: ZomeCallResponse) -> ExternResult<ExternIO> {
106    Ok( match response {
107        ZomeCallResponse::Ok(bytes)
108            => Ok(bytes),
109        ZomeCallResponse::Unauthorized(zome_call_auth, cell_id, zome, func, agent)
110            => Err(guest_error!(format!("UnauthorizedError( {}, {}, {}, {}, {} )", zome_call_auth, cell_id, zome, func, agent ))),
111        ZomeCallResponse::NetworkError(message)
112            => Err(guest_error!(format!("NetworkError( {} )", message ))),
113        ZomeCallResponse::CountersigningSession(message)
114            => Err(guest_error!(format!("CountersigningSessionError( {} )", message ))),
115    }? )
116}
117
118
119
120/// Call a local cell zome function
121#[macro_export]
122macro_rules! call_local_cell {
123    ( $role:literal, $zome:literal, $fn:literal, $($input:tt)+ ) => {
124        {
125            use $crate::hdk::prelude::*;
126            use $crate::hdi_extensions::guest_error;
127
128            call(
129                CallTargetCell::OtherRole( $role.into() ),
130                $zome,
131                $fn.into(),
132                None,
133                $($input)+,
134            ).and_then( |call_response| match call_response {
135                ZomeCallResponse::Ok(extern_io) => Ok(extern_io),
136                ZomeCallResponse::NetworkError(msg) => Err(guest_error!(format!("NetworkError: {}", msg))),
137                ZomeCallResponse::CountersigningSession(msg) => Err(guest_error!(format!("CountersigningSession: {}", msg))),
138                _ => Err(guest_error!(format!("Zome call response: Unauthorized"))),
139            })
140        }
141    };
142}
143
144/// Call a local cell zome function and decode the response
145#[macro_export]
146macro_rules! call_local_cell_decode {
147    ( $role:literal, $zome:literal, $fn:literal, $($input:tt)+ ) => {
148        {
149            use $crate::hdk::prelude::{
150                wasm_error,
151            };
152
153            $crate::call_local_cell!( $role, $zome, $fn, $($input)+ ).and_then(
154                |extern_io| extern_io.decode().map_err(|err| wasm_error!(WasmErrorInner::from(err)) )
155            )
156        }
157    };
158    ( $into_type:ident, $role:literal, $zome:literal, $fn:literal, $($input:tt)+ ) => {
159        {
160            use $crate::hdk::prelude::{
161                wasm_error,
162            };
163
164            $crate::call_local_cell!( $role, $zome, $fn, $($input)+ ).and_then(
165                |extern_io| extern_io.decode::<$into_type>().map_err(|err| wasm_error!(WasmErrorInner::from(err)) )
166            )
167        }
168    };
169}
170
171/// Define a zome function pair
172pub type ZomeFunction<T1,T2> = (T1, T2);
173
174/// Define a list of zome function pairs
175#[derive(Debug, Serialize, Clone)]
176#[allow(non_snake_case)]
177pub struct ListedFunctions {
178    pub Listed: Vec<ZomeFunction<String, String>>,
179}
180
181/// Define a list of zome function pairs for a specific DNA
182#[derive(Debug, Serialize)]
183pub struct RegisterHostInput {
184    pub dna: DnaHash,
185    pub granted_functions: ListedFunctions,
186}
187
188/// Input required for macros [`register`] and [`register_if_exists`]
189#[derive(Debug, Serialize)]
190pub struct RegisterInput<T1,T2>
191where
192    T1: Into<String>,
193    T2: Into<String>,
194{
195    pub dna: DnaHash,
196    pub granted_functions: Vec<ZomeFunction<T1,T2>>,
197}
198
199/// Register a list of zome/functions in a locally running portal cell
200#[macro_export]
201macro_rules! register {
202    ( $dna:literal, $zome:literal, $fn_name:literal, $($def:tt)* ) => {
203        {
204            use $crate::hdk::prelude::*;
205            use $crate::hc_crud::Entity;
206            use $crate::portal_types::HostEntry;
207
208            let input = $crate::RegisterInput $($def)*;
209            let payload = $crate::RegisterHostInput {
210                dna: input.dna,
211                granted_functions: $crate::ListedFunctions {
212                    Listed: input.granted_functions.into_iter()
213                        .map( |(zome, func)| (zome.into(), func.into()) )
214                        .collect()
215                },
216            };
217
218            type Response = Entity<HostEntry>;
219
220            $crate::call_local_cell_decode!(
221                Response,
222                $dna,
223                $zome,
224                $fn_name,
225                payload
226            )
227        }
228    };
229    ( $dna:literal, $zome:literal, $($def:tt)* ) => {
230        $crate::register!( $dna, $zome, "register_host", $($def)* )
231    };
232    ( $dna:literal, $($def:tt)* ) => {
233        $crate::register!( $dna, "portal_csr", $($def)* )
234    };
235    ( $($def:tt)* ) => {
236        $crate::register!( "portal", $($def)* )
237    };
238}
239
240/// Same as `register!` but will fail silently if the portal cell is not present
241#[macro_export]
242macro_rules! register_if_exists {
243    ( $($def:tt)* ) => {
244        {
245            use $crate::hdk::prelude::*;
246
247            let result = $crate::register!( $($def)* );
248
249            match result {
250                Err(err) => match err {
251                    WasmError {
252                        error: WasmErrorInner::Host(ref msg), ..
253                    } if msg.contains("Role not found") => Ok(None),
254                    err => Err(err),
255                },
256                Ok(value) => Ok(Some(value)),
257            }
258        }
259    };
260}