use crate::internal::audit::AuditHmacKey;
use crate::internal::backend::{BackendFactoryConfig, IbkrBackend, create_backend};
use crate::internal::domain::{
BrokerAccount, BrokerBackendKind, BrokerSessionStatus, ContractCandidate, GatewayError,
};
use std::fmt;
use std::path::PathBuf;
use std::sync::Arc;
use url::Url;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GatewayConfig {
pub backend: BrokerBackendKind,
pub fixture_root: PathBuf,
pub client_portal_base_url: Option<Url>,
pub verify_tls: bool,
pub audit_hmac_key: Option<Arc<AuditHmacKey>>,
}
impl GatewayConfig {
#[must_use]
pub fn fake_local() -> Self {
Self::fake_with_fixture_root("tests/fixtures/cpapi")
}
#[must_use]
pub fn fake_with_fixture_root(fixture_root: impl Into<PathBuf>) -> Self {
Self {
backend: BrokerBackendKind::Fake,
fixture_root: fixture_root.into(),
client_portal_base_url: None,
verify_tls: true,
audit_hmac_key: None,
}
}
#[must_use]
pub fn client_portal(base_url: Url) -> Self {
Self {
backend: BrokerBackendKind::ClientPortalGateway,
fixture_root: PathBuf::new(),
client_portal_base_url: Some(base_url),
verify_tls: true,
audit_hmac_key: None,
}
}
#[must_use]
pub const fn with_verify_tls(mut self, verify_tls: bool) -> Self {
self.verify_tls = verify_tls;
self
}
#[must_use]
pub fn with_audit_hmac_key(mut self, key: AuditHmacKey) -> Self {
self.audit_hmac_key = Some(Arc::new(key));
self
}
}
impl Default for GatewayConfig {
fn default() -> Self {
Self::fake_local()
}
}
#[derive(Clone)]
pub struct Gateway {
config: GatewayConfig,
backend: Arc<dyn IbkrBackend>,
}
impl fmt::Debug for Gateway {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("Gateway")
.field("config", &self.config)
.finish_non_exhaustive()
}
}
impl Gateway {
pub fn new(mut config: GatewayConfig) -> Result<Self, GatewayError> {
let audit_hmac_key = match config.audit_hmac_key.clone() {
Some(key) => key,
None => {
let key = Arc::new(AuditHmacKey::ephemeral()?);
config.audit_hmac_key = Some(key.clone());
key
}
};
let factory_config = BackendFactoryConfig {
backend: config.backend,
fixture_root: config.fixture_root.clone(),
client_portal_base_url: config.client_portal_base_url.clone(),
verify_tls: config.verify_tls,
audit_hmac_key,
};
let backend = create_backend(factory_config)?.into();
Ok(Self { config, backend })
}
#[must_use]
pub const fn config(&self) -> &GatewayConfig {
&self.config
}
pub async fn session_status(&self) -> Result<BrokerSessionStatus, GatewayError> {
self.backend.session_status().await
}
pub async fn keepalive(&self) -> Result<BrokerSessionStatus, GatewayError> {
self.backend.keepalive().await
}
pub async fn list_accounts(&self) -> Result<Vec<BrokerAccount>, GatewayError> {
self.backend.list_accounts().await
}
pub async fn search_contracts(
&self,
query: impl AsRef<str>,
) -> Result<Vec<ContractCandidate>, GatewayError> {
self.backend.search_contracts(query.as_ref()).await
}
}