use super::common::{borrow_cstr, cstring, last_error};
use super::pod::{
EkErrorField, EkInputOrder, EkInputOrderAction, EkInstrumentCommissionRate, EkInstrumentField,
EkInstrumentMarginRate, EkInstrumentStatus, EkInvestorPositionField, EkOrderField,
EkQryInstrumentCommissionRate, EkQryInstrumentMarginRate, EkTradeField, EkTradingAccountField,
};
use std::ffi::{c_char, c_int, c_void};
use std::path::Path;
#[repr(C)]
#[derive(Clone, Copy)]
pub struct TdSpiCallbacks {
pub on_front_connected: Option<unsafe extern "C" fn(*mut c_void)>,
pub on_front_disconnected: Option<unsafe extern "C" fn(*mut c_void, c_int)>,
pub on_rsp_authenticate: Option<unsafe extern "C" fn(*mut c_void, *const EkErrorField)>,
pub on_rsp_user_login:
Option<unsafe extern "C" fn(*mut c_void, c_int, c_int, *const EkErrorField)>,
pub on_rsp_settlement_info_confirm:
Option<unsafe extern "C" fn(*mut c_void, *const EkErrorField)>,
pub on_rsp_order_insert:
Option<unsafe extern "C" fn(*mut c_void, *const EkInputOrder, *const EkErrorField)>,
pub on_rsp_order_action: Option<unsafe extern "C" fn(*mut c_void, *const EkErrorField)>,
pub on_rsp_qry_instrument: Option<
unsafe extern "C" fn(*mut c_void, *const EkInstrumentField, *const EkErrorField, c_int),
>,
pub on_rsp_qry_investor_position: Option<
unsafe extern "C" fn(
*mut c_void,
*const EkInvestorPositionField,
*const EkErrorField,
c_int,
),
>,
pub on_rsp_qry_trading_account: Option<
unsafe extern "C" fn(*mut c_void, *const EkTradingAccountField, *const EkErrorField, c_int),
>,
pub on_rtn_order: Option<unsafe extern "C" fn(*mut c_void, *const EkOrderField)>,
pub on_rtn_trade: Option<unsafe extern "C" fn(*mut c_void, *const EkTradeField)>,
pub on_rsp_qry_instrument_margin_rate: Option<
unsafe extern "C" fn(
*mut c_void,
*const EkInstrumentMarginRate,
*const EkErrorField,
c_int,
),
>,
pub on_rsp_qry_instrument_commission_rate: Option<
unsafe extern "C" fn(
*mut c_void,
*const EkInstrumentCommissionRate,
*const EkErrorField,
c_int,
),
>,
pub on_rtn_instrument_status:
Option<unsafe extern "C" fn(*mut c_void, *const EkInstrumentStatus)>,
}
impl TdSpiCallbacks {
pub const fn none() -> Self {
Self {
on_front_connected: None,
on_front_disconnected: None,
on_rsp_authenticate: None,
on_rsp_user_login: None,
on_rsp_settlement_info_confirm: None,
on_rsp_order_insert: None,
on_rsp_order_action: None,
on_rsp_qry_instrument: None,
on_rsp_qry_investor_position: None,
on_rsp_qry_trading_account: None,
on_rtn_order: None,
on_rtn_trade: None,
on_rsp_qry_instrument_margin_rate: None,
on_rsp_qry_instrument_commission_rate: None,
on_rtn_instrument_status: None,
}
}
}
unsafe extern "C" {
fn ek_shim_td_api_version() -> *const c_char;
fn ek_shim_sizeof_td_spi_callbacks() -> c_int;
fn ek_shim_td_create(flow_path: *const c_char) -> *mut c_void;
fn ek_shim_td_release(handle: *mut c_void);
fn ek_shim_td_register_front(handle: *mut c_void, front_address: *const c_char);
fn ek_shim_td_register_spi(
handle: *mut c_void,
callbacks: *const TdSpiCallbacks,
ctx: *mut c_void,
);
fn ek_shim_td_subscribe_private_topic(handle: *mut c_void, resume_type: c_int);
fn ek_shim_td_subscribe_public_topic(handle: *mut c_void, resume_type: c_int);
fn ek_shim_td_init(handle: *mut c_void);
fn ek_shim_td_req_authenticate(
handle: *mut c_void,
broker_id: *const c_char,
user_id: *const c_char,
auth_code: *const c_char,
app_id: *const c_char,
request_id: c_int,
) -> c_int;
fn ek_shim_td_req_user_login(
handle: *mut c_void,
broker_id: *const c_char,
user_id: *const c_char,
password: *const c_char,
request_id: c_int,
) -> c_int;
fn ek_shim_td_req_settlement_confirm(
handle: *mut c_void,
broker_id: *const c_char,
investor_id: *const c_char,
request_id: c_int,
) -> c_int;
fn ek_shim_td_req_qry_instrument(handle: *mut c_void, request_id: c_int) -> c_int;
fn ek_shim_td_req_qry_trading_account(
handle: *mut c_void,
broker_id: *const c_char,
investor_id: *const c_char,
request_id: c_int,
) -> c_int;
fn ek_shim_td_req_qry_investor_position(
handle: *mut c_void,
broker_id: *const c_char,
investor_id: *const c_char,
request_id: c_int,
) -> c_int;
fn ek_shim_td_req_order_insert(
handle: *mut c_void,
order: *const EkInputOrder,
request_id: c_int,
) -> c_int;
fn ek_shim_td_req_order_action(
handle: *mut c_void,
action: *const EkInputOrderAction,
request_id: c_int,
) -> c_int;
fn ek_shim_td_req_qry_instrument_margin_rate(
handle: *mut c_void,
query: *const EkQryInstrumentMarginRate,
request_id: c_int,
) -> c_int;
fn ek_shim_td_req_qry_instrument_commission_rate(
handle: *mut c_void,
query: *const EkQryInstrumentCommissionRate,
request_id: c_int,
) -> c_int;
}
pub fn api_version() -> Option<String> {
let p = unsafe { ek_shim_td_api_version() };
unsafe { borrow_cstr(p) }
}
pub fn callbacks_sizeof() -> usize {
unsafe { ek_shim_sizeof_td_spi_callbacks() }.max(0) as usize
}
pub const TE_RESUME_RESTART: i32 = 0;
pub struct TdApi {
handle: *mut c_void,
}
unsafe impl Send for TdApi {}
impl TdApi {
pub fn new(flow_path: &Path) -> Result<Self, String> {
let path = flow_path
.to_str()
.ok_or_else(|| format!("flow path is not valid UTF-8: {}", flow_path.display()))?;
let flow = cstring(path, "flow path");
let handle = unsafe { ek_shim_td_create(flow.as_ptr()) };
if handle.is_null() {
return Err(last_error().unwrap_or_else(|| "ek_shim_td_create returned null".into()));
}
Ok(Self { handle })
}
pub fn register_front(&mut self, front_address: &str) {
let addr = cstring(front_address, "front address");
unsafe { ek_shim_td_register_front(self.handle, addr.as_ptr()) };
}
pub unsafe fn register_spi(&mut self, callbacks: &TdSpiCallbacks, ctx: *mut c_void) {
unsafe { ek_shim_td_register_spi(self.handle, callbacks, ctx) };
}
pub fn subscribe_private_topic(&mut self, resume_type: i32) {
unsafe { ek_shim_td_subscribe_private_topic(self.handle, resume_type as c_int) };
}
pub fn subscribe_public_topic(&mut self, resume_type: i32) {
unsafe { ek_shim_td_subscribe_public_topic(self.handle, resume_type as c_int) };
}
pub fn init(&mut self) {
unsafe { ek_shim_td_init(self.handle) };
}
pub fn req_authenticate(
&mut self,
broker_id: &str,
user_id: &str,
auth_code: &str,
app_id: &str,
request_id: i32,
) -> i32 {
let broker = cstring(broker_id, "broker id");
let user = cstring(user_id, "user id");
let auth = cstring(auth_code, "auth code");
let app = cstring(app_id, "app id");
unsafe {
ek_shim_td_req_authenticate(
self.handle,
broker.as_ptr(),
user.as_ptr(),
auth.as_ptr(),
app.as_ptr(),
request_id as c_int,
)
}
}
pub fn req_user_login(
&mut self,
broker_id: &str,
user_id: &str,
password: &str,
request_id: i32,
) -> i32 {
let broker = cstring(broker_id, "broker id");
let user = cstring(user_id, "user id");
let pass = cstring(password, "password");
unsafe {
ek_shim_td_req_user_login(
self.handle,
broker.as_ptr(),
user.as_ptr(),
pass.as_ptr(),
request_id as c_int,
)
}
}
pub fn req_settlement_confirm(
&mut self,
broker_id: &str,
investor_id: &str,
request_id: i32,
) -> i32 {
let broker = cstring(broker_id, "broker id");
let investor = cstring(investor_id, "investor id");
unsafe {
ek_shim_td_req_settlement_confirm(
self.handle,
broker.as_ptr(),
investor.as_ptr(),
request_id as c_int,
)
}
}
pub fn req_qry_instrument(&mut self, request_id: i32) -> i32 {
unsafe { ek_shim_td_req_qry_instrument(self.handle, request_id as c_int) }
}
pub fn req_qry_trading_account(
&mut self,
broker_id: &str,
investor_id: &str,
request_id: i32,
) -> i32 {
let broker = cstring(broker_id, "broker id");
let investor = cstring(investor_id, "investor id");
unsafe {
ek_shim_td_req_qry_trading_account(
self.handle,
broker.as_ptr(),
investor.as_ptr(),
request_id as c_int,
)
}
}
pub fn req_qry_investor_position(
&mut self,
broker_id: &str,
investor_id: &str,
request_id: i32,
) -> i32 {
let broker = cstring(broker_id, "broker id");
let investor = cstring(investor_id, "investor id");
unsafe {
ek_shim_td_req_qry_investor_position(
self.handle,
broker.as_ptr(),
investor.as_ptr(),
request_id as c_int,
)
}
}
pub fn req_order_insert(&mut self, order: &EkInputOrder, request_id: i32) -> i32 {
unsafe { ek_shim_td_req_order_insert(self.handle, order, request_id as c_int) }
}
pub fn req_order_action(&mut self, action: &EkInputOrderAction, request_id: i32) -> i32 {
unsafe { ek_shim_td_req_order_action(self.handle, action, request_id as c_int) }
}
pub fn req_qry_instrument_margin_rate(
&mut self,
query: &EkQryInstrumentMarginRate,
request_id: i32,
) -> i32 {
unsafe {
ek_shim_td_req_qry_instrument_margin_rate(self.handle, query, request_id as c_int)
}
}
pub fn req_qry_instrument_commission_rate(
&mut self,
query: &EkQryInstrumentCommissionRate,
request_id: i32,
) -> i32 {
unsafe {
ek_shim_td_req_qry_instrument_commission_rate(self.handle, query, request_id as c_int)
}
}
}
impl Drop for TdApi {
fn drop(&mut self) {
if !self.handle.is_null() {
unsafe { ek_shim_td_release(self.handle) };
self.handle = std::ptr::null_mut();
}
}
}