use crate::block_tlb::BlockIdExt;
use crate::clients::tl_client::tl::ser_de::serde_block_id_ext;
use crate::clients::tl_client::tl::types::{
TLBlocksHeader, TLBlocksMCInfo, TLBlocksShards, TLBlocksTransactionsExt, TLBlocksTxs, TLConfigInfo,
TLFullAccountState, TLLiteServerInfo, TLLogVerbosityLevel, TLOptionsInfo, TLRawExtMessageInfo,
TLRawFullAccountState, TLRawTxs, TLSmcInfo, TLSmcLibraryResult, TLSmcLibraryResultExt, TLUpdateSyncState,
};
use crate::error::TLError;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::ffi::CStr;
use std::os::raw::c_char;
use strum::IntoStaticStr;
#[derive(IntoStaticStr, Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(tag = "@type", rename_all = "camelCase")]
pub enum TLResponse {
Error {
code: i32,
message: String,
},
Ok(()),
#[serde(rename = "options.info")]
TLOptionsInfo(TLOptionsInfo),
#[serde(rename = "ton.blockIdExt")]
TLBlockIdExt(#[serde(with = "serde_block_id_ext")] BlockIdExt),
#[serde(rename = "raw.fullAccountState")]
TLRawFullAccountState(TLRawFullAccountState),
#[serde(rename = "raw.transactions")]
TLRawTxs(TLRawTxs),
#[serde(rename = "raw.extMessageInfo")]
TLRawExtMessageInfo(TLRawExtMessageInfo),
#[serde(rename = "fullAccountState")]
TLFullAccountState(Box<TLFullAccountState>),
#[serde(rename = "tvm_types.cell")]
TLTvmCell(()), #[serde(rename = "smc.info")]
TLSmcInfo(TLSmcInfo),
#[serde(rename = "smc.runResult")]
TLSmcRunResult(()), #[serde(rename = "smc.libraryResult")]
TLSmcLibraryResult(TLSmcLibraryResult),
#[serde(rename = "smc.libraryResultExt")]
TLSmcLibraryResultExt(TLSmcLibraryResultExt),
#[serde(rename = "updateSyncState")]
TLUpdateSyncState(TLUpdateSyncState),
#[serde(rename = "liteServer.info")]
TLLiteServerInfo(TLLiteServerInfo),
#[serde(rename = "logVerbosityLevel")]
TLLogVerbosityLevel(TLLogVerbosityLevel),
#[serde(rename = "blocks.masterchainInfo")]
TLBlocksMCInfo(TLBlocksMCInfo),
#[serde(rename = "blocks.shards")]
TLBlocksShards(TLBlocksShards),
#[serde(rename = "blocks.transactions")]
TLBlocksTxs(TLBlocksTxs),
#[serde(rename = "blocks.transactionsExt")]
TLBlocksTransactionsExt(TLBlocksTransactionsExt),
#[serde(rename = "blocks.header")]
TLBlocksHeader(TLBlocksHeader),
#[serde(rename = "configInfo")]
TLConfigInfo(TLConfigInfo),
}
impl TLResponse {
pub unsafe fn from_c_str_json(c_str: *const c_char) -> Result<(TLResponse, Option<String>), TLError> {
if c_str.is_null() {
return Err(TLError::TLWrongUsage("null pointer passed to TLResponse".to_string()));
}
let c_str = unsafe { CStr::from_ptr(c_str) };
let json_str = c_str.to_str()?.to_string();
let value: Value = serde_json::from_str(&json_str)?;
let extra: Option<String> =
value.as_object().and_then(|m| m.get("@extra")).and_then(|v| v.as_str()).map(|s| s.to_string());
let response = serde_json::from_value(value)?;
Ok((response, extra))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::CString;
#[test]
fn test_tl_response_from_c_str_json() -> anyhow::Result<()> {
let cstr =
CString::new("{\"@extra\":\"some_extra\",\"@type\":\"logVerbosityLevel\",\"verbosity_level\":100500}")?;
let (rsp, extra) = unsafe { TLResponse::from_c_str_json(cstr.as_ptr())? };
std::mem::forget(cstr); let expected = Some(String::from("some_extra"));
assert_eq!(extra, expected);
assert!(matches!(rsp, TLResponse::TLLogVerbosityLevel(_)));
Ok(())
}
}