use crate::define::TH_COMMON_ETCFN_APICALL;
use crate::define::TH_ESStreamInfo;
use crate::define::ThCommon;
use crate::helper::define::ConfigApi;
use anyhow::Result;
use anyhow::anyhow;
use cyberex::array_cstr_to_str;
use cyberex::void::HyVoid;
use cyberex::void::opacue_to_mut;
use cyberex::xffi::sto::cchar_to_string;
use std::ffi::*;
use xody::body::CallReq;
use xody::body::CallRet;
use super::define::ConfigRelay;
#[derive(Clone)]
pub struct Helper {
common: HyVoid<ThCommon>,
}
impl Helper {
pub fn new(common_p: *const ThCommon) -> Self {
Self {
common: HyVoid::from_ptr(common_p as *mut _),
}
}
fn ctx(&self) -> HyVoid<()> {
HyVoid::<()>::from_ptr(self.common.as_ref().ctx)
}
pub fn get_event_cb(&self) -> impl Fn(String) + 'static + Sync + Send {
let event_cb = self.common.as_ref().event_cb;
let ctx = self.ctx();
move |event_str: String| {
let Some(event_cb) = event_cb else {
return;
};
let Ok(event_str) = CString::new(event_str) else {
return;
};
unsafe {
event_cb(ctx.as_ptr(), event_str.as_ptr());
}
}
}
pub fn get_data_cb(&self) -> impl Fn(&str, &[u8], TH_ESStreamInfo) + Send + Sync + 'static {
let data_cb = self.common.as_ref().data_cb;
let ctx = self.ctx();
move |access_id, data, info| {
let Some(data_cb) = data_cb else {
return;
};
let Ok(access_id) = CString::new(access_id) else {
return;
};
unsafe {
data_cb(
ctx.as_ptr(),
access_id.as_ptr().cast(),
data.as_ptr().cast(),
data.len() as _,
std::ptr::addr_of!(info),
);
}
}
}
pub fn get_soul_relay(&self) -> Result<ConfigRelay> {
let s = self.get_soul_scope_ex("relay")?;
let config = serde_yaml::from_str(&s)?;
Ok(config)
}
pub fn get_soul_api(&self) -> Result<ConfigApi> {
let s = self.get_soul_scope_ex("api")?;
let config = serde_yaml::from_str(&s)?;
Ok(config)
}
pub fn get_soul_scope_ex(&self, scope: &str) -> Result<String> {
type RetType = Option<Result<String>>;
let get_soul_scope_ex = self
.common
.as_ref()
.get_soul_scope_ex
.ok_or_else(|| anyhow!("get_soul_scope_ex must be set in common"))?;
let mut sync_result: RetType = None;
extern "C" fn result_cb(ret: c_int, result: *const c_char, _result_len: usize, user_data: c_longlong) {
if ret != 0 {
return;
}
let sync_result = opacue_to_mut::<RetType>(user_data as *mut _);
let _ = sync_result.insert(Ok(cchar_to_string(result)));
}
let scope = CString::new(scope)?;
unsafe {
get_soul_scope_ex(
self.common.as_ref().ctx,
scope.as_ptr(),
Some(result_cb),
std::ptr::addr_of_mut!(sync_result) as _,
)
};
sync_result.ok_or_else(|| anyhow!("Soul not get"))?
}
pub fn do_etc_ex(&self, req: CallReq) -> Result<CallRet> {
type RetType = Option<Result<String>>;
let do_etc_ex = self
.common
.as_ref()
.do_etc_ex
.ok_or_else(|| anyhow!("do_etc_ex must be set in common"))?;
let mut sync_result: RetType = None;
extern "C" fn result_cb(ret: c_int, result: *const c_char, _result_len: usize, user_data: c_longlong) {
if ret != 0 {
return;
}
let sync_result = opacue_to_mut::<RetType>(user_data as *mut _);
let result_string = cchar_to_string(result);
let _ = sync_result.insert(Ok(result_string));
}
let input_json_cstr = CString::new(serde_json::to_string(&req)?)?;
unsafe {
do_etc_ex(
self.common.as_ref().ctx,
input_json_cstr.as_ptr().cast(),
Some(result_cb),
std::ptr::addr_of_mut!(sync_result) as _,
)
};
let re = sync_result.ok_or_else(|| anyhow!("Method no return"))??;
let call_ret = serde_json::from_str(&re)?;
Ok(call_ret)
}
pub fn logger_get_this_span(&self) -> Result<String> {
let req = CallReq::new("logger_get_this_span", None);
let ret = self.do_etc_ex(req)?.to_result()?;
match ret {
Some(this_span) => Ok(this_span.to_string()),
None => Ok("".to_string()),
}
}
pub fn get_plugin_installed_path(&self) -> Result<String> {
let req = CallReq::new("get_plugin_installed_path", None);
let ret = self.do_etc_ex(req)?.to_result()?;
match ret {
Some(this_span) => Ok(this_span.to_string()),
None => Ok("".to_string()),
}
}
pub fn api_call(&self, req: CallReq) -> Result<CallRet> {
let req_json_value = serde_json::to_value(req)?;
let req = CallReq::new_from_json(array_cstr_to_str!(TH_COMMON_ETCFN_APICALL), req_json_value)?;
let ret = self.do_etc_ex(req)?;
Ok(ret)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_send() {
fn test_fun<T: Sync + Send + Clone>() {}
test_fun::<Helper>();
}
}