use std::ffi::CString;
use crate::auth::AuthOptions;
use crate::correlation::CorrelationId;
use crate::errors::{BlpError, Result};
use crate::ffi;
pub struct SessionOptions {
ptr: *mut ffi::blpapi_SessionOptions_t,
}
impl SessionOptions {
pub fn new() -> Result<Self> {
let ptr = unsafe { ffi::blpapi_SessionOptions_create() };
if ptr.is_null() {
return Err(BlpError::Internal {
detail: "blpapi_SessionOptions_create returned null".into(),
});
}
Ok(Self { ptr })
}
pub fn set_server_host(&mut self, host: &str) -> Result<&mut Self> {
let cs = CString::new(host).map_err(|e| BlpError::InvalidArgument {
detail: format!("invalid host: {e}"),
})?;
unsafe { ffi::blpapi_SessionOptions_setServerHost(self.ptr, cs.as_ptr()) };
Ok(self)
}
pub fn set_server_port(&mut self, port: u16) -> &mut Self {
unsafe { ffi::blpapi_SessionOptions_setServerPort(self.ptr, port) };
self
}
pub fn set_server_address(&mut self, host: &str, port: u16, index: usize) -> Result<&mut Self> {
let cs = CString::new(host).map_err(|e| BlpError::InvalidArgument {
detail: format!("invalid host: {e}"),
})?;
let rc = unsafe {
ffi::blpapi_SessionOptions_setServerAddress(self.ptr, cs.as_ptr(), port, index)
};
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!(
"setServerAddress failed: host={host} port={port} index={index} rc={rc}"
),
});
}
Ok(self)
}
pub fn set_server_address_with_proxy(
&mut self,
host: &str,
port: u16,
socks5: &crate::socks5::Socks5Config,
index: usize,
) -> Result<&mut Self> {
let cs = CString::new(host).map_err(|e| BlpError::InvalidArgument {
detail: format!("invalid host: {e}"),
})?;
let rc = unsafe {
ffi::blpapi_SessionOptions_setServerAddressWithProxy(
self.ptr,
cs.as_ptr(),
port,
socks5.as_ptr(),
index,
)
};
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!(
"setServerAddressWithProxy failed: host={host} port={port} index={index} rc={rc}"
),
});
}
Ok(self)
}
pub fn set_session_identity_options(
&mut self,
auth_options: &AuthOptions,
) -> Result<CorrelationId> {
let mut cid = CorrelationId::default().to_ffi();
let rc = unsafe {
ffi::blpapi_SessionOptions_setSessionIdentityOptions(
self.ptr,
auth_options.as_ptr(),
&mut cid,
)
};
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("session identity auth options rejected: rc={rc}"),
});
}
Ok(CorrelationId::from_ffi(&cid))
}
pub fn set_authentication_options(&mut self, auth_options: &str) -> Result<&mut Self> {
let auth_options = CString::new(auth_options).map_err(|e| BlpError::InvalidArgument {
detail: format!("invalid auth options: {e}"),
})?;
unsafe {
ffi::blpapi_SessionOptions_setAuthenticationOptions(self.ptr, auth_options.as_ptr());
}
Ok(self)
}
pub fn set_num_start_attempts(&mut self, attempts: usize) -> Result<&mut Self> {
let attempts = i32::try_from(attempts).map_err(|_| BlpError::InvalidArgument {
detail: format!("num_start_attempts out of range: {attempts}"),
})?;
unsafe {
ffi::blpapi_SessionOptions_setNumStartAttempts(self.ptr, attempts);
}
Ok(self)
}
pub fn set_default_subscription_service(&mut self, svc: &str) -> Result<&mut Self> {
let cs = CString::new(svc).map_err(|e| BlpError::InvalidArgument {
detail: format!("invalid service: {e}"),
})?;
unsafe {
ffi::blpapi_SessionOptions_setDefaultSubscriptionService(self.ptr, cs.as_ptr());
}
Ok(self)
}
pub fn set_default_topic_prefix(&mut self, prefix: &str) -> Result<&mut Self> {
let cs = CString::new(prefix).map_err(|e| BlpError::InvalidArgument {
detail: format!("invalid prefix: {e}"),
})?;
unsafe {
ffi::blpapi_SessionOptions_setDefaultTopicPrefix(self.ptr, cs.as_ptr());
}
Ok(self)
}
pub fn set_auto_restart_on_disconnection(&mut self, auto_restart: bool) -> &mut Self {
unsafe {
ffi::blpapi_SessionOptions_setAutoRestartOnDisconnection(self.ptr, auto_restart as i32);
}
self
}
pub fn set_record_subscription_receive_times(&mut self, record: bool) -> &mut Self {
unsafe {
ffi::blpapi_SessionOptions_setRecordSubscriptionDataReceiveTimes(
self.ptr,
record as i32,
);
}
self
}
pub fn set_connect_timeout_ms(&mut self, timeout_ms: u32) -> Result<&mut Self> {
let rc = unsafe { ffi::blpapi_SessionOptions_setConnectTimeout(self.ptr, timeout_ms) };
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("connect timeout invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_service_check_timeout_ms(&mut self, timeout_ms: i32) -> Result<&mut Self> {
let rc = unsafe { ffi::blpapi_SessionOptions_setServiceCheckTimeout(self.ptr, timeout_ms) };
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("service check timeout invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_service_download_timeout_ms(&mut self, timeout_ms: i32) -> Result<&mut Self> {
let rc =
unsafe { ffi::blpapi_SessionOptions_setServiceDownloadTimeout(self.ptr, timeout_ms) };
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("service download timeout invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_max_event_queue_size(&mut self, size: usize) -> &mut Self {
unsafe {
ffi::blpapi_SessionOptions_setMaxEventQueueSize(self.ptr, size);
}
self
}
pub fn max_event_queue_size(&self) -> usize {
unsafe { ffi::blpapi_SessionOptions_maxEventQueueSize(self.ptr) }
}
pub fn set_slow_consumer_warning_hi_watermark(
&mut self,
hi_watermark: f32,
) -> Result<&mut Self> {
let rc = unsafe {
ffi::blpapi_SessionOptions_setSlowConsumerWarningHiWaterMark(self.ptr, hi_watermark)
};
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("slow consumer hi watermark invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_slow_consumer_warning_lo_watermark(
&mut self,
lo_watermark: f32,
) -> Result<&mut Self> {
let rc = unsafe {
ffi::blpapi_SessionOptions_setSlowConsumerWarningLoWaterMark(self.ptr, lo_watermark)
};
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("slow consumer lo watermark invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_keep_alive_enabled(&mut self, enabled: bool) -> Result<&mut Self> {
let rc =
unsafe { ffi::blpapi_SessionOptions_setKeepAliveEnabled(self.ptr, enabled as i32) };
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("keep alive enabled invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_keep_alive_inactivity_time_ms(&mut self, time_ms: i32) -> Result<&mut Self> {
let rc = unsafe {
ffi::blpapi_SessionOptions_setDefaultKeepAliveInactivityTime(self.ptr, time_ms)
};
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("keep alive inactivity time invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_keep_alive_response_timeout_ms(&mut self, timeout_ms: i32) -> Result<&mut Self> {
let rc = unsafe {
ffi::blpapi_SessionOptions_setDefaultKeepAliveResponseTimeout(self.ptr, timeout_ms)
};
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("keep alive response timeout invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_bandwidth_save_mode_disabled(&mut self, disabled: bool) -> Result<&mut Self> {
let rc = unsafe {
ffi::blpapi_SessionOptions_setBandwidthSaveModeDisabled(self.ptr, disabled as i32)
};
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("bandwidth save mode disabled invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_flush_published_events_timeout_ms(&mut self, timeout_ms: i32) -> Result<&mut Self> {
let rc = unsafe {
ffi::blpapi_SessionOptions_setFlushPublishedEventsTimeout(self.ptr, timeout_ms)
};
if rc != 0 {
return Err(BlpError::InvalidArgument {
detail: format!("flush published events timeout invalid: rc={rc}"),
});
}
Ok(self)
}
pub fn set_tls_options(&mut self, tls: &crate::tls::TlsOptions) {
unsafe { ffi::blpapi_SessionOptions_setTlsOptions(self.ptr, tls.as_ptr()) };
}
pub(crate) fn as_raw(&self) -> *mut ffi::blpapi_SessionOptions_t {
self.ptr
}
}
impl Drop for SessionOptions {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { ffi::blpapi_SessionOptions_destroy(self.ptr) };
self.ptr = std::ptr::null_mut();
}
}
}