rs_zephyr_sdk/
env.rs

1use rs_zephyr_common::{http::AgnosticRequest, RelayedMessageRequest};
2use serde::Serialize;
3use stellar_xdr::next::{Limits, ReadXdr};
4
5use crate::{database::{Database, DatabaseInteract}, external::{conclude_host, read_ledger_meta, tx_send_message}, logger::EnvLogger, Condition, MetaReader, SdkError, TableRows};
6
7
8/// Zephyr's host environment client.
9#[derive(Clone)]
10pub struct EnvClient {
11    xdr: Option<stellar_xdr::next::LedgerCloseMeta>,
12    inner_soroban_host: soroban_sdk::Env,
13}
14
15
16impl EnvClient {
17    /// Returns the logger object.
18    pub fn log(&self) -> EnvLogger {
19        EnvLogger
20    }
21
22    /// Returns a soroban host stub.
23    pub fn soroban(&self) -> &soroban_sdk::Env {
24        &self.inner_soroban_host
25    }
26
27    pub(crate) fn message_relay(message: impl Serialize) {
28        let serialized = bincode::serialize(&message).unwrap();
29        
30        let res = unsafe {
31            tx_send_message(
32                serialized.as_ptr() as i64, 
33                serialized.len() as i64
34            )
35        };
36
37        SdkError::express_from_status(res).unwrap()
38    }
39
40    /// Sends a web request message requests to the host.
41    pub fn send_web_request(&self, request: AgnosticRequest) {
42        let message = RelayedMessageRequest::Http(request);
43        
44        Self::message_relay(message)
45    }
46    
47    /// Reads a database table.
48    /// 
49    /// This function uses the [`DatabaseInteract`] trait
50    /// along with the `DatabaseDerive` macro to read the rows 
51    /// into a `DatabaseDerive` struct.
52    pub fn read<T: DatabaseInteract>(&self) -> Vec<T> {
53        T::read_to_rows(&self)
54    }
55
56    /// Writes a row to a database table.
57    /// 
58    /// This function uses the [`DatabaseInteract`] trait
59    /// along with the `DatabaseDerive` macro to write the row 
60    /// derived from the `DatabaseDerive` struct.
61    pub fn put<T: DatabaseInteract>(&self, row: &T) {
62        row.put(&self)
63    }
64
65    /// Updates a row to a database table.
66    /// 
67    /// This function uses the [`DatabaseInteract`] trait
68    /// along with the `DatabaseDerive` macro to update the row 
69    /// derived from the `DatabaseDerive` struct.
70    pub fn update<T: DatabaseInteract>(&self, row: &T, conditions: &[Condition]) {
71        row.update(&self, conditions)
72    }
73
74    /// Raw function to write to the database a row.
75    pub fn db_write(&self, table_name: &str, columns: &[&str], segments: &[&[u8]]) -> Result<(), SdkError> {
76        Database::write_table(table_name, columns, segments)
77    }
78
79    /// Raw function to update a database row.
80    pub fn db_update(&self, table_name: &str, columns: &[&str], segments: &[&[u8]], conditions: &[Condition]) -> Result<(), SdkError> {
81        Database::update_table(table_name, columns, segments, conditions)
82    }
83
84    /// Raw function to read from database.
85    pub fn db_read(&self, table_name: &str, columns: &[&str]) -> Result<TableRows, SdkError> {
86        Database::read_table(table_name, columns)
87    }
88
89    /// Returns the XDR reader object.
90    pub fn reader(&self) -> MetaReader {
91        let meta = &self.xdr;
92
93        if let Some(meta) = meta {
94            MetaReader::new(meta)
95        } else {
96            panic!("Internal SDK error") // todo: handle
97        }
98    }
99
100    /// New instance of the zephyr client with the ledger
101    /// meta already set.
102    pub fn new() -> Self {
103        let (offset, size) = unsafe { read_ledger_meta() };
104
105        let ledger_meta = {
106            let memory = 0 as *const u8;
107            let slice = unsafe {
108                let start = memory.offset(offset as isize);
109                core::slice::from_raw_parts(start, size as usize)
110            };
111            
112            Some(stellar_xdr::next::LedgerCloseMeta::from_xdr(slice, Limits::none()).unwrap())
113        };
114        
115        Self { xdr: ledger_meta, inner_soroban_host: soroban_sdk::Env::default() }
116    }
117
118    /// New empty instance of the zephyr client.
119    pub fn empty() -> Self {
120        Self { xdr: None, inner_soroban_host: soroban_sdk::Env::default() }
121    }
122
123    //
124    // Functions-only code
125    //
126    
127    /// Send a result to the host.
128    /// 
129    /// This function has no effect when used in ingestion zephyr programs
130    /// and should only be used with serverless functions as target.
131    /// 
132    pub fn conclude<T: Serialize>(&self, result: T) {
133        let v = bincode::serialize(&serde_json::to_string(&result).unwrap()).unwrap();
134        
135        unsafe {
136            conclude_host(v.as_ptr() as i64, v.len() as i64)
137        }
138    }
139}