ig_client/application/services/
account_service.rs

1use async_trait::async_trait;
2use reqwest::Method;
3use std::sync::Arc;
4use tracing::{debug, info};
5
6use crate::{
7    application::models::account::{
8        AccountActivity, AccountInfo, Positions, TransactionHistory, WorkingOrders,
9    },
10    config::Config,
11    error::AppError,
12    session::interface::IgSession,
13    transport::http_client::IgHttpClient,
14};
15
16/// Interface for the account service
17#[async_trait]
18pub trait AccountService: Send + Sync {
19    /// Gets information about all user accounts
20    async fn get_accounts(&self, session: &IgSession) -> Result<AccountInfo, AppError>;
21
22    /// Gets open positions
23    async fn get_positions(&self, session: &IgSession) -> Result<Positions, AppError>;
24
25    /// Gets working orders
26    async fn get_working_orders(&self, session: &IgSession) -> Result<WorkingOrders, AppError>;
27
28    /// Gets account activity
29    async fn get_activity(
30        &self,
31        session: &IgSession,
32        from: &str,
33        to: &str,
34    ) -> Result<AccountActivity, AppError>;
35
36    /// Gets transaction history
37    async fn get_transactions(
38        &self,
39        session: &IgSession,
40        from: &str,
41        to: &str,
42        page_size: u32,
43        page_number: u32,
44    ) -> Result<TransactionHistory, AppError>;
45}
46
47/// Implementation of the account service
48pub struct AccountServiceImpl<T: IgHttpClient> {
49    config: Arc<Config>,
50    client: Arc<T>,
51}
52
53impl<T: IgHttpClient> AccountServiceImpl<T> {
54    /// Creates a new instance of the account service
55    pub fn new(config: Arc<Config>, client: Arc<T>) -> Self {
56        Self { config, client }
57    }
58
59    /// Gets the current configuration
60    ///
61    /// # Returns
62    /// * The current configuration as an `Arc<Config>`
63    pub fn get_config(&self) -> Arc<Config> {
64        self.config.clone()
65    }
66
67    /// Sets a new configuration
68    ///
69    /// # Arguments
70    /// * `config` - The new configuration to use
71    pub fn set_config(&mut self, config: Arc<Config>) {
72        self.config = config;
73    }
74}
75
76#[async_trait]
77impl<T: IgHttpClient + 'static> AccountService for AccountServiceImpl<T> {
78    async fn get_accounts(&self, session: &IgSession) -> Result<AccountInfo, AppError> {
79        info!("Getting account information");
80
81        let result = self
82            .client
83            .request::<(), AccountInfo>(Method::GET, "accounts", session, None, "1")
84            .await?;
85
86        debug!(
87            "Account information obtained: {} accounts",
88            result.accounts.len()
89        );
90        Ok(result)
91    }
92
93    async fn get_positions(&self, session: &IgSession) -> Result<Positions, AppError> {
94        info!("Getting open positions");
95
96        let result = self
97            .client
98            .request::<(), Positions>(Method::GET, "positions", session, None, "2")
99            .await?;
100
101        debug!("Positions obtained: {} positions", result.positions.len());
102        Ok(result)
103    }
104
105    async fn get_working_orders(&self, session: &IgSession) -> Result<WorkingOrders, AppError> {
106        info!("Getting working orders");
107
108        let result = self
109            .client
110            .request::<(), WorkingOrders>(Method::GET, "workingorders", session, None, "2")
111            .await?;
112
113        debug!(
114            "Working orders obtained: {} orders",
115            result.working_orders.len()
116        );
117        Ok(result)
118    }
119
120    async fn get_activity(
121        &self,
122        session: &IgSession,
123        from: &str,
124        to: &str,
125    ) -> Result<AccountActivity, AppError> {
126        let path = format!("history/activity?from={}&to={}", from, to);
127        info!("Getting account activity");
128
129        let result = self
130            .client
131            .request::<(), AccountActivity>(Method::GET, &path, session, None, "3")
132            .await?;
133
134        debug!(
135            "Account activity obtained: {} activities",
136            result.activities.len()
137        );
138        Ok(result)
139    }
140
141    async fn get_transactions(
142        &self,
143        session: &IgSession,
144        from: &str,
145        to: &str,
146        page_size: u32,
147        page_number: u32,
148    ) -> Result<TransactionHistory, AppError> {
149        let path = format!(
150            "history/transactions?from={}&to={}&pageSize={}&pageNumber={}",
151            from, to, page_size, page_number
152        );
153        info!("Getting transaction history");
154
155        let result = self
156            .client
157            .request::<(), TransactionHistory>(Method::GET, &path, session, None, "2")
158            .await?;
159
160        debug!(
161            "Transaction history obtained: {} transactions",
162            result.transactions.len()
163        );
164        Ok(result)
165    }
166}
167
168#[cfg(test)]
169mod tests {
170    use super::*;
171    use crate::config::Config;
172    use crate::transport::http_client::IgHttpClientImpl;
173    use std::sync::Arc;
174
175    #[test]
176    fn test_get_and_set_config() {
177        let config = Arc::new(Config::new());
178        let client = Arc::new(IgHttpClientImpl::new(config.clone()));
179        let mut service = AccountServiceImpl::new(config.clone(), client.clone());
180
181        let cfg1 = service.get_config();
182        assert!(Arc::ptr_eq(&cfg1, &config));
183
184        let new_cfg = Arc::new(Config::default());
185        service.set_config(new_cfg.clone());
186        assert!(Arc::ptr_eq(&service.get_config(), &new_cfg));
187    }
188}