modio-logger 0.5.2

modio-logger Dbus service
Documentation
// Author: D.S. Ljungmark <spider@skuggor.se>, Modio AB
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::error::Error;

use zbus::Connection;

use zbus::Guid;

use fsipc::legacy::fsipcProxy;
use fsipc::unixtime;

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!("{} is valid", valid_key),
        Ok(false) => {
            println!("{} is invalid", valid_key);
            panic!("Valid key is invalid");
        }
        Err(e) => {
            println!("{} gives error: {}", valid_key, e);
            return Err(e);
        }
    }

    let invalid_key = "modio..invalid";
    match ipc.valid_key(invalid_key).await {
        Ok(true) => {
            println!("{} is valid", invalid_key);
            panic!("Valid when it should not be");
        }
        Ok(false) => println!("{} is invalid", invalid_key),
        Err(e) => {
            println!("{} gives error: {}", invalid_key, 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;
    let guid1 = Guid::generate(); // Transactions "id" are either a UUID or an timestamp-as-string
    match ipc
        .transaction_add(key, first, second, guid1.as_str())
        .await
    {
        Ok(_) => println!("Adding Transaction: {}   {}=>{}", key, first, second),
        Err(e) => println!("Error: {}", e),
    }
    let guid2 = Guid::generate();
    match ipc
        .transaction_add(key, first, second, guid2.as_str())
        .await
    {
        Ok(_) => println!("Adding Transaction: {}   {}=>{}", key, first, second),
        Err(e) => println!("Error: {}", e),
    }
    let guid3 = Guid::generate();
    match ipc
        .transaction_add(key, first, second, guid3.as_str())
        .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 = Guid::generate();
        match ipc
            .transaction_add(key, first, second, guid4.as_str())
            .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.get(0) {
                    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>> {
    env_logger::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(())
}