1
use std::path::PathBuf;
2

            
3
use anyhow::Context;
4
use clap::Parser;
5
use clap_verbosity_flag::Verbosity;
6
use systemd_journal_logger::JournalLog;
7

            
8
use crate::server::{
9
    config::{ServerConfigArgs, read_config_from_path_with_arg_overrides},
10
    supervisor::Supervisor,
11
    // server_loop::{
12
    //     listen_for_incoming_connections_with_socket_path,
13
    //     listen_for_incoming_connections_with_systemd_socket,
14
    // },
15
};
16

            
17
#[derive(Parser, Debug, Clone)]
18
pub struct ServerArgs {
19
    #[command(subcommand)]
20
    subcmd: ServerCommand,
21

            
22
    #[command(flatten)]
23
    config_overrides: ServerConfigArgs,
24

            
25
    #[arg(long)]
26
    systemd: bool,
27
}
28

            
29
#[derive(Parser, Debug, Clone)]
30
pub enum ServerCommand {
31
    #[command()]
32
    Listen,
33

            
34
    #[command()]
35
    SocketActivate,
36
}
37

            
38
const LOG_LEVEL_WARNING: &str = r#"
39
===================================================
40
== WARNING: LOG LEVEL IS SET TO 'TRACE'!         ==
41
== THIS WILL CAUSE THE SERVER TO LOG SQL QUERIES ==
42
== THAT MAY CONTAIN SENSITIVE INFORMATION LIKE   ==
43
== PASSWORDS AND AUTHENTICATION TOKENS.          ==
44
== THIS IS INTENDED FOR DEBUGGING PURPOSES ONLY  ==
45
== AND SHOULD *NEVER* BE USED IN PRODUCTION.     ==
46
===================================================
47
"#;
48

            
49
pub async fn handle_command(
50
    config_path: Option<PathBuf>,
51
    verbosity: Verbosity,
52
    args: ServerArgs,
53
) -> anyhow::Result<()> {
54
    let mut auto_detected_systemd_mode = false;
55
    let systemd_mode = args.systemd || {
56
        if let Ok(true) = sd_notify::booted() {
57
            auto_detected_systemd_mode = true;
58
            true
59
        } else {
60
            false
61
        }
62
    };
63
    if systemd_mode {
64
        JournalLog::new()
65
            .context("Failed to initialize journald logging")?
66
            .install()
67
            .context("Failed to install journald logger")?;
68

            
69
        log::set_max_level(verbosity.log_level_filter());
70

            
71
        if verbosity.log_level_filter() >= log::LevelFilter::Trace {
72
            log::warn!("{}", LOG_LEVEL_WARNING.trim());
73
        }
74

            
75
        if auto_detected_systemd_mode {
76
            log::info!("Running in systemd mode, auto-detected");
77
        } else {
78
            log::info!("Running in systemd mode");
79
        }
80

            
81
        // start_watchdog_thread_if_enabled();
82
    } else {
83
        env_logger::Builder::new()
84
            .filter_level(verbosity.log_level_filter())
85
            .init();
86

            
87
        log::info!("Running in standalone mode");
88
    }
89

            
90
    let config = read_config_from_path_with_arg_overrides(config_path, args.config_overrides)?;
91

            
92
    match args.subcmd {
93
        ServerCommand::Listen => Supervisor::new(config, systemd_mode).await?.run().await,
94
        ServerCommand::SocketActivate => {
95
            if !args.systemd {
96
                anyhow::bail!(concat!(
97
                    "The `--systemd` flag must be used with the `socket-activate` command.\n",
98
                    "This command currently only supports socket activation under systemd."
99
                ));
100
            }
101

            
102
            Supervisor::new(config, systemd_mode).await?.run().await
103
        }
104
    }
105
}
106

            
107
// fn start_watchdog_thread_if_enabled() {
108
//     let mut micro_seconds: u64 = 0;
109
//     let watchdog_enabled = sd_notify::watchdog_enabled(false, &mut micro_seconds);
110

            
111
//     if watchdog_enabled {
112
//         micro_seconds = micro_seconds.max(2_000_000).div_ceil(2);
113

            
114
//         tokio::spawn(async move {
115
//             log::debug!(
116
//                 "Starting systemd watchdog thread with {} millisecond interval",
117
//                 micro_seconds.div_ceil(1000)
118
//             );
119
//             loop {
120
//                 tokio::time::sleep(tokio::time::Duration::from_micros(micro_seconds)).await;
121
//                 if let Err(err) = sd_notify::notify(false, &[sd_notify::NotifyState::Watchdog]) {
122
//                     log::warn!("Failed to notify systemd watchdog: {}", err);
123
//                 } else {
124
//                     log::trace!("Ping sent to systemd watchdog");
125
//                 }
126
//             }
127
//         });
128
//     } else {
129
//         log::debug!("Systemd watchdog not enabled, skipping watchdog thread");
130
//     }
131
// }