modio-logger 0.11.1

modio-logger Dbus service
Documentation
// Author: D.S. Ljungmark <spider@skuggor.se>, Modio AB
// SPDX-License-Identifier: AGPL-3.0-or-later
#![allow(clippy::print_stdout)]
use fsipc::legacy::fsipcProxy;
use fsipc::unixtime;
use std::error::Error;
use zbus::Connection;

async fn printlast(ipc: &fsipcProxy<'_>, key: &str) {
    match ipc.retrieve(key).await {
        Ok(data) => println!("{}= {} @{}", data.key, data.value, data.timestamp),
        Err(e) => println!("Err retrieving: {key}  : {e}"),
    }
}

async fn get_points(ipc: &fsipcProxy<'_>) -> zbus::Result<()> {
    println!("Retrieving all data points");
    let res = ipc.retrieve_all().await?;
    for measure in &res {
        println!("Fetching {measure}");
        match ipc.retrieve(&measure.key).await {
            Ok(data) => {
                println!("Got: {data}");
                assert_eq!(data.key, measure.key);
            }
            Err(e) => {
                println!("Retrieve error: {e:?}");
                return Err(e);
            }
        }
    }
    Ok(())
}

async fn valid_invalid(ipc: &fsipcProxy<'_>) -> zbus::Result<()> {
    let valid_key = "modio.software.development";

    match ipc.valid_key(valid_key).await {
        Ok(true) => println!("{valid_key} is valid"),
        Ok(false) => {
            println!("{valid_key} is invalid");
            panic!("Valid key is invalid");
        }
        Err(e) => {
            println!("{valid_key} gives error: {e}");
            return Err(e);
        }
    }

    let invalid_key = "modio..invalid";
    match ipc.valid_key(invalid_key).await {
        Ok(true) => {
            println!("{invalid_key} is valid");
            panic!("Valid when it should not be");
        }
        Ok(false) => println!("{invalid_key} is invalid"),
        Err(e) => {
            println!("{invalid_key} gives error: {e}");
            return Err(e);
        }
    }
    Ok(())
}

async fn transaction_test(ipc: &fsipcProxy<'_>) -> zbus::Result<()> {
    let key = "test.test.one";
    let first = "first";
    let mut our_value = "first";
    let second = "second";

    printlast(ipc, key).await;
    match ipc.store(key, our_value).await {
        Ok(_) => println!("stored {key} = {our_value}"),
        Err(e) => println!("Error: {e}"),
    }
    printlast(ipc, key).await;
    let when = unixtime();
    match ipc.store_with_time(key, our_value, when).await {
        Ok(_) => println!("Store with time: {key}={our_value} @{when}"),
        Err(e) => println!("Store with time failed: {e}"),
    }
    printlast(ipc, key).await;

    // Transactions "id" are either a UUID or an timestamp-as-string
    let guid1 = "d62f250a-090d-4e20-bcf9-86ad29647dd1";
    match ipc.transaction_add(key, first, second, guid1).await {
        Ok(_) => println!("Adding Transaction: {key}   {first}=>{second}"),
        Err(e) => println!("Error: {e}"),
    }
    let guid2 = "1744124217";
    match ipc.transaction_add(key, first, second, guid2).await {
        Ok(_) => println!("Adding Transaction: {key}   {first}=>{second}"),
        Err(e) => println!("Error: {e}"),
    }
    let guid3 = "8a0f5a3d-bf64-4bb1-96d5-500a6d983b47";
    match ipc.transaction_add(key, first, second, guid3).await {
        Ok(_) => println!("Adding Transaction: {key}   {first}=>{second}"),
        Err(e) => println!("Error: {e}"),
    }
    println!("Fetching transaction for: {key}");
    match ipc.transaction_get(key).await {
        Ok(transactions) => {
            // The "id" here is an internal ID in the current logger instance, not the same as
            // our GUID ID we entered above.
            for trn in &transactions {
                if our_value == trn.expected {
                    println!(
                        "{}({}):  {} == {}, changing to  {}, ok",
                        trn.key, trn.t_id, trn.expected, our_value, trn.target
                    );
                    our_value = &trn.target;
                    match ipc.transaction_pass(trn.t_id).await {
                        Ok(_) => println!("marked passed"),
                        Err(e) => println!("error: {e}"),
                    }
                } else {
                    println!(
                        "{}({}):  {} != {},  failing",
                        trn.key, trn.t_id, our_value, trn.expected
                    );
                    match ipc.transaction_fail(trn.t_id).await {
                        Ok(_) => println!("marked failed"),
                        Err(e) => println!("error: {e}"),
                    }
                }
                ipc.store(key, our_value).await?;
            }
        }
        Err(e) => println!("Error in transaction_get: {e}"),
    }
    printlast(ipc, key).await;
    Ok(())
}

async fn double_transactions(ipc: &fsipcProxy<'_>) -> zbus::Result<()> {
    println!("Attempting double transactions");
    {
        let key = "test.test.one";
        let first = "first";
        let second = "second";

        let guid4 = "cfdccd25-8c0f-4935-a37c-90e29bc832f1";
        match ipc.transaction_add(key, first, second, guid4).await {
            Ok(_) => println!("Added transaction: {key}, {first}=>{second}"),
            Err(e) => println!("Error: {e}"),
        }
        match ipc.transaction_get(key).await {
            Err(e) => println!("Error in transaction_get: {e}"),
            Ok(transactions) => {
                if let Some(val) = transactions.first() {
                    println!("Received transaction: {}, t_id={}", val, val.t_id);

                    println!("About to pass t_id={}", val.t_id);
                    match ipc.transaction_pass(val.t_id).await {
                        Ok(_) => println!("pass1 of t_id={} success", val.t_id),
                        Err(e) => println!("pass1 of t_id={} fail: {}", val.t_id, e),
                    }

                    println!("About to pass t_id={}", val.t_id);
                    match ipc.transaction_pass(val.t_id).await {
                        Ok(_) => println!("pass2 of t_id={} success when it should not!", val.t_id),
                        Err(e) => println!("pass2 of t_id={} fail: as expected! {}", val.t_id, e),
                    }
                }
            }
        };
    }
    Ok(())
}

#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {
    tracing_subscriber::fmt().init();

    let connection = Connection::session().await?;
    let ipc = fsipcProxy::new(&connection).await?;

    printlast(&ipc, "hello.world").await;
    get_points(&ipc).await?;
    valid_invalid(&ipc).await?;
    transaction_test(&ipc).await?;
    double_transactions(&ipc).await?;
    Ok(())
}