diff --git a/.gitignore b/.gitignore index 869df07..58b916b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target -Cargo.lock \ No newline at end of file +Cargo.lock +*.db +*.sqlite \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml index 58d5838..8d9310c 100644 --- a/.idea/dataSources.xml +++ b/.idea/dataSources.xml @@ -8,40 +8,11 @@ jdbc:postgresql://home.hzer.xyz:5432/postgres $ProjectFileDir$ - + sqlite.xerial true org.sqlite.JDBC - jdbc:sqlite:D:\dev\code\mine\home-api\database.sqlite - $ProjectFileDir$ - - - sqlite.xerial - true - org.sqlite.JDBC - jdbc:sqlite:D:\code\mine\rust\home-api\packages\gotify-ws\test.sqlite - $ProjectFileDir$ - - - sqlite.xerial - true - org.sqlite.JDBC - jdbc:sqlite:D:\code\mine\rust\home-api\database.sqlite - $ProjectFileDir$ - - - file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar - - - file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar - - - - - sqlite.xerial - true - org.sqlite.JDBC - jdbc:sqlite:D:\dev\code\mine\home-api\db.sqlite + jdbc:sqlite:D:\dev\code\mine\home-api\gotify.db $ProjectFileDir$ diff --git a/packages/gotify-ws/Cargo.toml b/packages/gotify-ws/Cargo.toml index c0c88a6..323da39 100644 --- a/packages/gotify-ws/Cargo.toml +++ b/packages/gotify-ws/Cargo.toml @@ -18,4 +18,5 @@ serde_json = "1.0.142" tokio = { version = "1.47.1", features = ["full"] } tokio-tungstenite = { version = "0.27.0", features = ["native-tls"] } regex = "1.11.1" -sea-orm = "1.1.14" \ No newline at end of file +sea-orm = { version = "1.1.14", features = ["sqlx-sqlite", "runtime-tokio-rustls", "macros"] } +chrono = "0.4.41" diff --git a/packages/gotify-ws/src/main.rs b/packages/gotify-ws/src/main.rs index 07f493c..c3b42c5 100644 --- a/packages/gotify-ws/src/main.rs +++ b/packages/gotify-ws/src/main.rs @@ -2,9 +2,11 @@ mod model; mod tests; mod utils; -use crate::model::ws::WsMessage; +use crate::model::ssh_connection::{ActiveModel, SSHConnection}; +use crate::utils::sql::sqlite; use futures::StreamExt; use log::{info, warn}; +use regex::Regex; use tokio_tungstenite::connect_async; use tokio_tungstenite::tungstenite::client::IntoClientRequest; use utils::logger; @@ -12,25 +14,42 @@ use utils::logger; #[tokio::main] async fn main() { logger::init_logger(); - let addr = "wss://home.hzer.xyz/gotify/stream?token=CDIwYlYJuxWxVr5".into_client_request().unwrap(); + let addr = "wss://home.hzer.xyz/gotify/stream?token=CDIwYlYJuxWxVr5" + .into_client_request() + .unwrap(); let (stream, _) = connect_async(addr.clone()).await.unwrap(); - // info!("Connected to Gotify server {addr}"); + info!("Connected to Gotify server {addr:?}"); + sqlite::init("./gotify.db".to_string()).await; + sqlite::create_ssh_connection_table().await; let (_, mut read) = stream.split(); + let ipv4_re: Regex = Regex::new(r"\b[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\b").expect("正则表达式错误"); + while let Some(msg) = read.next().await { match msg { Ok(msg) => { let str = msg.to_text().unwrap(); - info!("Got message: {}", str); + // info!("Got message: {}", str); if str.trim().is_empty() { info!("监听到心跳{}", &msg); continue; } - match serde_json::from_str::(str) { - Ok(ws) => { - info!("Got {} from Gotify", ws.message); + match serde_json::from_str::(str) { + Ok(mut conn) => { + // info!("Got {ws:?} from Gotify"); + + match ipv4_re.find(conn.message.as_str()) { + Some(ipv4) => { + info!("已记录ipv4地址{:?}", ipv4.as_str()); + conn.ip = Some(ipv4.as_str().to_string()); + sqlite::insert_into_ssh_connection(ActiveModel::from(conn)).await; + } + None => { + warn!("未检测到ipv4地址"); + } + } } Err(e) => { warn!("转换json失败{} -- {e}", &msg) diff --git a/packages/gotify-ws/src/model/mod.rs b/packages/gotify-ws/src/model/mod.rs index 4f18129..442ddfb 100644 --- a/packages/gotify-ws/src/model/mod.rs +++ b/packages/gotify-ws/src/model/mod.rs @@ -1,3 +1 @@ -pub mod ws; -pub mod student; -mod test; \ No newline at end of file +pub mod ssh_connection; \ No newline at end of file diff --git a/packages/gotify-ws/src/model/ssh_connection.rs b/packages/gotify-ws/src/model/ssh_connection.rs new file mode 100644 index 0000000..1f672ba --- /dev/null +++ b/packages/gotify-ws/src/model/ssh_connection.rs @@ -0,0 +1,29 @@ +use crate::utils::time::get_current_time; +use sea_orm::prelude::DeriveEntityModel; +use sea_orm::{ActiveModelBehavior, DeriveRelation, EnumIter}; +use sea_orm::{DerivePrimaryKey, PrimaryKeyTrait}; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "ssh_connection")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: u32, + pub ip: Option, + #[sea_orm(not_null)] + pub appid: i64, + pub message: String, + pub title: String, + pub priority: i64, + pub date: String, + #[serde(default = "get_current_time")] + pub create_at: String, + #[serde(default = "get_current_time")] + pub update_at: String, +} + +pub type SSHConnection = Model; + +#[derive(Debug, DeriveRelation, EnumIter)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/packages/gotify-ws/src/model/student.rs b/packages/gotify-ws/src/model/student.rs deleted file mode 100644 index 4d65c61..0000000 --- a/packages/gotify-ws/src/model/student.rs +++ /dev/null @@ -1,26 +0,0 @@ -use sea_orm::entity::prelude::*; - -#[derive(Debug, Clone, DeriveEntityModel)] -#[sea_orm(table_name = "student")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: u32, - pub name: String, - pub age: i32, - pub sex: Sex, - pub class: u8, - pub score: f32, -} - -#[derive(EnumIter, Copy, Clone, Debug, DeriveRelation)] -pub enum Relation {} -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] -#[sea_orm(rs_type = "String", db_type = "Text")] -pub enum Sex { - #[sea_orm(string_value = "male")] - Male, - #[sea_orm(string_value = "female")] - Female, -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/packages/gotify-ws/src/model/test/mod.rs b/packages/gotify-ws/src/model/test/mod.rs deleted file mode 100644 index 705a436..0000000 --- a/packages/gotify-ws/src/model/test/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod student; \ No newline at end of file diff --git a/packages/gotify-ws/src/model/test/student.rs b/packages/gotify-ws/src/model/test/student.rs deleted file mode 100644 index 5e4198e..0000000 --- a/packages/gotify-ws/src/model/test/student.rs +++ /dev/null @@ -1,32 +0,0 @@ -#[cfg(test)] -mod student { - use crate::model::student; - use log::info; - use sea_orm::{Database, DbBackend, Schema, sea_query::Table}; - - #[tokio::test] - async fn db_test() { - db_connect().await; - println!("-----------"); - } - - async fn db_connect() { - if let Ok(db) = Database::connect("test.sqlite").await { - println!("DB connected {db:?}"); - - let stmt = Table::create().table(student::Entity).if_not_exists(); - println!("{}",1); - } - } - - #[test] - fn print_sql() { - let db = DbBackend::Sqlite; - let schema = Schema::new(db); - - let stmt = schema.create_table_from_entity(student::Entity); - let sql = db.build(&stmt); - println!("sql print {}", sql.sql); - println!("-------------------------------------------------") - } -} diff --git a/packages/gotify-ws/src/model/ws.rs b/packages/gotify-ws/src/model/ws.rs deleted file mode 100644 index 4eaf407..0000000 --- a/packages/gotify-ws/src/model/ws.rs +++ /dev/null @@ -1,11 +0,0 @@ -use serde::Deserialize; - -#[derive(Debug, Deserialize, Clone, PartialEq)] -pub struct WsMessage { - id: u64, - appid: u64, - pub message: String, - title: String, - priority: u64, - date: String, -} diff --git a/packages/gotify-ws/src/utils/logger/mod.rs b/packages/gotify-ws/src/utils/logger/mod.rs index ee20910..f4896b2 100644 --- a/packages/gotify-ws/src/utils/logger/mod.rs +++ b/packages/gotify-ws/src/utils/logger/mod.rs @@ -1,5 +1,5 @@ use env_logger::{Builder, Env}; -pub fn init_logger(){ - Builder::from_env(Env::default().default_filter_or("info")).init(); -} \ No newline at end of file +pub fn init_logger() { + Builder::from_env(Env::default().default_filter_or("info")).init(); +} diff --git a/packages/gotify-ws/src/utils/mod.rs b/packages/gotify-ws/src/utils/mod.rs index 94df7ff..18f2d43 100644 --- a/packages/gotify-ws/src/utils/mod.rs +++ b/packages/gotify-ws/src/utils/mod.rs @@ -1,2 +1,3 @@ pub mod logger; -pub mod sql; \ No newline at end of file +pub mod sql; +pub mod time; diff --git a/packages/gotify-ws/src/utils/sql/mod.rs b/packages/gotify-ws/src/utils/sql/mod.rs index 0382ff2..e7d549c 100644 --- a/packages/gotify-ws/src/utils/sql/mod.rs +++ b/packages/gotify-ws/src/utils/sql/mod.rs @@ -1,2 +1,2 @@ pub mod sqlite; -mod tests; \ No newline at end of file +mod tests; diff --git a/packages/gotify-ws/src/utils/sql/sqlite/mod.rs b/packages/gotify-ws/src/utils/sql/sqlite/mod.rs index f0882c7..c45ab74 100644 --- a/packages/gotify-ws/src/utils/sql/sqlite/mod.rs +++ b/packages/gotify-ws/src/utils/sql/sqlite/mod.rs @@ -1,8 +1,60 @@ -// use sea_orm::Database; -// -// const ADDR: &str = "db.sqlite"; -// static mut db = async || { -// Database::connect(ADDR).await -// }; -// -// +use crate::model::ssh_connection::{ActiveModel, Entity}; +use log::{info, warn}; +use sea_orm::{ + ActiveModelTrait, ConnectionTrait, Database, DatabaseBackend, DatabaseConnection, Schema, +}; +use std::sync::OnceLock; + +static DB: OnceLock> = OnceLock::new(); +pub async fn init(addr: String) { + match Database::connect(format!("sqlite://{addr}?mode=rwc")).await { + Ok(db) => { + info!("连接数据库成功!"); + DB.get_or_init(|| Some(db)); + } + Err(e) => { + info!("连接数据库出错! {e:?}"); + } + } +} + +pub fn get_connection() -> DatabaseConnection { + let db = DB.get().expect("数据库未连接"); + db.clone().unwrap() +} + +/** + * 创建ssh_connection表 + */ +pub async fn create_ssh_connection_table() -> bool { + let db = get_connection(); + let statement = Schema::new(DatabaseBackend::Sqlite).create_table_from_entity(Entity); + let sql = db.get_database_backend().build(&statement); + + match db.execute(sql).await { + Ok(_) => { + info!("创建表成功!"); + true + } + Err(e) => { + warn!("创建表失败! {e:?}"); + false + } + } +} + +/** + * 插入数据 + */ +pub async fn insert_into_ssh_connection(model: ActiveModel) { + let db = get_connection(); + + match model.insert(&db).await { + Ok(_) => { + info!("插入数据成功!"); + } + Err(e) => { + warn!("插入数据失败! {e:?}"); + } + } +} diff --git a/packages/gotify-ws/src/utils/sql/tests/mod.rs b/packages/gotify-ws/src/utils/sql/tests/mod.rs index 80f2bb3..8e0367d 100644 --- a/packages/gotify-ws/src/utils/sql/tests/mod.rs +++ b/packages/gotify-ws/src/utils/sql/tests/mod.rs @@ -1 +1 @@ -mod sqlite; \ No newline at end of file +mod sqlite; diff --git a/packages/gotify-ws/src/utils/sql/tests/sqlite.rs b/packages/gotify-ws/src/utils/sql/tests/sqlite.rs index d3fdcdc..4852623 100644 --- a/packages/gotify-ws/src/utils/sql/tests/sqlite.rs +++ b/packages/gotify-ws/src/utils/sql/tests/sqlite.rs @@ -1,32 +1,43 @@ -// #[cfg(test)] -// mod sqlite_test { -// use std::fs::remove_file; -// use std::path::Path; -// -// use crate::utils::sql::sqlite::SqliteDB; -// -// #[test] -// fn new_database() { -// let file_path: &str = "test.sqlite"; -// SqliteDB::new(&file_path).unwrap(); -// -// let file = Path::new(&file_path); -// assert!(file.exists()); -// -// if file.exists() { -// remove_file(file).unwrap(); -// } -// } -// -// #[test] -// fn create_table() { -// let file_path: &str = "test.sqlite"; -// let db = SqliteDB::new(&file_path).unwrap(); -// db.create_table(); -// drop(db.connection_pool); -// -// if Path::new(&file_path).exists() { -// remove_file(file_path).unwrap(); -// } -// } -// } +#[cfg(test)] +mod sqlite_test { + use crate::utils::logger::init_logger; + use crate::utils::sql::sqlite; + use crate::utils::sql::sqlite::create_ssh_connection_table; + use std::fs::remove_file; + use std::path::Path; + + static FILE_PATH: &str = "test.sqlite"; + #[test] + fn create_table() { + before_detail(); + create_ssh_connection_table(); + } + + #[test] + fn insert_data() { + create_table(); + // insert_into_ssh_connection(ActiveModel { + // id: ActiveValue::Set(2), + // appid: ActiveValue::Set(1), + // message: ActiveValue::Set("message".to_string()), + // title: ActiveValue::Set("title".to_string()), + // priority: ActiveValue::Set(1), + // data: ActiveValue::Set("{}".to_string()), + // create_at: ActiveValue::Set("2025-08-12T16:55:44+08:00".to_string()), + // update_at: ActiveValue::Set("2025-08-12T16:55:44+08:00".to_string()), + // }); + } + + fn before_detail() { + init_logger(); + sqlite::init(format!("sqlite://{}?mode=rwc", &FILE_PATH)); + } + + #[test] + pub fn after_detail() { + let file = Path::new(&FILE_PATH); + if file.exists() { + remove_file(file).unwrap(); + } + } +} diff --git a/packages/gotify-ws/src/utils/time/mod.rs b/packages/gotify-ws/src/utils/time/mod.rs new file mode 100644 index 0000000..0e4753b --- /dev/null +++ b/packages/gotify-ws/src/utils/time/mod.rs @@ -0,0 +1,6 @@ +use chrono::Local; + +pub fn get_current_time() -> String { + let time = Local::now(); + time.format("%Y-%m-%d %H:%M:%S").to_string() +}