use crate::prelude::{
AppError, Client, IgResult, MarketData, MarketNavigationResponse, MarketNode, MarketService,
};
use std::future::Future;
use std::pin::Pin;
use tracing::{debug, error, info};
pub fn build_market_hierarchy<'a>(
client: &'a Client,
node_id: Option<&'a str>,
depth: usize,
) -> Pin<Box<dyn Future<Output = IgResult<Vec<MarketNode>>> + 'a>> {
Box::pin(async move {
if depth > 7 {
debug!("Reached maximum depth of 5, stopping recursion");
return Ok(Vec::new());
}
let navigation: MarketNavigationResponse = match node_id {
Some(id) => {
debug!("Getting navigation node: {}", id);
match client.get_market_navigation_node(id).await {
Ok(response) => {
debug!(
"Response received for node {}: {} nodes, {} markets",
id,
response.nodes.len(),
response.markets.len()
);
response
}
Err(e) => {
error!("Error getting node {}: {:?}", id, e);
if matches!(e, AppError::RateLimitExceeded | AppError::Unexpected(_)) {
info!("Rate limit or API error encountered, returning partial results");
return Ok(Vec::new());
}
return Err(e);
}
}
}
None => {
debug!("Getting top-level navigation nodes");
match client.get_market_navigation().await {
Ok(response) => {
debug!(
"Response received for top-level nodes: {} nodes, {} markets",
response.nodes.len(),
response.markets.len()
);
response
}
Err(e) => {
error!("Error getting top-level nodes: {:?}", e);
return Err(e);
}
}
}
};
let mut nodes = Vec::new();
let nodes_to_process = navigation.nodes;
for node in nodes_to_process.into_iter() {
match build_market_hierarchy(client, Some(&node.id), depth + 1).await {
Ok(children) => {
info!("Adding node {} with {} children", node.name, children.len());
nodes.push(MarketNode {
id: node.id.clone(),
name: node.name.clone(),
children,
markets: Vec::new(),
});
}
Err(e) => {
error!("Error building hierarchy for node {}: {:?}", node.id, e);
if depth < 7 {
nodes.push(MarketNode {
id: node.id.clone(),
name: format!("{} (error: {})", node.name, e),
children: Vec::new(),
markets: Vec::new(),
});
}
}
}
}
let markets_to_process = navigation.markets;
for market in markets_to_process {
debug!("Adding market: {}", market.instrument_name);
nodes.push(MarketNode {
id: market.epic.clone(),
name: market.instrument_name.clone(),
children: Vec::new(),
markets: vec![market],
});
}
Ok(nodes)
})
}
pub fn extract_markets_from_hierarchy(nodes: &[MarketNode]) -> Vec<MarketData> {
let mut all_markets = Vec::new();
for node in nodes {
all_markets.extend(node.markets.clone());
if !node.children.is_empty() {
all_markets.extend(extract_markets_from_hierarchy(&node.children));
}
}
all_markets
}