ctp_dyn/v1alpha1/
builder.rs1use 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#[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
36pub 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 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); 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 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 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); 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 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 return Err(libloading::Error::DlSymUnknown);
289 }
290 };
291
292 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}