ctp_dyn/v1alpha1/
builder.rs

1use std::cell::Cell;
2use std::error::Error;
3use std::ffi::{CStr, CString};
4use std::os::raw::c_char;
5use std::path::Path;
6use std::ptr::null_mut;
7
8use libloading::Library;
9
10use crate::v1alpha1::{CThostFtdcMdApi, CThostFtdcTraderApi};
11
12use crate::v1alpha1::MdApi;
13use crate::v1alpha1::TraderApi;
14
15// 根据 'sopt' 特性定义符号
16#[cfg(not(feature = "sopt"))]
17mod symbols {
18    pub const MDAPI_CREATE_API_SYMBOL: &[u8] = b"_ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb";
19    pub const MDAPI_GET_API_VERSION_SYMBOL: &[u8] = b"_ZN15CThostFtdcMdApi13GetApiVersionEv";
20    pub const TDAPI_CREATE_API_SYMBOL: &[u8] = b"_ZN19CThostFtdcTraderApi19CreateFtdcTraderApiEPKc";
21    pub const TDAPI_GET_API_VERSION_SYMBOL: &[u8] = b"_ZN19CThostFtdcTraderApi13GetApiVersionEv";
22}
23
24#[cfg(feature = "sopt")]
25mod symbols {
26    pub const MDAPI_CREATE_API_SYMBOL: &[u8] =
27        b"_ZN8ctp_sopt15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb";
28    pub const MDAPI_GET_API_VERSION_SYMBOL: &[u8] =
29        b"_ZN8ctp_sopt15CThostFtdcMdApi13GetApiVersionEv";
30    pub const TDAPI_CREATE_API_SYMBOL: &[u8] =
31        b"_ZN8ctp_sopt19CThostFtdcTraderApi19CreateFtdcTraderApiEPKc";
32    pub const TDAPI_GET_API_VERSION_SYMBOL: &[u8] =
33        b"_ZN8ctp_sopt19CThostFtdcTraderApi13GetApiVersionEv";
34}
35
36// 重新导出符号
37pub use symbols::*;
38
39impl MdApi {
40    pub fn create_api<P: AsRef<Path>, F: AsRef<Path>>(
41        dynlib_path: P,
42        flow_path: F,
43        is_using_udp: bool,
44        is_multicast: bool,
45    ) -> Self {
46        // CThostFtdcMdApi_CreateFtdcMdApi(flow_path, is_using_udp, is_multicast)
47        let dynlib =
48            unsafe { libloading::Library::new(dynlib_path.as_ref()).expect("failed to open") };
49        type MdApiCreator = unsafe extern "C" fn(*const c_char, bool, bool) -> *mut CThostFtdcMdApi;
50        let create_api: libloading::Symbol<MdApiCreator> =
51            unsafe { dynlib.get(MDAPI_CREATE_API_SYMBOL).expect("failed to get") };
52        let cflow_path = CString::new(flow_path.as_ref().to_str().unwrap()).expect("fail to new");
53        let api_ptr: *mut CThostFtdcMdApi =
54            unsafe { create_api(cflow_path.as_ptr(), is_using_udp, is_multicast) };
55
56        Self {
57            api_ptr: api_ptr,
58            spi_ptr: Cell::new(null_mut()),
59            dynlib: Some(dynlib),
60        }
61    }
62
63    pub fn get_api_version(&self) -> String {
64        unsafe {
65            type MdGetApiVersion = unsafe extern "C" fn() -> *const c_char;
66            let get_api_version: libloading::Symbol<MdGetApiVersion> = self
67                .dynlib
68                .as_ref()
69                .unwrap()
70                .get(MDAPI_GET_API_VERSION_SYMBOL)
71                .unwrap();
72            let cstr_ptr = get_api_version();
73            let c_str: &CStr = CStr::from_ptr(cstr_ptr);
74            c_str.to_string_lossy().to_string()
75        }
76    }
77}
78
79impl Default for MdApi {
80    fn default() -> Self {
81        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
82        unsafe {
83            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
84            s.assume_init()
85        }
86    }
87}
88
89impl Drop for MdApi {
90    fn drop(&mut self) {
91        let spi_ptr = self.spi_ptr.get();
92        if !spi_ptr.is_null() {
93            unsafe {
94                ((*(*self.api_ptr).vtable_).CThostFtdcMdApi_RegisterSpi)(
95                    self.api_ptr,
96                    std::ptr::null_mut(),
97                );
98                let last_spi = Box::from_raw(spi_ptr); // 释放动态分配的内存
99                drop(last_spi);
100            }
101        }
102        unsafe {
103            if !self.api_ptr.is_null() {
104                ((*(*self.api_ptr).vtable_).CThostFtdcMdApi_Release)(self.api_ptr);
105            }
106            let dynlib = self.dynlib.take();
107            let _ = dynlib.unwrap().close();
108        }
109    }
110}
111
112#[derive(Debug, Default)]
113pub struct MdApiBuilder {
114    flow_path: Option<String>,
115    use_udp: bool,
116    use_multicast: bool,
117    dynlib: Option<String>,
118}
119
120impl MdApiBuilder {
121    pub fn new() -> Self {
122        Self {
123            flow_path: None,
124            use_udp: false,
125            use_multicast: false,
126            dynlib: None,
127        }
128    }
129
130    pub fn from_dynlib(self, path: &str) -> Self {
131        Self {
132            dynlib: Some(path.to_string()),
133            ..self
134        }
135    }
136
137    pub fn flow_path<P: AsRef<Path>>(self, value: P) -> Self {
138        Self {
139            flow_path: Some(value.as_ref().as_os_str().to_str().unwrap().into()),
140            ..self
141        }
142    }
143
144    pub fn using_udp(self, value: bool) -> Self {
145        Self {
146            use_udp: value,
147            ..self
148        }
149    }
150
151    pub fn multicast(self, value: bool) -> Self {
152        Self {
153            use_multicast: value,
154            ..self
155        }
156    }
157
158    pub fn build(self) -> Result<MdApi, &'static str> {
159        let flow_path = self.flow_path.unwrap().clone();
160        let use_udp = self.use_udp;
161        let use_multicast = self.use_multicast;
162
163        // utils::check_and_create_dir(flow_path.as_str())?;
164        match self.dynlib {
165            Some(dynlib_path) => {
166                let mut mdapi = MdApi {
167                    api_ptr: null_mut(),
168                    spi_ptr: Cell::new(null_mut()),
169                    dynlib: None,
170                };
171                println!("here?");
172                unsafe {
173                    let lib = libloading::Library::new(dynlib_path).expect("load dynlib error");
174                    type MdApiCreator =
175                        unsafe extern "C" fn(*const c_char, bool, bool) -> *mut CThostFtdcMdApi;
176                    let create_api: libloading::Symbol<MdApiCreator> = lib
177                        .get(MDAPI_CREATE_API_SYMBOL)
178                        .expect("get md_create_api symbol error");
179                    let cflow_path =
180                        CString::new(flow_path.as_bytes()).expect("create cflow path error");
181                    mdapi.api_ptr = create_api(cflow_path.as_ptr(), use_udp, use_multicast);
182                    mdapi.dynlib = Some(lib);
183                }
184                Ok(mdapi)
185            }
186            None => Err("dynlib null"),
187        }
188    }
189}
190
191impl TraderApi {
192    pub fn create_api<P: AsRef<Path>, F: AsRef<Path>>(dynlib_path: P, flow_path: F) -> Self {
193        // CThostFtdcMdApi_CreateFtdcMdApi(flow_path, is_using_udp, is_multicast)
194        let dynlib =
195            unsafe { libloading::Library::new(dynlib_path.as_ref()).expect("failed to open") };
196        type TraderApiCreator = unsafe extern "C" fn(*const c_char) -> *mut CThostFtdcTraderApi;
197        let create_api: libloading::Symbol<TraderApiCreator> =
198            unsafe { dynlib.get(TDAPI_CREATE_API_SYMBOL).expect("failed to get") };
199        let cflow_path = CString::new(flow_path.as_ref().to_str().unwrap()).expect("fail to new");
200        let api_ptr: *mut CThostFtdcTraderApi = unsafe { create_api(cflow_path.as_ptr()) };
201
202        Self {
203            api_ptr: api_ptr,
204            spi_ptr: Cell::new(null_mut()),
205            dynlib: Some(dynlib),
206        }
207    }
208
209    pub fn get_api_version(&self) -> String {
210        unsafe {
211            type TdGetApiVersion = unsafe extern "C" fn() -> *const c_char;
212            let get_api_version: libloading::Symbol<TdGetApiVersion> = self
213                .dynlib
214                .as_ref()
215                .unwrap()
216                .get(TDAPI_GET_API_VERSION_SYMBOL)
217                .unwrap();
218            let cstr_ptr = get_api_version();
219            let c_str: &CStr = CStr::from_ptr(cstr_ptr);
220            c_str.to_string_lossy().to_string()
221        }
222    }
223}
224
225impl Default for TraderApi {
226    fn default() -> Self {
227        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
228        unsafe {
229            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
230            s.assume_init()
231        }
232    }
233}
234
235impl Drop for TraderApi {
236    fn drop(&mut self) {
237        let spi_ptr = self.spi_ptr.get();
238        if !spi_ptr.is_null() {
239            unsafe {
240                ((*(*self.api_ptr).vtable_).CThostFtdcTraderApi_RegisterSpi)(
241                    self.api_ptr,
242                    std::ptr::null_mut(),
243                );
244                let last_spi = Box::from_raw(spi_ptr); // 释放动态分配的内存
245                drop(last_spi);
246            }
247        }
248        unsafe {
249            if !self.api_ptr.is_null() {
250                ((*(*self.api_ptr).vtable_).CThostFtdcTraderApi_Release)(self.api_ptr);
251            }
252            let dynlib = self.dynlib.take();
253            let _ = dynlib.unwrap().close();
254        }
255    }
256}
257
258pub fn get_api_version_symbol<P: AsRef<Path>>(
259    dynlib_path: P,
260    symbol: &[u8],
261) -> Result<String, libloading::Error> {
262    let dynlib = unsafe { libloading::Library::new(dynlib_path.as_ref())? };
263    unsafe {
264        type GetApiVersion = unsafe extern "C" fn() -> *const c_char;
265        let get_api_version: libloading::Symbol<GetApiVersion> = dynlib.get(symbol)?;
266        let cstr_ptr = get_api_version();
267        let c_str: &CStr = CStr::from_ptr(cstr_ptr);
268        Ok(c_str.to_string_lossy().to_string())
269    }
270}
271
272pub fn get_api_version<P: AsRef<Path>>(dynlib_path: P) -> Result<String, libloading::Error> {
273    let md_symbol = MDAPI_GET_API_VERSION_SYMBOL;
274    let td_symbol = TDAPI_GET_API_VERSION_SYMBOL;
275
276    let dynlib = unsafe { libloading::Library::new(dynlib_path.as_ref())? };
277
278    // 尝试加载 MDAPI 符号
279    let _get_api_version = unsafe {
280        type GetApiVersion = unsafe extern "C" fn() -> *const c_char;
281
282        if let Ok(symbol) = dynlib.get::<GetApiVersion>(md_symbol) {
283            symbol
284        } else if let Ok(symbol) = dynlib.get::<GetApiVersion>(td_symbol) {
285            symbol
286        } else {
287            // 如果两个符号都加载失败,返回错误
288            return Err(libloading::Error::DlSymUnknown);
289        }
290    };
291
292    // 调用加载的符号函数并获取结果
293    unsafe {
294        let cstr_ptr = _get_api_version();
295        let c_str: &CStr = CStr::from_ptr(cstr_ptr);
296        Ok(c_str.to_string_lossy().to_string())
297    }
298}