working system
This commit is contained in:
parent
1afa975c6a
commit
2a5c13306e
13 changed files with 597 additions and 484 deletions
274
Cargo.lock
generated
274
Cargo.lock
generated
|
@ -88,6 +88,12 @@ version = "0.21.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -109,6 +115,16 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
|
@ -191,9 +207,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "command_attr"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f08c85a02e066b7b4f7dcb60eee6ae0793ef7d6452a3547d1f19665df070a9"
|
||||
checksum = "88da8d7e9fe6f30d8e3fcf72d0f84102b49de70fece952633e8439e89bdc7631"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -640,15 +656,6 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "info"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nopalmo",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.9.0"
|
||||
|
@ -670,6 +677,12 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "levenshtein"
|
||||
version = "1.0.5"
|
||||
|
@ -714,6 +727,15 @@ version = "0.4.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
|
||||
[[package]]
|
||||
name = "luau0-src"
|
||||
version = "0.10.2+luau635"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8bd6bc70c84fdd4e89b71b528f7ab7db7b97adf759faa8dbe15c5011468e290"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.2"
|
||||
|
@ -772,17 +794,55 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d111deb18a9c9bd33e1541309f4742523bfab01d276bfa9a27519f6de9c11dc7"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"futures-util",
|
||||
"libloading",
|
||||
"mlua-sys",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mlua-sys"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ab7a5b4756b8177a2dfa8e0bbcde63bd4000afbc4ab20cbb68d114a25470f29"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"luau0-src",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nopalmo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libloading",
|
||||
"phf",
|
||||
"mlua",
|
||||
"rand",
|
||||
"regex",
|
||||
"serenity",
|
||||
"sqlite",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -815,6 +875,12 @@ version = "1.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.2"
|
||||
|
@ -844,48 +910,6 @@ version = "2.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||
dependencies = [
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
|
@ -898,6 +922,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
|
@ -1013,7 +1043,7 @@ version = "0.11.27"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
|
@ -1072,6 +1102,12 @@ version = "0.1.24"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.34"
|
||||
|
@ -1117,7 +1153,7 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1206,6 +1242,15 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_cow"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7bbbec7196bfde255ab54b65e34087c0849629280028238e67ee25d6a4b7da"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.202"
|
||||
|
@ -1242,13 +1287,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serenity"
|
||||
version = "0.12.1"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c64da29158bb55d70677cacd4f4f8eab1acef005fb830d9c3bea411b090e96a9"
|
||||
checksum = "880a04106592d0a8f5bdacb1d935889bfbccb4a14f7074984d9cd857235d34ac"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"async-trait",
|
||||
"base64",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.5.0",
|
||||
"bytes",
|
||||
"chrono",
|
||||
|
@ -1264,6 +1309,7 @@ dependencies = [
|
|||
"reqwest",
|
||||
"secrecy",
|
||||
"serde",
|
||||
"serde_cow",
|
||||
"serde_json",
|
||||
"static_assertions",
|
||||
"time",
|
||||
|
@ -1287,6 +1333,15 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
|
@ -1296,12 +1351,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||
|
||||
[[package]]
|
||||
name = "skeptic"
|
||||
version = "0.13.7"
|
||||
|
@ -1348,6 +1397,34 @@ version = "0.9.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "sqlite"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfe6fb16f2bee6452feeb4d12bfa404fbcd3cfc121b2950e501d1ae9cae718e"
|
||||
dependencies = [
|
||||
"sqlite3-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlite3-src"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "174d4a6df77c27db281fb23de1a6d968f3aaaa4807c2a1afa8056b971f947b4a"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlite3-sys"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3901ada7090c3c3584dc92ec7ef1b7091868d13bfe6d7de9f0bcaffee7d0ade5"
|
||||
dependencies = [
|
||||
"sqlite3-src",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
|
@ -1447,6 +1524,16 @@ dependencies = [
|
|||
"syn 2.0.65",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.36"
|
||||
|
@ -1608,6 +1695,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"nu-ansi-term",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1744,6 +1858,12 @@ version = "0.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4bf03e0ca70d626ecc4ba6b0763b934b6f2976e8c744088bb3c1d646fbb1ad0"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
@ -1879,6 +1999,22 @@ dependencies = [
|
|||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.8"
|
||||
|
@ -1888,6 +2024,12 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
|
|
28
Cargo.toml
28
Cargo.toml
|
@ -3,28 +3,20 @@ name = "nopalmo"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
[lib]
|
||||
name = "nopalmo_lib"
|
||||
path = "src/lib/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nopalmo"
|
||||
path = "src/main.rs"
|
||||
|
||||
[workspace]
|
||||
members = ["commands/info"]
|
||||
|
||||
[dependencies]
|
||||
libloading = "0.8.5"
|
||||
phf = { version = "0.11.2", features = ["phf_macros"] }
|
||||
rand = "0.8.5"
|
||||
regex = "1.10.4"
|
||||
# rs-cord = { git = "https://github.com/jay3332/rs-cord" }
|
||||
serenity = "0.12.1"
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["chrono"] }
|
||||
|
||||
rand = "0.8.5"
|
||||
regex = "1.10.4"
|
||||
sqlite = { version = "0.36.1", features = ["bundled"] }
|
||||
|
||||
mlua = { version = "0.9.9", features = ["async", "luau"] }
|
||||
serenity = "0.12.1"
|
||||
|
||||
[features]
|
||||
|
||||
# slated for removal, originally this engine was going to be a multipurpose and publicly available bot, however plans change and im limiting the scope
|
||||
nsfw_features = []
|
||||
premium_features = []
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
[package]
|
||||
name = "info"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.39.2", features = ["full"] }
|
||||
tracing = "0.1.40"
|
||||
nopalmo = { path = "../../" }
|
|
@ -1,43 +0,0 @@
|
|||
use nopalmo_lib::PluginError;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::task;
|
||||
|
||||
type AsyncFn = Box<dyn Fn() -> task::JoinHandle<Result<(), PluginError>> + Send + Sync>;
|
||||
|
||||
static FUNCTION_MAP: ::std::sync::OnceLock<Arc<Mutex<HashMap<String, AsyncFn>>>> =
|
||||
::std::sync::OnceLock::new();
|
||||
|
||||
#[allow(improper_ctypes_definitions)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn register_functions(function_map: Arc<Mutex<HashMap<String, AsyncFn>>>) {
|
||||
if let Err(_) = FUNCTION_MAP.set(Arc::clone(&function_map)) {
|
||||
tracing::error!("Could not set function map oncelock in `info` plugin.");
|
||||
return;
|
||||
}
|
||||
|
||||
let example_function: AsyncFn = Box::new(|| {
|
||||
task::spawn(async {
|
||||
tracing::info!("example_function is running");
|
||||
// Simulate some async work
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
||||
tracing::info!("example_function completed");
|
||||
// Return an error for demonstration
|
||||
Err(PluginError::FunctionError(
|
||||
"Something went wrong".to_string(),
|
||||
))
|
||||
})
|
||||
});
|
||||
|
||||
function_map
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert("example_function".to_string(), example_function);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn unregister_functions() {
|
||||
if let Some(function_map) = FUNCTION_MAP.get() {
|
||||
function_map.lock().unwrap().remove("example_function");
|
||||
}
|
||||
}
|
75
src/arguments.rs
Normal file
75
src/arguments.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct ArgumentStorage {
|
||||
// arguments: Vec<Argument>,
|
||||
long_key_to_id: HashMap<String, Arc<Argument>>,
|
||||
short_key_to_id: HashMap<String, Arc<Argument>>,
|
||||
}
|
||||
|
||||
impl ArgumentStorage {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn add(&mut self, argument: Argument) {
|
||||
let argument = Arc::new(argument);
|
||||
|
||||
if let Some(long) = argument.long_name {
|
||||
self.long_key_to_id
|
||||
.insert(long.to_string(), argument.clone());
|
||||
}
|
||||
if let Some(short) = argument.short_name {
|
||||
self.long_key_to_id.insert(short.to_string(), argument);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, long: Option<String>, short: Option<String>) {
|
||||
match (long, short) {
|
||||
(None, None) => todo!(), // what
|
||||
(None, Some(short_key)) => {
|
||||
let argument = self.short_key_to_id.remove(&short_key);
|
||||
|
||||
if let Some(argument) = argument {
|
||||
if let Some(long_name) = argument.long_name {
|
||||
self.long_key_to_id.remove(long_name);
|
||||
}
|
||||
} // TODO case where name is invalid?
|
||||
}
|
||||
(Some(long_key), None) => {
|
||||
let argument = self.long_key_to_id.remove(&long_key);
|
||||
|
||||
if let Some(argument) = argument {
|
||||
if let Some(short_name) = argument.short_name {
|
||||
self.short_key_to_id.remove(short_name);
|
||||
}
|
||||
} // TODO case where name is invalid?
|
||||
}
|
||||
(Some(long_key), Some(short_key)) => {
|
||||
self.long_key_to_id.remove(&long_key);
|
||||
self.short_key_to_id.remove(&short_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Argument {
|
||||
pub pretty_name: &'static str,
|
||||
// we will use usize as an argument id system, the arguments will be available inside the argument cache
|
||||
// the bool is for if its required or not
|
||||
pub sub_arguments: Vec<(ArgumentContainer, bool)>,
|
||||
pub requires_prefix: bool,
|
||||
|
||||
pub wildcard_name: Option<&'static str>,
|
||||
pub long_name: Option<&'static str>, // change to vec?
|
||||
pub short_name: Option<&'static str>, // change to vec?
|
||||
// /// use 0 for any position, 1 or more for positionals
|
||||
// pub position: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum ArgumentContainer {
|
||||
Value(String),
|
||||
Argument(usize),
|
||||
}
|
139
src/commands.rs
Normal file
139
src/commands.rs
Normal file
|
@ -0,0 +1,139 @@
|
|||
use std::{fmt::Debug, time::Duration};
|
||||
|
||||
use serenity::all::{Context, GuildId, Message, Permissions};
|
||||
|
||||
use crate::arguments::{Argument, ArgumentStorage};
|
||||
|
||||
// pub type DmCommand = fn(Context, Message);
|
||||
// pub type GuildCommand = fn(Context, Message, GuildId);
|
||||
|
||||
pub enum CommandFnKind {
|
||||
Lua(()),
|
||||
Rust(fn(Context, Message, Option<GuildId>)),
|
||||
}
|
||||
|
||||
pub struct Command {
|
||||
pub run_dm_command: Option<CommandFnKind>,
|
||||
pub run_guild_command: Option<CommandFnKind>,
|
||||
pub aliases: Vec<String>,
|
||||
pub pretty_name: Option<String>,
|
||||
pub name: String,
|
||||
pub command_category: Option<String>,
|
||||
pub help: Option<String>,
|
||||
// pub usage: String, // will be calculated from arguments automatically
|
||||
pub timeout: Option<Duration>, // TODO make this dynamic?
|
||||
pub hidden: bool,
|
||||
|
||||
pub arguments: ArgumentStorage,
|
||||
pub required_caller_discord_permissions: ::serenity::all::Permissions,
|
||||
|
||||
#[cfg(feature = "nsfw_features")]
|
||||
pub is_nsfw: bool,
|
||||
#[cfg(feature = "premium_features")]
|
||||
pub premium_kind: usize,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn new(name: String) -> Self {
|
||||
Self {
|
||||
run_dm_command: None,
|
||||
run_guild_command: None,
|
||||
aliases: vec![],
|
||||
pretty_name: None,
|
||||
name,
|
||||
hidden: false,
|
||||
command_category: None,
|
||||
help: None,
|
||||
timeout: None,
|
||||
arguments: ArgumentStorage::new(),
|
||||
required_caller_discord_permissions: Permissions::empty(),
|
||||
#[cfg(feature = "nsfw_features")]
|
||||
is_nsfw: false,
|
||||
#[cfg(feature = "premium_features")]
|
||||
premium_kind: 0,
|
||||
}
|
||||
}
|
||||
pub fn dm_command(mut self, dm_command: CommandFnKind) -> Self {
|
||||
self.run_dm_command = Some(dm_command);
|
||||
self
|
||||
}
|
||||
pub fn guild_command(mut self, guild_command: CommandFnKind) -> Self {
|
||||
self.run_guild_command = Some(guild_command);
|
||||
self
|
||||
}
|
||||
pub fn pretty_name(mut self, pretty_name: String) -> Self {
|
||||
self.pretty_name = Some(pretty_name);
|
||||
self
|
||||
}
|
||||
// pub fn name(mut self, name: String) -> Self {
|
||||
// self.name = name;
|
||||
// self
|
||||
// }
|
||||
pub fn alias(mut self, alias: String) -> Self {
|
||||
self.aliases.push(alias);
|
||||
self
|
||||
}
|
||||
pub fn aliases(mut self, aliases: &mut Vec<String>) -> Self {
|
||||
self.aliases.append(aliases);
|
||||
self
|
||||
}
|
||||
pub fn category(mut self, category: String) -> Self {
|
||||
self.command_category = Some(category);
|
||||
self
|
||||
}
|
||||
pub fn help(mut self, help: String) -> Self {
|
||||
self.help = Some(help);
|
||||
self
|
||||
}
|
||||
pub fn timeout(mut self, timeout: Duration) -> Self {
|
||||
self.timeout = Some(timeout);
|
||||
self
|
||||
}
|
||||
pub fn argument(mut self, argument: Argument) -> Self {
|
||||
self.arguments.add(argument);
|
||||
self
|
||||
}
|
||||
pub fn hidden(mut self, hidden: bool) -> Self {
|
||||
self.hidden = hidden;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Command {}
|
||||
unsafe impl Send for Command {}
|
||||
|
||||
impl Debug for Command {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut binding = f.debug_struct("Command");
|
||||
binding
|
||||
.field(
|
||||
"run_dm_command",
|
||||
&::std::any::type_name_of_val(&self.run_dm_command),
|
||||
)
|
||||
.field(
|
||||
"run_guild_command",
|
||||
&::std::any::type_name_of_val(&self.run_guild_command),
|
||||
)
|
||||
.field("aliases", &self.aliases)
|
||||
.field("name", &self.name)
|
||||
.field("pretty_name", &self.pretty_name)
|
||||
.field("command_type", &self.command_category)
|
||||
.field("help", &self.help)
|
||||
.field("hidden", &self.hidden)
|
||||
// .field("usage", &self.usage)
|
||||
.field("timeout", &self.timeout)
|
||||
.field("arguments", &self.arguments)
|
||||
.field("permissions", &self.required_caller_discord_permissions);
|
||||
#[cfg(feature = "nsfw_features")]
|
||||
binding.field("is_nsfw", &self.is_nsfw);
|
||||
#[cfg(feature = "premium_features")]
|
||||
binding.field("premium_kind", &self.premium_kind);
|
||||
binding.finish()
|
||||
}
|
||||
}
|
||||
|
||||
// impl Default for Command {
|
||||
// fn default() -> Self {
|
||||
|
||||
// }
|
||||
// }
|
|
@ -1,109 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct ArgumentStorage {
|
||||
arguments: Vec<Argument>,
|
||||
long_key_to_id: HashMap<String, usize>,
|
||||
short_key_to_id: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
impl ArgumentStorage {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn add(&mut self, long: Option<String>, short: Option<String>, argument: Argument) {
|
||||
let mut index = None;
|
||||
for i in 0..self.arguments.len() {
|
||||
if self.arguments.get(i).is_none() {
|
||||
index = Some(i);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(index) = index {
|
||||
self.arguments[index] = argument;
|
||||
|
||||
if let Some(long) = long {
|
||||
self.long_key_to_id.insert(long, index);
|
||||
}
|
||||
if let Some(short) = short {
|
||||
self.long_key_to_id.insert(short, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, long: Option<String>, short: Option<String>) {
|
||||
|
||||
match (long, short) {
|
||||
(None, None) => todo!(),
|
||||
(None, Some(short_key)) => {
|
||||
let short_index = *self.short_key_to_id.get(&short_key).unwrap();
|
||||
self.short_key_to_id.remove(&short_key);
|
||||
|
||||
let mut long_to_remove = None;
|
||||
|
||||
for (long_key, long_index) in &self.long_key_to_id {
|
||||
// hate cloning here but i couldnt figure out how to avoid it
|
||||
if short_index == *long_index {
|
||||
long_to_remove = Some(long_key.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(long_to_remove) = long_to_remove {
|
||||
self.long_key_to_id.remove(&long_to_remove);
|
||||
}
|
||||
}
|
||||
(Some(long_key), None) => {
|
||||
let long_index = *self.long_key_to_id.get(&long_key).unwrap();
|
||||
self.long_key_to_id.remove(&long_key);
|
||||
|
||||
let mut short_to_remove = None;
|
||||
|
||||
for (short_key, short_index) in &self.short_key_to_id {
|
||||
// hate cloning here but i couldnt figure out how to avoid it
|
||||
if long_index == *short_index {
|
||||
short_to_remove = Some(short_key.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(short_to_remove) = short_to_remove {
|
||||
self.short_key_to_id.remove(&short_to_remove);
|
||||
}
|
||||
}
|
||||
(Some(long_key), Some(short_key)) => {
|
||||
|
||||
|
||||
|
||||
self.long_key_to_id.remove(&long_key);
|
||||
self.short_key_to_id.remove(&short_key);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ArgumentKind {
|
||||
Short,
|
||||
Long,
|
||||
WildCard,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Argument {
|
||||
pub pretty_name: &'static str,
|
||||
// we will use usize as an argument id system, the arguments will be available inside the argument cache
|
||||
// the bool is for if its required or not
|
||||
pub sub_arguments: Vec<(ArgumentContainer, bool)>,
|
||||
pub requires_prefix: bool,
|
||||
|
||||
pub long_name: Option<&'static str>, // change to vec?
|
||||
pub short_name: Option<&'static str>, // change to vec?
|
||||
// /// use 0 for any position, 1 or more for positionals
|
||||
// pub position: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum ArgumentContainer {
|
||||
Value(String),
|
||||
Argument(usize)
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
use std::{fmt::Debug, time::Duration};
|
||||
|
||||
pub mod arguments;
|
||||
|
||||
use arguments::ArgumentStorage;
|
||||
use serenity::all::{Context, GuildId, Message};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PluginError {
|
||||
FunctionError(String),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for PluginError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
PluginError::FunctionError(msg) => write!(f, "Function error: {}", msg),
|
||||
PluginError::Other(msg) => write!(f, "Other error: {}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for PluginError {}
|
||||
|
||||
pub struct Command<DMC, GMC, CommandReturn> {
|
||||
pub run_dm_command: Box<dyn Fn(&DMC, Context, Message) -> CommandReturn>,
|
||||
pub run_guild_command: Box<dyn Fn(&GMC, Context, Message, GuildId) -> CommandReturn>,
|
||||
pub aliases: Vec<String>,
|
||||
pub name: String,
|
||||
pub command_category: String,
|
||||
pub help: String,
|
||||
pub usage: String,
|
||||
pub timeout: Duration, // TODO make this dynamic?
|
||||
|
||||
pub arguments: ArgumentStorage,
|
||||
pub required_caller_discord_permissions: ::serenity::all::Permissions,
|
||||
|
||||
#[cfg(feature = "nsfw_features")]
|
||||
pub is_nsfw: bool,
|
||||
#[cfg(feature = "premium_features")]
|
||||
pub premium_kind: usize,
|
||||
}
|
||||
|
||||
unsafe impl<DMC, GMC, CommandReturn> Sync for Command<DMC, GMC, CommandReturn> {}
|
||||
unsafe impl<DMC, GMC, CommandReturn> Send for Command<DMC, GMC, CommandReturn> {}
|
||||
|
||||
impl<DMC, GMC, CommandReturn> Debug for Command<DMC, GMC, CommandReturn> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut binding = f.debug_struct("Command");
|
||||
binding
|
||||
.field(
|
||||
"run_dm_command",
|
||||
&::std::any::type_name_of_val(&self.run_dm_command),
|
||||
)
|
||||
.field(
|
||||
"run_guild_command",
|
||||
&::std::any::type_name_of_val(&self.run_guild_command),
|
||||
)
|
||||
.field("aliases", &self.aliases)
|
||||
.field("name", &self.name)
|
||||
.field("command_type", &self.command_category)
|
||||
.field("help", &self.help)
|
||||
.field("usage", &self.usage)
|
||||
.field("timeout", &self.timeout)
|
||||
.field("arguments", &self.arguments)
|
||||
.field("permissions", &self.required_caller_discord_permissions);
|
||||
#[cfg(feature = "nsfw_features")]
|
||||
binding.field("is_nsfw", &self.is_nsfw);
|
||||
#[cfg(feature = "premium_features")]
|
||||
binding.field("premium_kind", &self.premium_kind);
|
||||
binding.finish()
|
||||
}
|
||||
}
|
274
src/main.rs
274
src/main.rs
|
@ -2,88 +2,51 @@
|
|||
#![deny(clippy::expect_used)]
|
||||
#![deny(clippy::pedantic)]
|
||||
|
||||
//#![feature(async_fn_traits)]
|
||||
|
||||
// mod commands;
|
||||
// use nopalmo_lib;
|
||||
|
||||
mod arguments;
|
||||
mod commands;
|
||||
mod constants;
|
||||
// mod permissions;
|
||||
mod system_messages;
|
||||
mod tasks;
|
||||
|
||||
// use ::std::collections::hash_map::HashMap;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Condvar, OnceLock};
|
||||
|
||||
// use std::error::Error;
|
||||
// use std::future::Future;
|
||||
// use std::pin::Pin;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
// use std::sync::Arc;
|
||||
// use std::time::Duration;
|
||||
|
||||
// use discord_permissions::DiscordPermission;
|
||||
// use nopalmo_lib::Command;
|
||||
// use serenity::all::GuildId;
|
||||
// use commands::Command;
|
||||
use commands::Command;
|
||||
use metadata::LevelFilter;
|
||||
use serenity::all::{ActivityData, Context, GuildId, ShardManager};
|
||||
use serenity::all::{EventHandler, GatewayIntents};
|
||||
use serenity::model::channel::Message;
|
||||
use serenity::model::gateway::Ready;
|
||||
use serenity::prelude::*;
|
||||
// use tokio::sync::mpsc;
|
||||
|
||||
// type DMCommandArguments = Handler;
|
||||
// type GCommandArguments = Handler;
|
||||
// pub type CommandReturn = Pin<Box<dyn Future<Output = ()>>>;
|
||||
// pub type CommandReturn = ();
|
||||
|
||||
|
||||
// pub mod discord_permissions;
|
||||
|
||||
// use self::arguments::Argument;
|
||||
use ::serenity::all::Context;
|
||||
|
||||
// use discord_permissions::DiscordPermission;
|
||||
|
||||
// #[cfg(feature = "premium_features")]
|
||||
// pub enum PremiumLevel {
|
||||
// Free,
|
||||
// Tier1,
|
||||
// Tier2,
|
||||
// Tier3,
|
||||
// Super,
|
||||
// }
|
||||
|
||||
// pub enum CommandType {
|
||||
// General,
|
||||
// Moderation,
|
||||
// Fun,
|
||||
// Info,
|
||||
// Extra,
|
||||
// Unknown,
|
||||
// }
|
||||
use serenity::Client;
|
||||
use tracing::*;
|
||||
|
||||
// pub const CAT_DEV: &'static str = "Dev";
|
||||
pub const CAT_FUN: &'static str = "Fun";
|
||||
pub const CAT_MOD: &'static str = "Moderation";
|
||||
pub const CAT_GEN: &'static str = "General";
|
||||
pub const CAT_INF: &'static str = "Info";
|
||||
pub const CAT_HID: &'static str = "Hidden";
|
||||
|
||||
static SHARD_MANAGER: OnceLock<Arc<ShardManager>> = OnceLock::new();
|
||||
// static SHARDS_READY: AtomicBool = AtomicBool::new(false);
|
||||
static DO_SHUTDOWN: (AtomicBool, Condvar) = (AtomicBool::new(false), Condvar::new()); // atombool and condvar combo to ensure maximum coverage when the bot needs to power off
|
||||
|
||||
struct Handler {
|
||||
// TODO use data field instead?
|
||||
// system_sender: Mutex<mpsc::Sender<system_messages::SystemMessage>>,
|
||||
// system_receiver: Mutex<mpsc::Receiver<system_messages::SystemMessage>>,
|
||||
do_shutdown: AtomicBool,
|
||||
// task_count: AtomicUsize,
|
||||
// command_map: ::std::collections::hash_map::HashMap<
|
||||
// String,
|
||||
// Arc<Command<DMCommandArguments, GCommandArguments, CommandReturn>>,
|
||||
// >,
|
||||
commands: HashMap<String, Command>,
|
||||
}
|
||||
|
||||
unsafe impl Sync for Handler {}
|
||||
unsafe impl Send for Handler {}
|
||||
|
||||
// unsafe impl Sync for CommandReturn {}
|
||||
// unsafe impl Send for CommandReturn {}
|
||||
|
||||
#[serenity::async_trait]
|
||||
impl EventHandler for Handler {
|
||||
async fn message(&self, ctx: Context, msg: Message) {
|
||||
// We do not reply to bots https://en.wikipedia.org/wiki/Email_storm
|
||||
if msg.author.bot {
|
||||
return;
|
||||
}
|
||||
|
||||
let prefix_regex = format!(
|
||||
r"^({}|{}|<@{}>)\s?",
|
||||
constants::COMMAND_PREFIX,
|
||||
|
@ -100,7 +63,7 @@ impl EventHandler for Handler {
|
|||
None => return, // silently exit because not every message is meant for the bot
|
||||
};
|
||||
|
||||
if self.do_shutdown.load(std::sync::atomic::Ordering::SeqCst) {
|
||||
if DO_SHUTDOWN.0.load(Ordering::SeqCst) {
|
||||
let _ = msg
|
||||
.channel_id
|
||||
.say(
|
||||
|
@ -113,34 +76,70 @@ impl EventHandler for Handler {
|
|||
|
||||
let target_cmd_name = regex::Regex::new(prefix_regex.as_str())
|
||||
.unwrap()
|
||||
.replace(result.as_str(), "");
|
||||
|
||||
dbg!(&target_cmd_name);
|
||||
.replace(result.as_str(), "")
|
||||
.to_string();
|
||||
|
||||
msg.reply(&ctx.http, target_cmd_name.to_string())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
//if let Some(command) = self.command_map.get(target_cmd_name) {
|
||||
// if let Some(guild_id) = msg.guild_id {
|
||||
// (command.run_guild_command)(&self, ctx, msg, guild_id);
|
||||
// } else {
|
||||
// (command.run_dm_command)(&self, ctx, msg);
|
||||
// }
|
||||
//}
|
||||
if let Some(command) = self.commands.get(&target_cmd_name) {
|
||||
if let Some(guild_id) = msg.guild_id {
|
||||
if let Some(run_guild_command) = &command.run_guild_command {
|
||||
match run_guild_command {
|
||||
commands::CommandFnKind::Lua(_) => todo!(),
|
||||
commands::CommandFnKind::Rust(cmd) => (cmd)(ctx, msg, Some(guild_id)),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(run_dm_command) = &command.run_dm_command {
|
||||
match run_dm_command {
|
||||
commands::CommandFnKind::Lua(_) => todo!(),
|
||||
commands::CommandFnKind::Rust(cmd) => (cmd)(ctx, msg, None),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn ready(&self, _: Context, ready: Ready) {
|
||||
println!("Shart `{}` is connected!", ready.shard.unwrap().id);
|
||||
/// Runs once for every shard once its ready
|
||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||
info!("Shart `{}` is connected!", ready.shard.unwrap().id);
|
||||
ctx.set_activity(Some(ActivityData::custom("Initializing.")))
|
||||
}
|
||||
|
||||
/// Runs once when all shards are ready
|
||||
async fn shards_ready(&self, ctx: Context, total_shards: u32) {
|
||||
tasks::start_tasks(ctx).await;
|
||||
info!("{total_shards} shards ready.");
|
||||
}
|
||||
|
||||
// Runs once for every shard when its cache is ready
|
||||
async fn cache_ready(&self, _ctx: Context, _guild_id_list: Vec<GuildId>) {
|
||||
info!("Cache ready.");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing::subscriber::set_global_default(
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(LevelFilter::INFO)
|
||||
.finish(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// TODO load this at runtime so the key will not be stored in the binary?
|
||||
#[cfg(not(debug_assertions))]
|
||||
let token = include_str!("bot_token.prod");
|
||||
let token = {
|
||||
info!("Initializing bot with production token.");
|
||||
include_str!("bot_token.prod")
|
||||
};
|
||||
#[cfg(debug_assertions)]
|
||||
let token = include_str!("bot_token.dev");
|
||||
let token = {
|
||||
info!("Initializing bot with development token.");
|
||||
include_str!("bot_token.dev")
|
||||
};
|
||||
|
||||
let intents = GatewayIntents::DIRECT_MESSAGES
|
||||
| GatewayIntents::DIRECT_MESSAGE_REACTIONS
|
||||
|
@ -152,89 +151,64 @@ async fn main() {
|
|||
| GatewayIntents::GUILD_MESSAGES
|
||||
| GatewayIntents::MESSAGE_CONTENT;
|
||||
|
||||
// let (system_sender, system_receiver) = mpsc::channel(256);
|
||||
// let system_sender = Mutex::new(system_sender);
|
||||
// let system_receiver = Mutex::new(system_receiver);
|
||||
let mut commands = HashMap::default();
|
||||
|
||||
// let mut command_map = HashMap::new();
|
||||
|
||||
// fn ping_dm_run(handler: &Handler, ctx: Context, msg: Message) -> () {}
|
||||
// fn ping_guild_run(handler: &Handler, ctx: Context, msg: Message, guild_id: GuildId) -> () {
|
||||
// // MessageChannel channel = blob.getChannel();
|
||||
|
||||
// channel
|
||||
// .sendMessage("Pong!\n" + ctx. + "ms\n")
|
||||
// .queue();
|
||||
|
||||
// // if (argumentMap.get("all") != null) {
|
||||
|
||||
// // channel.sendMessage("Gathering data. . .").queue(msg -> {
|
||||
// // long timeToProcess = System.currentTimeMillis();
|
||||
|
||||
// // long jdaPing = blob.getJDA().getGatewayPing();
|
||||
// // long googlePing = -1;
|
||||
// // try {
|
||||
// // googlePing = UptimePing.sendPing("www.google.com");
|
||||
// // } catch (Exception e) {
|
||||
// // e.printStackTrace();
|
||||
// // }
|
||||
// // long discordPing = -1;
|
||||
// // try {
|
||||
// // discordPing = UptimePing.sendPing("www.discord.com");
|
||||
// // } catch (Exception e) {
|
||||
// // e.printStackTrace();
|
||||
// // }
|
||||
|
||||
// // String out = "Ping:\n"
|
||||
// // + (googlePing > 0 ? "Google: " + googlePing + "ms\n" : "Could not connect to www.google.com\n")
|
||||
// // + (discordPing > 0 ? "Discord: " + discordPing + "ms\n"
|
||||
// // : "Could not connect to www.discord.com\n")
|
||||
// // + "JDA-Discord heartbeat: " + jdaPing + "ms";
|
||||
|
||||
// // msg.editMessage(out + "\nTime to process: " + (System.currentTimeMillis() - timeToProcess) + "ms")
|
||||
// // .queue();
|
||||
// // });
|
||||
// // }
|
||||
// }
|
||||
|
||||
// command_map.insert(
|
||||
// "ping".to_owned(),
|
||||
// Arc::new(Command {
|
||||
// aliases: vec!["ping".to_owned()],
|
||||
// arguments: HashMap::new(),
|
||||
// command_type: nopalmo_lib::CommandType::General,
|
||||
// help: "Some help info".to_owned(),
|
||||
// name: "Ping".to_owned(),
|
||||
// usage: "ping".to_owned(),
|
||||
// permissions: vec![],
|
||||
// timeout: Duration::from_secs(0),
|
||||
// run_dm_command: Box::new(ping_dm_run),
|
||||
// run_guild_command: Box::new(ping_guild_run),
|
||||
// }),
|
||||
// );
|
||||
stock_commands::insert_all(&mut commands);
|
||||
|
||||
let mut client = match Client::builder(&token, intents)
|
||||
.event_handler(Handler {
|
||||
// system_receiver,
|
||||
// system_sender,
|
||||
do_shutdown: AtomicBool::new(false),
|
||||
// task_count: AtomicUsize::new(0),
|
||||
// command_map,
|
||||
})
|
||||
.event_handler(Handler { commands })
|
||||
.await
|
||||
{
|
||||
Ok(client) => client,
|
||||
Err(err) => panic!("Error starting client connection: `{err}`"),
|
||||
};
|
||||
|
||||
let status_timer = tokio::spawn(tasks::status_timer(
|
||||
client.shard_manager.runners.clone(),
|
||||
client.cache.clone(),
|
||||
));
|
||||
SHARD_MANAGER.set(client.shard_manager.clone()).unwrap();
|
||||
|
||||
if let Err(why) = client.start_shards(2).await {
|
||||
println!("Client error: {why:?}");
|
||||
error!("Client error: {why:?}");
|
||||
}
|
||||
|
||||
status_timer.abort();
|
||||
warn!("EXITING");
|
||||
}
|
||||
|
||||
mod stock_commands {
|
||||
use std::{collections::HashMap, sync::atomic::Ordering};
|
||||
|
||||
use serenity::all::{Context, GuildId, Message};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, CommandFnKind},
|
||||
CAT_HID, DO_SHUTDOWN, SHARD_MANAGER,
|
||||
};
|
||||
|
||||
pub fn insert_all(commands: &mut HashMap<String, Command>) {
|
||||
commands.insert(
|
||||
"stop".to_owned(),
|
||||
Command::new("stop".to_owned())
|
||||
.alias("svs".to_owned())
|
||||
.category(CAT_HID.to_owned())
|
||||
.hidden(true)
|
||||
.dm_command(CommandFnKind::Rust(stop_command))
|
||||
.guild_command(CommandFnKind::Rust(stop_command))
|
||||
.pretty_name("Stop the bot".to_owned())
|
||||
.help("Stops the bot. Does nothing unless you are a developer.".to_owned()),
|
||||
);
|
||||
}
|
||||
|
||||
fn stop_command(_: Context, msg: Message, _: Option<GuildId>) {
|
||||
// hardcode my id for now
|
||||
if msg.author.id != 380045419381784576 {
|
||||
return;
|
||||
}
|
||||
DO_SHUTDOWN.0.store(true, Ordering::SeqCst);
|
||||
DO_SHUTDOWN.1.notify_all();
|
||||
|
||||
let handle = tokio::runtime::Handle::current();
|
||||
let _eg = handle.enter();
|
||||
|
||||
handle.spawn(async {
|
||||
SHARD_MANAGER.get().unwrap().shutdown_all().await;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
pub enum SystemMessage {
|
||||
|
||||
}
|
52
src/tasks.rs
52
src/tasks.rs
|
@ -1,34 +1,64 @@
|
|||
use crate::constants;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use std::{
|
||||
sync::{Arc, LazyLock},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use ::std::collections::hash_map::HashMap;
|
||||
use rand::{distributions::uniform::SampleRange, rngs::OsRng};
|
||||
use serenity::all::{ActivityData, Cache, ShardId, ShardRunnerInfo};
|
||||
use tokio::sync::Mutex;
|
||||
use serenity::all::{ActivityData, Cache, Context, ShardId, ShardRunnerInfo};
|
||||
use tokio::{sync::Mutex, task::JoinHandle};
|
||||
use tracing::info;
|
||||
|
||||
static TASK_HANDLES: LazyLock<Arc<Mutex<TaskContainer>>> =
|
||||
LazyLock::new(|| Arc::new(Mutex::new(TaskContainer::default())));
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TaskContainer {
|
||||
pub misc: Vec<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
pub async fn start_tasks(ctx: Context) {
|
||||
info!("Starting MISC tasks.");
|
||||
|
||||
info!("Starting activity switcher task.");
|
||||
TASK_HANDLES
|
||||
.lock()
|
||||
.await
|
||||
.misc
|
||||
.push(tokio::spawn(status_timer(
|
||||
crate::SHARD_MANAGER.get().unwrap().runners.clone(),
|
||||
ctx.cache,
|
||||
)));
|
||||
|
||||
info!("MISC tasks started.");
|
||||
}
|
||||
|
||||
pub async fn status_timer(
|
||||
shard_runners: Arc<Mutex<HashMap<ShardId, ShardRunnerInfo>>>,
|
||||
cache: Arc<Cache>,
|
||||
) {
|
||||
let mut rand = OsRng::default();
|
||||
let activity_list = [
|
||||
let activities = [
|
||||
ActivityData::watching("my developer eat a watermelon whole."),
|
||||
ActivityData::watching(format!(
|
||||
"{} users in {} guilds.",
|
||||
cache.user_count(),
|
||||
cache.guild_count()
|
||||
cache.user_count() as u64 + cache.unknown_members(),
|
||||
cache.guild_count() + cache.unavailable_guilds().len()
|
||||
)),
|
||||
ActivityData::watching(format!("for {}help", constants::COMMAND_PREFIX)),
|
||||
ActivityData::listening("Infected Mushroom"),
|
||||
];
|
||||
let mut interval = tokio::time::interval(Duration::from_secs(20 * 60));
|
||||
|
||||
loop {
|
||||
let activity = SampleRange::sample_single(0..activities.len() - 1, &mut rand);
|
||||
for (_shard_id, shard_info) in shard_runners.lock().await.iter() {
|
||||
shard_info.runner_tx.set_activity(Some(
|
||||
activity_list[SampleRange::sample_single(0..activity_list.len() - 1, &mut rand)]
|
||||
.clone(),
|
||||
));
|
||||
shard_info
|
||||
.runner_tx
|
||||
.set_activity(Some(activities[activity].clone()));
|
||||
}
|
||||
tokio::time::sleep(Duration::from_secs(20 * 60)).await;
|
||||
|
||||
interval.tick().await;
|
||||
}
|
||||
}
|
||||
|
|
BIN
testdb
Normal file
BIN
testdb
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue