diff --git a/Cargo.lock b/Cargo.lock index cbfb439..63b3441 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.4" @@ -448,6 +463,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets", +] + [[package]] name = "cipher" version = "0.3.0" @@ -653,8 +681,18 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core 0.20.3", + "darling_macro 0.20.3", ] [[package]] @@ -671,17 +709,42 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.38", +] + [[package]] name = "darling_macro" version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ - "darling_core", + "darling_core 0.14.4", "quote", "syn 1.0.109", ] +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core 0.20.3", + "quote", + "syn 2.0.38", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -704,6 +767,15 @@ dependencies = [ "const-oid", ] +[[package]] +name = "deranged" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +dependencies = [ + "serde", +] + [[package]] name = "derive_builder" version = "0.11.2" @@ -719,7 +791,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" dependencies = [ - "darling", + "darling 0.14.4", "proc-macro2", "quote", "syn 1.0.109", @@ -1190,6 +1262,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hkdf" version = "0.12.3" @@ -1305,6 +1383,29 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1841,6 +1942,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "mod_use" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95ee98a292cf91c2f5b3f35424773af16842a68b3be33b389137606b2633539" + [[package]] name = "mozjpeg" version = "0.10.5" @@ -2003,6 +2110,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -2255,6 +2371,40 @@ dependencies = [ "unicase", ] +[[package]] +name = "qbit-rs" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb4e7f851472565b5de97dd7f8d3ab68b9570d45e26029af058a717ba7246eee" +dependencies = [ + "mod_use", + "reqwest", + "serde", + "serde-value", + "serde_json", + "serde_repr", + "serde_with", + "tap", + "thiserror", + "tracing", + "typed-builder", + "url", +] + +[[package]] +name = "qbittorrent" +version = "0.1.0" +dependencies = [ + "anyhow", + "env_logger", + "log", + "matrix_bot_core", + "qbit-rs", + "serde", + "tokio", + "toml 0.8.2", +] + [[package]] name = "qoi" version = "0.4.1" @@ -2647,6 +2797,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_bytes" version = "0.11.12" @@ -2688,6 +2848,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "serde_spanned" version = "0.6.3" @@ -2709,6 +2880,34 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "base64 0.13.1", + "chrono", + "hex", + "indexmap 1.9.3", + "serde", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling 0.20.3", + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "sha2" version = "0.9.9" @@ -2916,6 +3115,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.8.0" @@ -2980,6 +3185,34 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +dependencies = [ + "deranged", + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -3189,6 +3422,17 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typed-builder" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cba322cb9b7bc6ca048de49e83918223f35e7a86311267013afff257004870" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "typenum" version = "1.17.0" @@ -3244,6 +3488,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -3486,6 +3731,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 0470f84..e56bd04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ # plugins "plugins/yande_popular", "plugins/webhook", + "plugins/qbittorrent", ] resolver = "2" diff --git a/plugins/qbittorrent/Cargo.toml b/plugins/qbittorrent/Cargo.toml new file mode 100644 index 0000000..aa5d49c --- /dev/null +++ b/plugins/qbittorrent/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "qbittorrent" +version = "0.1.0" +edition = "2021" + + +[dependencies] +anyhow = "1" +matrix_bot_core = { path = "../../matrix_bot_core" } +log = "0.4.14" +toml = "0.8.2" +serde = { version = "1.0.188", features = ["derive"] } +tokio = { version = "1.33.0", default-features = false, features = [] } +qbit-rs = { version = "0.3.7" } + +[dev-dependencies] +env_logger = "0.10.0" diff --git a/plugins/qbittorrent/src/lib.rs b/plugins/qbittorrent/src/lib.rs new file mode 100644 index 0000000..19b4797 --- /dev/null +++ b/plugins/qbittorrent/src/lib.rs @@ -0,0 +1,16 @@ +use anyhow::Result; +use matrix_bot_core::matrix::client::Client; + +mod qbit; +mod setting; + +#[allow(unused_variables)] +pub async fn run(client: Client, plugin_folder: impl AsRef) -> Result<()> { + log::info!("start yande_popular"); + + let setting = setting::get_or_init(plugin_folder)?; + + if setting.use_internal_qbit {} + + Ok(()) +} diff --git a/plugins/qbittorrent/src/qbit/binary.rs b/plugins/qbittorrent/src/qbit/binary.rs new file mode 100644 index 0000000..ed92c17 --- /dev/null +++ b/plugins/qbittorrent/src/qbit/binary.rs @@ -0,0 +1,21 @@ +use anyhow::Result; + +#[allow(dead_code)] +fn get_download_link() -> Result { + if !(cfg!(target_os = "linux")) { + return Err(anyhow::anyhow!("only support linux")); + } + + let mut link = + "https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/".to_string(); + if cfg!(target_arch = "x86_64") { + link.push_str("x86_64-qbittorrent-nox"); + } else if cfg!(target_arch = "aarch64") { + link.push_str("aarch64-qbittorrent-nox"); + } else if cfg!(target_arch = "x86") { + link.push_str("x86-qbittorrent-nox"); + } else { + return Err(anyhow::anyhow!("only support x86_64 and aarch64")); + } + Ok(link) +} diff --git a/plugins/qbittorrent/src/qbit/mod.rs b/plugins/qbittorrent/src/qbit/mod.rs new file mode 100644 index 0000000..96eab66 --- /dev/null +++ b/plugins/qbittorrent/src/qbit/mod.rs @@ -0,0 +1 @@ +pub mod binary; diff --git a/plugins/qbittorrent/src/setting.rs b/plugins/qbittorrent/src/setting.rs new file mode 100644 index 0000000..c9839ff --- /dev/null +++ b/plugins/qbittorrent/src/setting.rs @@ -0,0 +1,56 @@ +use std::path::{Path, PathBuf}; + +use anyhow::Result; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Setting { + pub room_setting: Vec, + pub qbit_user: String, + pub qbit_pass: String, + pub qbit_url: String, + pub use_internal_qbit: bool, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct RoomSetting { + pub download_path: PathBuf, + pub file_size_limit: u128, + pub room_id: String, + pub db_path: PathBuf, +} + +pub fn get_or_init(path: impl AsRef) -> Result { + let setting_path = path.as_ref().join("qbittorrent.toml"); + // load setting, if not exists, create it and exit + let setting = if !setting_path.exists() { + log::info!("create setting file: {}", setting_path.to_string_lossy()); + let setting = Setting { + room_setting: vec![RoomSetting { + download_path: path.as_ref().join("qbittorrent").join("download"), + file_size_limit: 0, + room_id: "".to_string(), + db_path: path.as_ref().join("qbittorrent").join("db"), + }], + qbit_user: "admin".to_string(), + qbit_pass: "adminadmin".to_string(), + qbit_url: "http://127.0.0.1:8080".to_string(), + use_internal_qbit: true, + }; + let toml = toml::to_string_pretty(&setting).unwrap(); + std::fs::write(&setting_path, toml)?; + log::error!( + "please edit setting file: {}", + setting_path.to_string_lossy() + ); + return Err(anyhow::anyhow!( + "please edit setting file: {}", + setting_path.to_string_lossy() + )); + } else { + log::info!("load setting file: {}", setting_path.to_string_lossy()); + let toml = std::fs::read_to_string(&setting_path)?; + toml::from_str(&toml)? + }; + Ok(setting) +} diff --git a/plugins/webhook/src/lib.rs b/plugins/webhook/src/lib.rs index 7e7c7d0..000358c 100644 --- a/plugins/webhook/src/lib.rs +++ b/plugins/webhook/src/lib.rs @@ -1,71 +1,37 @@ -use std::{collections::HashMap, net::SocketAddr, sync::OnceLock}; +use std::{collections::HashMap, net::SocketAddr}; use anyhow::Result; -use axum::{extract::Path, http::StatusCode, routing::post, Json, Router}; -use matrix_bot_core::matrix::{ - client::Client, - room::{self, Room}, +use axum::{ + extract::{Path, State}, + http::StatusCode, + routing::post, + Json, Router, }; -use serde::{Deserialize, Serialize}; +use matrix_bot_core::matrix::{client::Client, room::Room}; -#[derive(Debug, Deserialize, Serialize)] -struct Setting { - room_id: Vec, - token: Option, - port: u16, -} - -static ROOM: OnceLock> = OnceLock::new(); +use crate::setting::Setting; +mod setting; pub async fn run(client: Client, setting_folder: impl AsRef) -> Result<()> { log::info!("start webhook"); - let setting_path = setting_folder.as_ref().join("webhook.toml"); - - // load setting, if not exists, create it and exit - let setting: Setting = if !setting_path.exists() { - log::info!("create setting file: {}", setting_path.to_string_lossy()); - let settings = Setting { - room_id: vec!["".to_string()], - token: Some("123456".to_string()), - port: 0, - }; - let toml = toml::to_string_pretty(&settings).unwrap(); - std::fs::write(&setting_path, toml)?; - log::error!( - "please edit setting file: {}", - setting_path.to_string_lossy() - ); - return Err(anyhow::anyhow!( - "please edit setting file: {}", - setting_path.to_string_lossy() - )); - } else { - log::info!("load setting file: {}", setting_path.to_string_lossy()); - let toml = std::fs::read_to_string(&setting_path)?; - toml::from_str(&toml)? - }; - - // map to hashmap for easy access - // key: room_id Value: Room - let mut setting_map = HashMap::new(); - for room_id in setting.room_id { - let room = room::Room::new(&client, &room_id).await?; - setting_map.insert(room_id, room); - } - ROOM.get_or_init(|| setting_map); + let setting = Setting::get_or_init(setting_folder)?; + let token = setting.token.clone(); + let port = setting.port; + let setting = setting.to_hashmap(&client).await?; - let mut app: Router = Router::new() + let mut app = Router::new() .route("/send/:room_id", post(send)) - .fallback(not_found); + .fallback(not_found) + .with_state(setting); - if let Some(token) = &setting.token { + if let Some(token) = &token { app = app.layer(tower_http::validate_request::ValidateRequestHeaderLayer::bearer(token)); } - log::info!("listen on {}", setting.port); + log::info!("listen on {}", port); - let addr = SocketAddr::from(([0, 0, 0, 0], setting.port)); + let addr = SocketAddr::from(([0, 0, 0, 0], port)); let server = axum::Server::bind(&addr).serve(app.into_make_service()); server.await.unwrap(); @@ -77,8 +43,11 @@ pub async fn run(client: Client, setting_folder: impl AsRef) -> struct Msg { msg: String, } -async fn send((Path(room_id), Json(msg)): (Path, Json)) -> StatusCode { - let room = ROOM.get().unwrap(); +async fn send( + State(room): State>, + Path(room_id): Path, + Json(msg): Json, +) -> StatusCode { if let Some(room) = room.get(&room_id) { log::info!("send msg: {}", msg.msg); match room.send_msg(&msg.msg, true).await { diff --git a/plugins/webhook/src/setting.rs b/plugins/webhook/src/setting.rs new file mode 100644 index 0000000..051e058 --- /dev/null +++ b/plugins/webhook/src/setting.rs @@ -0,0 +1,52 @@ +use std::{collections::HashMap, path::Path}; + +use anyhow::Result; +use matrix_bot_core::matrix::{client::Client, room::Room}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Setting { + pub room_id: Vec, + pub token: Option, + pub port: u16, +} + +impl Setting { + pub async fn to_hashmap(self, client: &Client) -> Result> { + let mut hashmap = HashMap::new(); + for room_id in self.room_id { + let room = Room::new(&client, &room_id).await?; + hashmap.insert(room_id, room); + } + Ok(hashmap) + } + + pub fn get_or_init(path: impl AsRef) -> Result { + let setting_path = path.as_ref().join("webhook.toml"); + + // load setting, if not exists, create it and exit + let setting: Setting = if !setting_path.exists() { + log::info!("create setting file: {}", setting_path.to_string_lossy()); + let settings = Setting { + room_id: vec!["".to_string()], + token: Some("123456".to_string()), + port: 0, + }; + let toml = toml::to_string_pretty(&settings).unwrap(); + std::fs::write(&setting_path, toml)?; + log::error!( + "please edit setting file: {}", + setting_path.to_string_lossy() + ); + return Err(anyhow::anyhow!( + "please edit setting file: {}", + setting_path.to_string_lossy() + )); + } else { + log::info!("load setting file: {}", setting_path.to_string_lossy()); + let toml = std::fs::read_to_string(&setting_path)?; + toml::from_str(&toml)? + }; + Ok(setting) + } +} diff --git a/plugins/yande_popular/src/lib.rs b/plugins/yande_popular/src/lib.rs index 64657ba..e815a1d 100644 --- a/plugins/yande_popular/src/lib.rs +++ b/plugins/yande_popular/src/lib.rs @@ -1,78 +1,25 @@ -use std::{ - collections::HashMap, - hash::Hash, - path::{self, Path, PathBuf}, -}; +use std::path::Path; use anyhow::Result; -use matrix_bot_core::matrix::{client::Client, room}; -use serde::{Deserialize, Serialize}; +use matrix_bot_core::matrix::client::Client; + +use crate::setting::Setting; mod db; mod resize; +mod setting; mod yande; -#[derive(Debug, Deserialize, Serialize)] -struct Settings { - setting: Vec, -} - -#[derive(Debug, Deserialize, Serialize, Clone, Hash, Eq, PartialEq)] -struct Setting { - tmp_path: PathBuf, - db_path: PathBuf, - room_id: String, - resize: Option, - yande_url: Vec, -} - -pub async fn run(client: Client, setting_folder: impl AsRef) -> Result<()> { +pub async fn run(client: Client, plugin_folder: impl AsRef) -> Result<()> { log::info!("start yande_popular"); - let setting_path = setting_folder.as_ref().join("yande_popular.toml"); - - // load setting, if not exists, create it and exit - let settings: Settings = if !setting_path.exists() { - log::info!("create setting file: {}", setting_path.to_string_lossy()); - let settings = Settings { - setting: vec![Setting { - tmp_path: setting_folder.as_ref().join("yande_popular").join("tmp"), - db_path: setting_folder.as_ref().join("yande_popular").join("db"), - room_id: "".to_string(), - resize: Some(1920), - yande_url: vec!["https://yande.re/post/popular_recent".to_string()], - }], - }; - let toml = toml::to_string_pretty(&settings).unwrap(); - std::fs::write(&setting_path, toml)?; - log::error!( - "please edit setting file: {}", - setting_path.to_string_lossy() - ); - return Err(anyhow::anyhow!( - "please edit setting file: {}", - setting_path.to_string_lossy() - )); - } else { - log::info!("load setting file: {}", setting_path.to_string_lossy()); - let toml = std::fs::read_to_string(&setting_path)?; - toml::from_str(&toml)? - }; - // map to hashmap for easy access - // key: Setting Value: (DB, Room) - let mut settings_hash = HashMap::new(); - for setting in settings.setting { - let db = db::DB::open(&setting.db_path); - std::fs::create_dir_all(path::Path::new(&setting.tmp_path)).unwrap_or_else(|e| { - log::error!("create tmp dir failed: {}", e); - }); - let room = room::Room::new(&client, &setting.room_id).await?; - settings_hash.insert(setting.clone(), (db, room)); - } + let setting_hashmap = Setting::get_or_init(plugin_folder)? + .to_hashmap(&client) + .await?; loop { log::info!("start scan"); - for (setting, (db, room)) in settings_hash.iter() { + for (setting, (db, room)) in setting_hashmap.iter() { log::info!("scan: {}", setting.room_id); let mut image_list = Vec::new(); diff --git a/plugins/yande_popular/src/setting.rs b/plugins/yande_popular/src/setting.rs new file mode 100644 index 0000000..16b42db --- /dev/null +++ b/plugins/yande_popular/src/setting.rs @@ -0,0 +1,70 @@ +use std::{ + collections::HashMap, + path::{Path, PathBuf}, +}; + +use anyhow::Result; +use matrix_bot_core::matrix::{client::Client, room::Room}; +use serde::{Deserialize, Serialize}; + +use crate::db::DB; + +#[derive(Debug, Deserialize, Serialize, Clone, Hash, Eq, PartialEq)] +pub struct RoomSetting { + pub tmp_path: PathBuf, + pub db_path: PathBuf, + pub room_id: String, + pub resize: Option, + pub yande_url: Vec, +} +#[derive(Debug, Deserialize, Serialize)] +pub struct Setting { + room: Vec, +} + +impl Setting { + pub async fn to_hashmap(self, client: &Client) -> Result> { + let mut hashmap = HashMap::new(); + for setting in self.room { + let db = DB::open(&setting.db_path); + std::fs::create_dir_all(Path::new(&setting.tmp_path)).unwrap_or_else(|e| { + log::error!("create tmp dir failed: {}", e); + }); + let room = Room::new(&client, &setting.room_id).await?; + hashmap.insert(setting.clone(), (db, room)); + } + Ok(hashmap) + } + + pub fn get_or_init(path: impl AsRef) -> Result { + let setting_path = path.as_ref().join("yande_popular.toml"); + // load setting, if not exists, create it and exit + let settings: Self = if !setting_path.exists() { + log::info!("create setting file: {}", setting_path.to_string_lossy()); + let settings = Setting { + room: vec![RoomSetting { + tmp_path: path.as_ref().join("yande_popular").join("tmp"), + db_path: path.as_ref().join("yande_popular").join("db"), + room_id: "".to_string(), + resize: Some(1920), + yande_url: vec!["https://yande.re/post/popular_recent".to_string()], + }], + }; + let toml = toml::to_string_pretty(&settings).unwrap(); + std::fs::write(&setting_path, toml)?; + log::error!( + "please edit setting file: {}", + setting_path.to_string_lossy() + ); + return Err(anyhow::anyhow!( + "please edit setting file: {}", + setting_path.to_string_lossy() + )); + } else { + log::info!("load setting file: {}", setting_path.to_string_lossy()); + let toml = std::fs::read_to_string(&setting_path)?; + toml::from_str(&toml)? + }; + Ok(settings) + } +}