use std::ffi::{
c_void,
CString,
};
use std::os::raw::c_char;
use std::ptr;
use super::signer::Signers;
use crate::ffi::callback::Callback;
use crate::ffi::error::Error;
use crate::ffi::runtime::RUNTIME;
use crate::ffi::signer::Signer;
use crate::ffi::util::cstr_from_ptr;
use crate::transaction::AnyTransaction;
use crate::{
AnyMirrorQuery,
AnyQuery,
Client,
};
#[derive(serde::Deserialize)]
#[cfg_attr(feature = "ffi", serde(untagged))]
enum AnyRequest {
Transaction(Box<AnyTransaction>),
Query(Box<AnyQuery>),
MirrorQuery(AnyMirrorQuery),
QueryCost(QueryCostRequest),
}
#[derive(serde::Deserialize)]
struct QueryCostRequest {
query: Box<AnyQuery>,
}
#[no_mangle]
pub unsafe extern "C" fn hedera_execute(
client: *const Client,
request: *const c_char,
context: *const c_void,
signers: Signers,
has_timeout: bool,
timeout: f64,
callback: extern "C" fn(context: *const c_void, err: Error, response: *const c_char),
) -> Error {
assert!(!client.is_null());
let client = unsafe { &*client };
let request = unsafe { cstr_from_ptr(request) };
let request: AnyRequest =
ffi_try!(serde_json::from_str(&request).map_err(crate::Error::request_parse));
let signers_2: Vec<_> = signers.as_slice().iter().map(Signer::to_csigner).collect();
let timeout = has_timeout
.then(|| std::time::Duration::try_from_secs_f64(timeout))
.transpose()
.map_err(crate::Error::request_parse);
let timeout = ffi_try!(timeout);
drop(signers);
let signers = signers_2;
let callback = Callback::new(context, callback);
RUNTIME.spawn(async move {
let response = match request {
AnyRequest::Query(mut query) => query
.execute_with_optional_timeout(client, timeout)
.await
.map(|response| serde_json::to_string(&response).unwrap()),
AnyRequest::Transaction(mut transaction) => {
for signer in signers {
transaction.sign_signer(crate::signer::AnySigner::C(signer));
}
transaction
.execute_with_optional_timeout(client, timeout)
.await
.map(|response| serde_json::to_string(&response).unwrap())
}
AnyRequest::MirrorQuery(mirror_query) => mirror_query
.execute_with_optional_timeout(client, timeout)
.await
.map(|response| serde_json::to_string(&response).unwrap()),
AnyRequest::QueryCost(req) => req
.query
.get_cost_with_optional_timeout(client, timeout)
.await
.map(|response| serde_json::to_string(&response).unwrap()),
};
let response =
response.map(|response| CString::new(response).unwrap().into_raw().cast_const());
let (err, response) = match response {
Ok(response) => (Error::Ok, response),
Err(error) => (Error::new(error), ptr::null()),
};
callback.call(err, response);
if !response.is_null() {
drop(unsafe { CString::from_raw(response.cast_mut()) });
}
});
Error::Ok
}