ig_client/application/services/
market_service.rs

1use crate::application::services::MarketService;
2use crate::{
3    application::models::market::{HistoricalPricesResponse, MarketDetails, MarketSearchResult},
4    config::Config,
5    error::AppError,
6    session::interface::IgSession,
7    transport::http_client::IgHttpClient,
8};
9use async_trait::async_trait;
10use reqwest::Method;
11use std::sync::Arc;
12use tracing::{debug, info};
13
14/// Implementation of the market service
15pub struct MarketServiceImpl<T: IgHttpClient> {
16    config: Arc<Config>,
17    client: Arc<T>,
18}
19
20impl<T: IgHttpClient> MarketServiceImpl<T> {
21    /// Creates a new instance of the market service
22    pub fn new(config: Arc<Config>, client: Arc<T>) -> Self {
23        Self { config, client }
24    }
25
26    /// Gets the current configuration
27    ///
28    /// # Returns
29    /// * Reference to the current configuration
30    pub fn get_config(&self) -> &Config {
31        &self.config
32    }
33
34    /// Sets a new configuration
35    ///
36    /// # Arguments
37    /// * `config` - The new configuration to use
38    pub fn set_config(&mut self, config: Arc<Config>) {
39        self.config = config;
40    }
41}
42
43#[async_trait]
44impl<T: IgHttpClient + 'static> MarketService for MarketServiceImpl<T> {
45    async fn search_markets(
46        &self,
47        session: &IgSession,
48        search_term: &str,
49    ) -> Result<MarketSearchResult, AppError> {
50        let path = format!("markets?searchTerm={}", search_term);
51        info!("Searching markets with term: {}", search_term);
52
53        let result = self
54            .client
55            .request::<(), MarketSearchResult>(Method::GET, &path, session, None, "1")
56            .await?;
57
58        debug!("{} markets found", result.markets.len());
59        Ok(result)
60    }
61
62    async fn get_market_details(
63        &self,
64        session: &IgSession,
65        epic: &str,
66    ) -> Result<MarketDetails, AppError> {
67        let path = format!("markets/{}", epic);
68        info!("Getting market details: {}", epic);
69
70        let result = self
71            .client
72            .request::<(), MarketDetails>(Method::GET, &path, session, None, "3")
73            .await?;
74
75        debug!("Market details obtained for: {}", epic);
76        Ok(result)
77    }
78
79    async fn get_historical_prices(
80        &self,
81        session: &IgSession,
82        epic: &str,
83        resolution: &str,
84        from: &str,
85        to: &str,
86    ) -> Result<HistoricalPricesResponse, AppError> {
87        let path = format!("prices/{}/{}?from={}&to={}", epic, resolution, from, to);
88        info!("Getting historical prices for: {}", epic);
89
90        let result = self
91            .client
92            .request::<(), HistoricalPricesResponse>(Method::GET, &path, session, None, "3")
93            .await?;
94
95        debug!("Historical prices obtained for: {}", epic);
96        Ok(result)
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use crate::config::Config;
104    use crate::transport::http_client::IgHttpClientImpl;
105    use std::sync::Arc;
106
107    #[test]
108    fn test_get_and_set_config() {
109        let config = Arc::new(Config::new());
110        let client = Arc::new(IgHttpClientImpl::new(config.clone()));
111        let mut service = MarketServiceImpl::new(config.clone(), client.clone());
112        assert!(std::ptr::eq(service.get_config(), &*config));
113        let new_cfg = Arc::new(Config::default());
114        service.set_config(new_cfg.clone());
115        assert!(std::ptr::eq(service.get_config(), &*new_cfg));
116    }
117}