gadget-sdk 0.6.2

SDK for building Blueprints and gadget on Tangle Network
Documentation
//! Quality of Service (QoS) reporting module.

#![allow(clippy::unused_async)]

use alloc::boxed::Box;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use async_trait::async_trait;
use core::time::Duration;

/// A trait for reporting the quality of service of a service.
///
/// The quality of service (QoS) is a measure of the performance of a service. It is used to determine
/// the quality of a service based on various metrics. With the [`DefaultQoSReporter`], those metrics
/// include uptime, response time, error rate, throughput, memory usage, and CPU usage.
#[async_trait]
pub trait QoSReporter {
    /// The type of metrics used to determine the quality of a service.
    type Metrics;
    /// A report describing the quality of a service.
    type ReportResult;
    /// The associated error which can be returned from the reporter.
    type Error;

    /// Collects the metrics for the service.
    ///
    /// # Errors
    ///
    /// Returns an error if the metrics could not be collected.
    async fn collect_metrics(&self) -> Result<Self::Metrics, Self::Error>;

    /// Generates the report for the service based on the collected metrics.
    ///
    /// # Errors
    ///
    /// Returns an error if the report could not be generated.
    async fn report(&self, metrics: &Self::Metrics) -> Result<Self::ReportResult, Self::Error>;
}

/// The default quality of service report.
#[derive(Debug, Clone)]
pub struct QoSReport {
    pub service_id: u64,
    pub block_number: u64,
    pub metrics: QoSMetrics,
    pub breached_metrics: Vec<String>,
    pub custom_report: Vec<u8>,
}

/// The default service metrics.
#[derive(Debug, Clone, Copy)]
pub struct QoSMetrics {
    pub uptime: Duration,
    pub response_time: Duration,
    pub error_rate: f64,
    pub throughput: u64,
    pub memory_usage: f64,
    pub cpu_usage: f64,
}

/// The default quality of service reporter.
#[derive(Debug, Clone, Copy)]
pub struct DefaultQoSReporter {
    pub service_id: u64,
}

#[async_trait]
impl QoSReporter for DefaultQoSReporter {
    type Metrics = QoSMetrics;
    type ReportResult = QoSReport;
    type Error = QoSError;

    async fn collect_metrics(&self) -> Result<QoSMetrics, QoSError> {
        collect_qos_metrics().await
    }

    async fn report(&self, metrics: &QoSMetrics) -> Result<QoSReport, QoSError> {
        let breached_metrics = check_breached_metrics(metrics);
        Ok(QoSReport {
            service_id: self.service_id,
            block_number: 0, // This should be updated with the actual block number
            metrics: *metrics,
            breached_metrics,
            custom_report: Vec::new(), // This should be updated based on your custom report logic
        })
    }
}

async fn collect_qos_metrics() -> Result<QoSMetrics, QoSError> {
    let uptime = get_service_uptime().await?;
    let response_time = measure_response_time().await?;
    let error_rate = calculate_error_rate().await?;
    let throughput = measure_throughput().await?;
    let memory_usage = get_memory_usage().await?;
    let cpu_usage = get_cpu_usage().await?;

    let metrics = QoSMetrics {
        uptime,
        response_time,
        error_rate,
        throughput,
        memory_usage,
        cpu_usage,
    };

    Ok(metrics)
}

fn check_breached_metrics(metrics: &QoSMetrics) -> Vec<String> {
    let mut breached = Vec::new();

    // These thresholds should be configurable
    if metrics.uptime < Duration::from_secs(3600) {
        breached.push("uptime".to_string());
    }
    if metrics.response_time > Duration::from_millis(500) {
        breached.push("response_time".to_string());
    }
    if metrics.error_rate > 0.05 {
        breached.push("error_rate".to_string());
    }
    if metrics.throughput < 100 {
        breached.push("throughput".to_string());
    }
    if metrics.memory_usage > 0.9 {
        breached.push("memory_usage".to_string());
    }
    if metrics.cpu_usage > 0.8 {
        breached.push("cpu_usage".to_string());
    }

    breached
}

async fn get_service_uptime() -> Result<Duration, QoSError> {
    // Implementation to get service uptime
    todo!()
}

async fn measure_response_time() -> Result<Duration, QoSError> {
    // Implementation to measure response time
    todo!()
}

async fn calculate_error_rate() -> Result<f64, QoSError> {
    // Implementation to calculate error rate
    todo!()
}

async fn measure_throughput() -> Result<u64, QoSError> {
    // Implementation to measure throughput
    todo!()
}

async fn get_memory_usage() -> Result<f64, QoSError> {
    // Implementation to get memory usage
    todo!()
}

async fn get_cpu_usage() -> Result<f64, QoSError> {
    // Implementation to get CPU usage
    todo!()
}

/// Error type for `QoS` reporting
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum QoSError {
    /// Failed to collect uptime metric.
    #[error("Failed to collect uptime: {0}")]
    UptimeError(String),
    /// Failed to measure response time.
    #[error("Failed to measure response time: {0}")]
    ResponseTimeError(String),
    /// Failed to calculate error rate.
    #[error("Failed to calculate error rate: {0}")]
    ErrorRateError(String),
    /// Failed to measure throughput.
    #[error("Failed to measure throughput: {0}")]
    ThroughputError(String),
    /// Failed to get memory usage.
    #[error("Failed to get memory usage: {0}")]
    MemoryUsageError(String),
    /// Failed to get CPU usage.
    #[error("Failed to get CPU usage: {0}")]
    CpuUsageError(String),
}