use super::common::{borrow_cstr, cstring, last_error};
use super::pod::{EkDepthMarketData, EkErrorField};
use std::ffi::{CString, c_char, c_int, c_void};
use std::path::Path;
#[repr(C)]
#[derive(Clone, Copy)]
pub struct MdSpiCallbacks {
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_user_login: Option<unsafe extern "C" fn(*mut c_void, *const EkErrorField)>,
pub on_rsp_error: Option<unsafe extern "C" fn(*mut c_void, *const EkErrorField)>,
pub on_rsp_sub_market_data: Option<unsafe extern "C" fn(*mut c_void, *const EkErrorField)>,
pub on_rtn_depth_market_data:
Option<unsafe extern "C" fn(*mut c_void, *const EkDepthMarketData)>,
}
impl MdSpiCallbacks {
pub const fn none() -> Self {
Self {
on_front_connected: None,
on_front_disconnected: None,
on_rsp_user_login: None,
on_rsp_error: None,
on_rsp_sub_market_data: None,
on_rtn_depth_market_data: None,
}
}
}
unsafe extern "C" {
fn ek_shim_md_api_version() -> *const c_char;
fn ek_shim_sizeof_md_spi_callbacks() -> c_int;
fn ek_shim_md_create(
flow_path: *const c_char,
use_udp: c_int,
use_multicast: c_int,
) -> *mut c_void;
fn ek_shim_md_release(handle: *mut c_void);
fn ek_shim_md_register_front(handle: *mut c_void, front_address: *const c_char);
fn ek_shim_md_register_spi(
handle: *mut c_void,
callbacks: *const MdSpiCallbacks,
ctx: *mut c_void,
);
fn ek_shim_md_init(handle: *mut c_void);
fn ek_shim_md_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_md_subscribe(
handle: *mut c_void,
instrument_ids: *const *const c_char,
count: c_int,
) -> c_int;
}
pub fn api_version() -> Option<String> {
let p = unsafe { ek_shim_md_api_version() };
unsafe { borrow_cstr(p) }
}
pub fn callbacks_sizeof() -> usize {
unsafe { ek_shim_sizeof_md_spi_callbacks() }.max(0) as usize
}
pub struct MdApi {
handle: *mut c_void,
}
unsafe impl Send for MdApi {}
impl MdApi {
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_md_create(flow.as_ptr(), 0, 0) };
if handle.is_null() {
return Err(
last_error().unwrap_or_else(|| "ek_shim_md_create returned null".to_string())
);
}
Ok(Self { handle })
}
pub fn register_front(&mut self, front_address: &str) {
let addr = cstring(front_address, "front address");
unsafe { ek_shim_md_register_front(self.handle, addr.as_ptr()) };
}
pub unsafe fn register_spi(&mut self, callbacks: &MdSpiCallbacks, ctx: *mut c_void) {
unsafe { ek_shim_md_register_spi(self.handle, callbacks, ctx) };
}
pub fn init(&mut self) {
unsafe { ek_shim_md_init(self.handle) };
}
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_md_req_user_login(
self.handle,
broker.as_ptr(),
user.as_ptr(),
pass.as_ptr(),
request_id as c_int,
)
}
}
pub fn subscribe(&mut self, instruments: &[&str]) -> i32 {
let owned: Vec<CString> = instruments
.iter()
.map(|s| cstring(s, "instrument id"))
.collect();
let ptrs: Vec<*const c_char> = owned.iter().map(|c| c.as_ptr()).collect();
unsafe { ek_shim_md_subscribe(self.handle, ptrs.as_ptr(), ptrs.len() as c_int) }
}
}
impl Drop for MdApi {
fn drop(&mut self) {
if !self.handle.is_null() {
unsafe { ek_shim_md_release(self.handle) };
self.handle = std::ptr::null_mut();
}
}
}