aboutsummaryrefslogtreecommitdiff
path: root/core/src/service/cli_addition/runtime_consoles.rs
blob: 2b2984b83f26b7de0f68fa8b28a3c9adf415f819 (plain) (blame)
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
use crate::service::cli_addition::utils::read_cli;
use clap::{Command, FromArgMatches};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use log::{info, warn};
use tokio::{join, select, spawn};
use tokio::signal::ctrl_c;
use tokio::time::sleep;
use crate::service::service_runner::NoGamepadsService;

pub struct RuntimeConsole<PadService, Cmd> where Cmd: FromArgMatches {
    command: Command,
    prefix: String,
    service: Arc<Mutex<PadService>>,
    process_command: fn(Arc<Mutex<PadService>>, Cmd) -> bool,
    check_close: fn(rt: Arc<Mutex<PadService>>) -> bool,
    close: fn(rt: Arc<Mutex<PadService>>),
}

impl<PadService, Cmd> RuntimeConsole<PadService, Cmd>
where PadService: Send + 'static, Cmd: FromArgMatches + 'static {
    pub fn build(command: Command,
                 prefix: String,
                 service: Arc<Mutex<PadService>>,
                 process_command: fn(Arc<Mutex<PadService>>, Cmd) -> bool,
                 check_close: fn(rt: Arc<Mutex<PadService>>) -> bool,
                 close: fn(rt: Arc<Mutex<PadService>>),
    ) -> RuntimeConsole<PadService, Cmd> {
        RuntimeConsole { command, prefix, service, process_command, check_close, close }
    }

    pub fn build_entry(self) -> NoGamepadsService {
        let arc = Arc::new(self);
        let entry = async move {
            let console_main = spawn({
                let console = Arc::clone(&arc);
                async move {
                    Self::console_main(console).await
                }
            });

            // Join
            let _ = join!(console_main);
        };

        Box::pin(entry)
    }

    async fn console_main(self: Arc<RuntimeConsole<PadService, Cmd>>) {
        let prefix_uppercase = self.prefix.to_uppercase();
        let prefix_lowercase = self.prefix.to_lowercase();
        let mut confirm_close = false;

        loop {
            select! {
                // Auto check
                _ = Self::auto_check_close(self.clone()) => { break; },

                // Ctrl + C
                _ = ctrl_c() => {
                    if !confirm_close {
                        warn!("To close the process, press Ctrl + C again.");
                        confirm_close = true;
                    } else {
                        (self.close)(self.service.clone());
                        break;
                    }
                }

                // Command Line
                option = read_cli(
                    format!("{}> ", prefix_uppercase),
                    &prefix_lowercase,
                    self.command.clone()
                ) => {
                    match option {
                        None => {}
                        Some(cmd) => {
                            confirm_close = false;
                            if !(self.process_command)(Arc::clone(&self.service), cmd) { break; }
                        }
                    }
                }
            }
        }
        info!("[Console] Shutdown.")
    }

    async fn auto_check_close(self: Arc<RuntimeConsole<PadService, Cmd>>) {
        loop {
            sleep(Duration::from_secs(1)).await;
            if (self.check_close)(Arc::clone(&self.service)) { break; }
        }
    }
}