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
#[macro_use]
extern crate derive_more;
use chrono::NaiveDateTime;
use sqlx::{error::Error as DBError, SqlitePool};
use std::path::Path;
mod db;
mod event;
pub mod migration;
pub use event::*;
#[derive(Debug, Clone)]
pub struct Historian {
pool: SqlitePool,
}
impl Historian {
async fn raw_record(&self, script_id: i64, ty: &str, cmd: &str) -> Result<(), DBError> {
sqlx::query!(
"INSERT INTO events (script_id, type, cmd) VALUES(?, ?, ?)",
script_id,
ty,
cmd
)
.execute(&self.pool)
.await?;
Ok(())
}
pub async fn new(hyper_scripter_path: impl AsRef<Path>) -> Result<Self, DBError> {
db::get_pool(hyper_scripter_path)
.await
.map(|pool| Historian { pool })
}
pub async fn record(&self, event: Event<'_>) -> Result<(), DBError> {
log::debug!("記錄事件 {:?}", event);
let cmd = std::env::args().collect::<Vec<_>>().join(" ");
let ty = event.data.get_type().to_string();
match &event.data {
EventData::Miss => {
self.raw_record(event.script_id, &ty, &cmd).await?;
}
EventData::Read => {
self.raw_record(event.script_id, &ty, &cmd).await?;
}
EventData::Exec(content) => {
let mut content = Some(*content);
let last_event = sqlx::query!(
"SELECT content FROM events
WHERE type = ? AND script_id = ? AND NOT content IS NULL
ORDER BY time DESC LIMIT 1",
ty,
event.script_id
)
.fetch_optional(&self.pool)
.await?;
if let Some(last_event) = last_event {
if last_event.content.as_ref().map(|s| s.as_str()) == content {
log::debug!("上次執行內容相同,不重覆記錄");
content = None;
}
}
sqlx::query!(
"INSERT INTO events (script_id, type, cmd, content) VALUES(?, ?, ?, ?)",
event.script_id,
ty,
cmd,
content,
)
.execute(&self.pool)
.await?;
}
EventData::ExecDone(code) => {
let code = code.to_string();
sqlx::query!(
"INSERT INTO events (script_id, type, cmd, content) VALUES(?, ?, ?, ?)",
event.script_id,
ty,
cmd,
code
)
.execute(&self.pool)
.await?;
}
}
Ok(())
}
pub async fn last_time_of(&self, ty: EventType) -> Result<Vec<(i64, NaiveDateTime)>, DBError> {
let ty = ty.to_string();
let records = sqlx::query_as(
"
SELECT e.script_id, MAX(e.time) as time FROM events e
WHERE type = ?
GROUP BY e.script_id ORDER BY script_id
",
)
.bind(ty)
.fetch_all(&self.pool)
.await?;
Ok(records)
}
}