summaryrefslogtreecommitdiffstats
path: root/tedge/src/lib.rs
blob: b20bff9ca69a3503e76846923e8fad72c04ef303 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#![doc = include_str!("../README.md")]

use miette::IntoDiagnostic;
use tracing::debug;
use tracing::error;
use tracing::info;

use tedge_core::TedgeApplication;
use tedge_core::TedgeApplicationCancelSender;

pub mod cli;
pub mod config;
pub mod logging;
mod registry;

pub use crate::registry::Registry;

pub async fn run_app(args: crate::cli::Cli, registry: Registry) -> miette::Result<()> {
    match args.command {
        cli::CliCommand::Run { config } => {
            let (cancel_sender, application) =
                registry.app_builder.with_config_from_path(config).await?;
            info!("Application built");

            debug!("Verifying the configuration");
            application.verify_configurations().await?;

            debug!("Going to run the application");
            run(cancel_sender, application).await
        }
        cli::CliCommand::ValidateConfig { config } => {
            let (_, application) = registry.app_builder.with_config_from_path(config).await?;
            info!("Application built");

            debug!("Only going to validate the configuration");
            application.verify_configurations().await?;
            info!("Configuration validated");
            Ok(())
        }
        cli::CliCommand::GetPluginKinds => {
            use std::io::Write;

            let mut out = std::io::stdout();
            for name in registry.app_builder.plugin_kind_names() {
                writeln!(out, "{}", name).into_diagnostic()?;
            }
            Ok(())
        }
        cli::CliCommand::Doc { plugin_name } => {
            let mut registry = registry;
            if let Some(plugin_name) = plugin_name {
                let printer = registry
                    .doc_printers
                    .remove(&plugin_name)
                    .ok_or_else(|| miette::miette!("Plugin named '{}' not found", plugin_name))?;

                (printer)()?;
            } else {
                for printer in registry.doc_printers.into_values() {
                    printer()?;
                }
            }

            Ok(())
        }

        #[cfg(feature = "bugreport")]
        cli::CliCommand::BugReport => {
            use bugreport::collector::*;
            bugreport::bugreport!()
                .info(SoftwareVersion::default())
                .info(OperatingSystem::default())
                .info(CommandLine::default())
                .info(EnvironmentVariables::list(&["SHELL"]))
                .info(CompileTimeInformation::default())
                .print::<bugreport::format::Markdown>();
            Ok(())
        }
    }
}

async fn run(
    cancel_sender: TedgeApplicationCancelSender,
    application: TedgeApplication,
) -> miette::Result<()> {
    info!("Booting app now.");
    let mut run_fut = Box::pin(application.run());

    let kill_app = |fut| -> miette::Result<()> {
        error!("Killing application");
        drop(fut);
        miette::bail!("Application killed")
    };

    let res = tokio::select! {
        res = &mut run_fut => {
            res
        },

        _int = tokio::signal::ctrl_c() => {
            if !cancel_sender.is_cancelled() {
                info!("Shutting down...");
                cancel_sender.cancel_app();
                tokio::select! {
                    res = &mut run_fut => res,
                    _ = tokio::signal::ctrl_c() => return kill_app(run_fut),
                }
            } else {
                return kill_app(run_fut);
            }
        },
    };

    info!("Bye");
    Ok(res?)
}