// ===========================
// File: src/feed.rs (NEW)
// ===========================
use crate::types::Tick;
use crate::redis::{RedisCore, get_redis_conn};
use redis::AsyncCommands;
use std::sync::Arc;
/// Модуль для чтения/публикации тиков через Redis.
pub struct Feed {
redis: Arc<RedisCore>,
}
impl Feed {
pub fn new(redis: Arc<RedisCore>) -> Self {
Feed { redis }
}
/// Получаем последний тик по символу из Redis.
///
/// Монитор пишет:
/// - список: LPUSH hb:ticks:{SYMBOL} "<json Tick>"
/// - последний тик: SET hb:last:{SYMBOL} "<json Tick>"
///
/// Здесь используем именно hb:last:{SYMBOL}, чтобы:
/// - не дёргать лишний раз список
/// - всегда брать актуальный последний тик O(1)
pub async fn get_tick_from_redis(&self, symbol: &str) -> Option<Tick> {
let mut conn = match get_redis_conn(&self.redis).await {
Ok(c) => c,
Err(_) => return None,
};
let key = format!("hb:last:{}", symbol);
let raw: Option<String> = conn.get(&key).await.ok()?;
raw.and_then(|s| serde_json::from_str::<Tick>(&s).ok())
}
/// Публикуем тик в Redis — вспомогательный метод,
/// если захочешь где-то ещё генерировать тики.
///
/// Здесь пишем ТОЛЬКО в hb:ticks:{SYMBOL}, как "историю",
/// last по-хорошему должен писать монитор или отдельный парсер.
pub async fn publish_tick_to_redis(&self, tick: &Tick) {
if let Ok(mut conn) = get_redis_conn(&self.redis).await {
let key_list = format!("hb:ticks:{}", tick.symbol);
if let Ok(value) = serde_json::to_string(tick) {
let _: redis::RedisResult<i64> = conn.lpush(&key_list, &value).await;
// ограничиваем хвост до 1000 элементов
let _: redis::RedisResult<i64> = conn.ltrim(&key_list, 0, 999).await;
}
}
}
}