mirror of
https://github.com/csehviktor/status-monitor.git
synced 2026-04-28 08:17:35 +02:00
99 lines
2.8 KiB
Rust
99 lines
2.8 KiB
Rust
use async_trait::async_trait;
|
|
use chrono::{DateTime, Utc};
|
|
use common::{MQTT_SEND_INTERVAL, StatusMessage};
|
|
use memory::InMemoryRepository;
|
|
use rusqlite::Row;
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlite::SQLiteRepository;
|
|
use std::sync::Arc;
|
|
|
|
pub mod memory;
|
|
pub mod sqlite;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct UptimeStorageModel {
|
|
pub id: String,
|
|
pub first_seen: DateTime<Utc>,
|
|
pub last_seen: DateTime<Utc>,
|
|
pub message_count: u64,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct UptimeMessage {
|
|
pub agent: String,
|
|
pub uptime: f64,
|
|
pub last_seen: DateTime<Utc>,
|
|
}
|
|
|
|
impl Into<UptimeMessage> for UptimeStorageModel {
|
|
fn into(self) -> UptimeMessage {
|
|
let duration = Utc::now().signed_duration_since(self.first_seen);
|
|
let expected_messages = duration.num_seconds() as f64 / MQTT_SEND_INTERVAL as f64;
|
|
|
|
let uptime_pct = (self.message_count as f64 / expected_messages * 100.0).min(100.0);
|
|
|
|
UptimeMessage {
|
|
agent: self.id,
|
|
uptime: uptime_pct,
|
|
last_seen: self.last_seen,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&Row<'_>> for UptimeStorageModel {
|
|
type Error = rusqlite::Error;
|
|
|
|
fn try_from(row: &Row) -> Result<Self, Self::Error> {
|
|
let first_seen: DateTime<Utc> = row.get::<_, String>(1)?.parse().map_err(|e| {
|
|
rusqlite::Error::FromSqlConversionFailure(1, rusqlite::types::Type::Text, Box::new(e))
|
|
})?;
|
|
|
|
let last_seen: DateTime<Utc> = row.get::<_, String>(2)?.parse().map_err(|e| {
|
|
rusqlite::Error::FromSqlConversionFailure(2, rusqlite::types::Type::Text, Box::new(e))
|
|
})?;
|
|
|
|
Ok(UptimeStorageModel {
|
|
id: row.get(0)?,
|
|
first_seen,
|
|
last_seen,
|
|
message_count: row.get(1)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
pub trait StorageRepository: Send + Sync {
|
|
async fn record_message(&self, message: &StatusMessage) -> anyhow::Result<()>;
|
|
async fn record_uptime(&self, agent: &str) -> anyhow::Result<()>;
|
|
async fn get_history(
|
|
&self,
|
|
agent: &str,
|
|
duration: Option<DateTime<Utc>>,
|
|
) -> anyhow::Result<Vec<StatusMessage>>;
|
|
async fn get_agents(&self) -> anyhow::Result<Vec<UptimeMessage>>;
|
|
}
|
|
|
|
pub enum StorageStrategy {
|
|
InMemory,
|
|
SQLite(String),
|
|
}
|
|
|
|
pub struct StorageRepositoryImpl {
|
|
inner: Arc<dyn StorageRepository>,
|
|
}
|
|
|
|
impl StorageRepositoryImpl {
|
|
pub fn new(strategy: StorageStrategy) -> Self {
|
|
let inner: Arc<dyn StorageRepository> = match strategy {
|
|
StorageStrategy::InMemory => Arc::new(InMemoryRepository::new()),
|
|
StorageStrategy::SQLite(path) => Arc::new(SQLiteRepository::new(path)),
|
|
};
|
|
|
|
Self { inner }
|
|
}
|
|
|
|
pub fn inner(&self) -> Arc<dyn StorageRepository> {
|
|
self.inner.clone()
|
|
}
|
|
}
|