use serde::{Deserialize, Serialize}; use tokio::sync::mpsc; use zeromq::{Socket, SocketRecv, SocketSend}; #[derive(Clone, Debug, Serialize)] pub struct HistoryRequest { #[serde(rename = "type")] pub req_type: String, // "download_history" pub symbol: String, pub timeframe: String, pub start: String, pub end: String, pub mode: String, // "OHLC" or "TICKS" } #[derive(Clone, Debug, Deserialize)] pub struct HistoryResponse { pub success: bool, pub error: Option, pub message: Option, } pub struct Mt5Client { pub rep_address: String, } impl Mt5Client { pub fn new(rep_address: &str) -> Self { Self { rep_address: rep_address.to_string(), } } pub async fn download_history(&self, request: HistoryRequest) -> Result { let mut socket = zeromq::ReqSocket::new(); socket.connect(&self.rep_address).await.map_err(|e| format!("Failed to connect: {}", e))?; let json_request = serde_json::to_string(&request).map_err(|e| format!("Serialization error: {}", e))?; socket.send(json_request.into()).await.map_err(|e| format!("Send error: {}", e))?; let msg = socket.recv().await.map_err(|e| format!("Receive error: {}", e))?; let payload = msg.get(0).ok_or("Empty response")?; let json_str = std::str::from_utf8(payload).map_err(|e| format!("UTF8 error: {}", e))?; let response: HistoryResponse = serde_json::from_str(json_str).map_err(|e| format!("JSON Parse error: {}", e))?; if response.success { if let Some(msg) = response.message { if msg.contains("||CSV_DATA||") { let parts: Vec<&str> = msg.splitn(2, "||CSV_DATA||").collect(); if parts.len() == 2 { let csv_content = parts[1].replace("|NL|", "\n"); return Ok(csv_content); } } return Ok(msg); } Ok("Success".to_string()) } else { Err(response.error.unwrap_or_else(|| "Unknown error".to_string())) } } }