sys/
sysmod.rs

1//! システムモジュール関連。
2
3pub mod camera;
4pub mod discord;
5pub mod health;
6pub mod http;
7pub mod line;
8pub mod openai;
9pub mod sysinfo;
10pub mod twitter;
11
12use self::{
13    camera::Camera, discord::Discord, health::Health, http::HttpServer, openai::OpenAi,
14    sysinfo::SystemInfo, twitter::Twitter,
15};
16use crate::{sysmod::line::Line, taskserver::Control};
17use anyhow::Result;
18use chrono::NaiveTime;
19use log::info;
20use std::sync::Arc;
21use tokio::sync::Mutex as TokioMutex;
22
23/// システムモジュールが実装するトレイト。
24pub trait SystemModule: Sync + Send {
25    /// [SystemModule] の初期化時には [crate::sys::taskserver::TaskServer] がまだ存在しないので
26    /// タスクの登録はこのタイミングまで遅延させる。
27    fn on_start(&mut self, _ctrl: &Control) {}
28}
29
30/// [SystemModules] 内の [SystemModule] はマルチスレッドにアクセスされるため、
31/// ロックが必要かつ await 可能。
32type SysModArc<T> = Arc<TokioMutex<T>>;
33
34/// タスクのエントリポイントに渡される引数からアクセス可能な [SystemModule] のリスト。
35/// デッドロックに注意。
36///
37/// ## デッドロックについて
38/// それぞれの [SystemModule] はアクセスする前にロックを取得する必要があるが、
39/// 複数同時にロックする場合、その順番に気を付けないと
40/// デッドロックを引き起こす可能性がある。
41pub struct SystemModules {
42    pub sysinfo: SysModArc<sysinfo::SystemInfo>,
43    pub health: SysModArc<health::Health>,
44    pub camera: SysModArc<camera::Camera>,
45    pub twitter: SysModArc<twitter::Twitter>,
46    pub discord: SysModArc<discord::Discord>,
47    pub line: SysModArc<line::Line>,
48    pub openai: SysModArc<openai::OpenAi>,
49    pub http: SysModArc<http::HttpServer>,
50
51    /// 全 [SystemModule] にイベントを配送するための参照のリストを作る。
52    event_target_list: Vec<SysModArc<dyn SystemModule>>,
53}
54
55impl SystemModules {
56    pub fn new() -> Result<SystemModules> {
57        info!("initialize system modules...");
58
59        let wakeup_health_ck: Vec<_> = (0..24)
60            .flat_map(|hour| (0..60).map(move |min| NaiveTime::from_hms_opt(hour, min, 0).unwrap()))
61            .collect();
62        let wakeup_health_tw = vec![
63            NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
64            NaiveTime::from_hms_opt(6, 0, 0).unwrap(),
65            NaiveTime::from_hms_opt(12, 0, 0).unwrap(),
66            NaiveTime::from_hms_opt(18, 0, 0).unwrap(),
67        ];
68
69        let wakeup_camera = vec![
70            NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
71            NaiveTime::from_hms_opt(3, 0, 0).unwrap(),
72            NaiveTime::from_hms_opt(6, 0, 0).unwrap(),
73            NaiveTime::from_hms_opt(9, 0, 0).unwrap(),
74            NaiveTime::from_hms_opt(12, 0, 0).unwrap(),
75            NaiveTime::from_hms_opt(15, 0, 0).unwrap(),
76            NaiveTime::from_hms_opt(18, 0, 0).unwrap(),
77            NaiveTime::from_hms_opt(21, 0, 0).unwrap(),
78        ];
79
80        let wakeup_twiter: Vec<_> = (0..24)
81            .flat_map(|hour| {
82                (0..60)
83                    .step_by(5)
84                    .map(move |min| NaiveTime::from_hms_opt(hour, min, 0).unwrap())
85            })
86            .collect();
87
88        let wakeup_discord: Vec<_> = (0..24)
89            .flat_map(|hour| {
90                (0..60)
91                    .step_by(10)
92                    .map(move |min| NaiveTime::from_hms_opt(hour, min, 0).unwrap())
93            })
94            .collect();
95
96        let mut event_target_list: Vec<SysModArc<dyn SystemModule>> = vec![];
97
98        let sysinfo = Arc::new(TokioMutex::new(SystemInfo::new()));
99        let health = Arc::new(TokioMutex::new(Health::new(
100            wakeup_health_ck,
101            wakeup_health_tw,
102        )?));
103        let camera = Arc::new(TokioMutex::new(Camera::new(wakeup_camera)?));
104        let twitter = Arc::new(TokioMutex::new(Twitter::new(wakeup_twiter)?));
105        let discord = Arc::new(TokioMutex::new(Discord::new(wakeup_discord)?));
106        let line = Arc::new(TokioMutex::new(Line::new()?));
107        let openai = Arc::new(TokioMutex::new(OpenAi::new()?));
108        let http = Arc::new(TokioMutex::new(HttpServer::new()?));
109
110        event_target_list.push(sysinfo.clone());
111        event_target_list.push(health.clone());
112        event_target_list.push(camera.clone());
113        event_target_list.push(twitter.clone());
114        event_target_list.push(discord.clone());
115        event_target_list.push(line.clone());
116        event_target_list.push(openai.clone());
117        event_target_list.push(http.clone());
118
119        info!("OK: initialize system modules");
120        Ok(Self {
121            sysinfo,
122            health,
123            camera,
124            twitter,
125            discord,
126            line,
127            openai,
128            http,
129            event_target_list,
130        })
131    }
132
133    pub async fn on_start(&self, ctrl: &Control) {
134        info!("invoke on_start for system modules...");
135        for sysmod in self.event_target_list.iter() {
136            sysmod.lock().await.on_start(ctrl);
137        }
138        info!("OK: invoke on_start for system modules");
139    }
140}