Basics are in place
This commit is contained in:
parent
4226f7c143
commit
c935d725aa
9 changed files with 625 additions and 45 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
/target
|
||||
/.direnv
|
||||
/.pre-commit-config.yaml
|
||||
/conf.toml
|
||||
|
|
337
Cargo.lock
generated
337
Cargo.lock
generated
|
@ -233,6 +233,18 @@ name = "bitflags"
|
|||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
|
@ -284,6 +296,7 @@ dependencies = [
|
|||
"axum",
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"config",
|
||||
"discord",
|
||||
"redact",
|
||||
"reqwest",
|
||||
|
@ -374,6 +387,55 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"convert_case",
|
||||
"json5",
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"pathdiff",
|
||||
"ron",
|
||||
"rust-ini",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toml",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
|
||||
dependencies = [
|
||||
"const-random-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random-macro"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
||||
dependencies = [
|
||||
"getrandom 0.2.14",
|
||||
"once_cell",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
|
@ -390,6 +452,15 @@ version = "0.8.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.0"
|
||||
|
@ -399,6 +470,22 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.8"
|
||||
|
@ -444,6 +531,16 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "discord"
|
||||
version = "0.9.0"
|
||||
|
@ -466,6 +563,15 @@ dependencies = [
|
|||
"websocket",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dlv-list"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
|
||||
dependencies = [
|
||||
"const-random",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "1.5.3"
|
||||
|
@ -657,6 +763,16 @@ dependencies = [
|
|||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
|
@ -712,6 +828,12 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
|
@ -974,6 +1096,17 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json5"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "language-tags"
|
||||
version = "0.2.2"
|
||||
|
@ -1004,6 +1137,12 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.13"
|
||||
|
@ -1093,6 +1232,12 @@ dependencies = [
|
|||
"unicase 2.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.2"
|
||||
|
@ -1155,6 +1300,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
|
@ -1269,6 +1424,16 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-multimap"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e"
|
||||
dependencies = [
|
||||
"dlv-list",
|
||||
"hashbrown 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
|
@ -1306,6 +1471,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathdiff"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
|
@ -1318,6 +1489,51 @@ version = "2.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.5"
|
||||
|
@ -1673,6 +1889,28 @@ dependencies = [
|
|||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bitflags 2.5.0",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"ordered-multimap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
|
@ -1820,6 +2058,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
@ -1862,6 +2109,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
|
@ -2053,6 +2311,15 @@ dependencies = [
|
|||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
|
@ -2132,6 +2399,40 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
|
||||
dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
|
@ -2250,6 +2551,18 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "1.4.2"
|
||||
|
@ -2289,6 +2602,12 @@ dependencies = [
|
|||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.7.2"
|
||||
|
@ -2663,6 +2982,15 @@ version = "0.52.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.52.0"
|
||||
|
@ -2672,3 +3000,12 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
|
|
@ -8,6 +8,7 @@ anyhow = "1.0.82"
|
|||
axum = "0.7.5"
|
||||
clap = "4.5.4"
|
||||
color-eyre = "0.6.3"
|
||||
config = "0.14.0"
|
||||
discord = { git = "https://github.com/SpaceManiac/discord-rs" }
|
||||
redact = { version = "0.1.9", features = ["serde"] }
|
||||
reqwest = { version = "0.12.3", features = ["json", "socks"] }
|
||||
|
|
185
src/chatbot.rs
Normal file
185
src/chatbot.rs
Normal file
|
@ -0,0 +1,185 @@
|
|||
// TODO: family reminders?
|
||||
// TODO: connect to Discord
|
||||
// TODO: handle messages
|
||||
// TODO: data persistence? (sqlite? sled?)
|
||||
|
||||
use std::{any::Any, future};
|
||||
|
||||
use discord::{
|
||||
model::{Event, Message},
|
||||
Discord,
|
||||
};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub async fn start(conf: Arc<Config>) -> Result<()> {
|
||||
if conf.discord.is_none() {
|
||||
warn!("Chatbot starting without Discord token. Nothing will happen.");
|
||||
// wait forever
|
||||
future::pending::<()>().await;
|
||||
}
|
||||
|
||||
let discord = Discord::from_bot_token(
|
||||
conf.discord
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.bot_token
|
||||
.clone()
|
||||
.expose_secret(),
|
||||
)?;
|
||||
|
||||
let (mut conn, ready_ev) = discord.connect()?;
|
||||
info!("Discord connection ready: {ready_ev:?}");
|
||||
while let Ok(event) = conn.recv_event() {
|
||||
tokio::spawn(async move {
|
||||
match handle_event(event).await {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
error!("Failed to handle Discord event: {err}")
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn handle_event(event: Event) -> Result<()> {
|
||||
match event {
|
||||
Event::Ready(_) => return Ok(ignore_event(event)),
|
||||
Event::Resumed { trace: _ } => return Ok(ignore_event(event)),
|
||||
Event::UserUpdate(_) => return Ok(ignore_event(event)),
|
||||
Event::UserNoteUpdate(_, _) => return Ok(ignore_event(event)),
|
||||
Event::UserSettingsUpdate {
|
||||
detect_platform_accounts: _,
|
||||
developer_mode: _,
|
||||
enable_tts_command: _,
|
||||
inline_attachment_media: _,
|
||||
inline_embed_media: _,
|
||||
locale: _,
|
||||
message_display_compact: _,
|
||||
render_embeds: _,
|
||||
server_positions: _,
|
||||
show_current_game: _,
|
||||
status: _,
|
||||
theme: _,
|
||||
convert_emoticons: _,
|
||||
friend_source_flags: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::UserServerSettingsUpdate(_) => return Ok(ignore_event(event)),
|
||||
Event::VoiceStateUpdate(_, _) => return Ok(ignore_event(event)),
|
||||
Event::VoiceServerUpdate {
|
||||
server_id: _,
|
||||
channel_id: _,
|
||||
endpoint: _,
|
||||
token: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::CallCreate(_) => return Ok(ignore_event(event)),
|
||||
Event::CallUpdate {
|
||||
channel_id: _,
|
||||
message_id: _,
|
||||
region: _,
|
||||
ringing: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::CallDelete(_) => return Ok(ignore_event(event)),
|
||||
Event::ChannelRecipientAdd(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ChannelRecipientRemove(_, _) => return Ok(ignore_event(event)),
|
||||
Event::TypingStart {
|
||||
channel_id: _,
|
||||
user_id: _,
|
||||
timestamp: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::PresenceUpdate {
|
||||
presence: _,
|
||||
server_id: _,
|
||||
roles: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::PresencesReplace(_) => return Ok(ignore_event(event)),
|
||||
Event::RelationshipAdd(_) => return Ok(ignore_event(event)),
|
||||
Event::RelationshipRemove(_, _) => return Ok(ignore_event(event)),
|
||||
Event::MessageCreate(msg) => return Ok(handle_message(msg)),
|
||||
Event::MessageUpdate {
|
||||
id: _,
|
||||
channel_id: _,
|
||||
kind: _,
|
||||
content: _,
|
||||
nonce: _,
|
||||
tts: _,
|
||||
pinned: _,
|
||||
timestamp: _,
|
||||
edited_timestamp: _,
|
||||
author: _,
|
||||
mention_everyone: _,
|
||||
mentions: _,
|
||||
mention_roles: _,
|
||||
attachments: _,
|
||||
embeds: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::MessageAck {
|
||||
channel_id: _,
|
||||
message_id: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::MessageDelete {
|
||||
channel_id: _,
|
||||
message_id: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::MessageDeleteBulk {
|
||||
channel_id: _,
|
||||
ids: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::ServerCreate(_) => return Ok(ignore_event(event)),
|
||||
Event::ServerUpdate(_) => return Ok(ignore_event(event)),
|
||||
Event::ServerDelete(_) => return Ok(ignore_event(event)),
|
||||
Event::ServerMemberAdd(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ServerMemberUpdate {
|
||||
server_id: _,
|
||||
roles: _,
|
||||
user: _,
|
||||
nick: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::ServerMemberRemove(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ServerMembersChunk(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ServerSync {
|
||||
server_id: _,
|
||||
large: _,
|
||||
members: _,
|
||||
presences: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::ServerRoleCreate(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ServerRoleUpdate(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ServerRoleDelete(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ServerBanAdd(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ServerBanRemove(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ServerIntegrationsUpdate(_) => return Ok(ignore_event(event)),
|
||||
Event::ServerEmojisUpdate(_, _) => return Ok(ignore_event(event)),
|
||||
Event::ChannelCreate(_) => return Ok(ignore_event(event)),
|
||||
Event::ChannelUpdate(_) => return Ok(ignore_event(event)),
|
||||
Event::ChannelDelete(_) => return Ok(ignore_event(event)),
|
||||
Event::ChannelPinsAck {
|
||||
channel_id: _,
|
||||
timestamp: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::ChannelPinsUpdate {
|
||||
channel_id: _,
|
||||
last_pin_timestamp: _,
|
||||
} => return Ok(ignore_event(event)),
|
||||
Event::ReactionAdd(_) => return Ok(ignore_event(event)),
|
||||
Event::ReactionRemove(_) => return Ok(ignore_event(event)),
|
||||
Event::Unknown(_, _) => return Ok(ignore_event(event)),
|
||||
_ => return Ok(ignore_event(event)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ignore_event(event: Event) -> () {
|
||||
let event_type_id = event.type_id();
|
||||
info!("Ignoring Discord event of type: {event_type_id:?}")
|
||||
}
|
||||
|
||||
pub fn handle_message(msg: Message) -> () {
|
||||
info!(
|
||||
"Recieved Discord message in channel {} with content: {}",
|
||||
msg.channel_id, msg.content
|
||||
);
|
||||
|
||||
return ();
|
||||
}
|
|
@ -1,48 +1,76 @@
|
|||
use std::fmt::Debug;
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use config::{builder::DefaultState, Config as CConfig, ConfigBuilder};
|
||||
use redact::serde::redact_secret;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
const CURRENT_VERSION: u64 = 1;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Discord {
|
||||
#[serde(serialize_with = "redact_secret")]
|
||||
pub bot_token: Secret<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct OpenAI {
|
||||
#[serde(serialize_with = "redact_secret")]
|
||||
pub token: Secret<String>,
|
||||
}
|
||||
|
||||
// pub static ref CONFIG: Config = Config::load_or_defaults();
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub version: u64,
|
||||
pub secret: String,
|
||||
pub discord: Option<Discord>,
|
||||
pub open_ai: Option<OpenAI>,
|
||||
|
||||
#[serde(serialize_with = "redact_secret")]
|
||||
pub secret: Secret<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Loads a configuration via the predetermined methods, overlaying a
|
||||
/// default configuration. Returns any relevant errors that occurred
|
||||
/// during loading to be reported later to the user after logging (or other
|
||||
/// reporting faculties) have been initialized.
|
||||
pub fn load_or_defaults() -> (Self, Option<Error>) {
|
||||
let config = Self::defaults();
|
||||
(config, None)
|
||||
pub fn load() -> Result<Self> {
|
||||
let c = Self::builder()?.build()?;
|
||||
Ok(c.try_deserialize()?)
|
||||
}
|
||||
|
||||
pub fn defaults() -> Self {
|
||||
Self {
|
||||
version: 1,
|
||||
secret: "this is a secret!".to_owned(),
|
||||
pub fn builder() -> Result<ConfigBuilder<DefaultState>> {
|
||||
// TODO: log whether or not we were able to load conf.toml?
|
||||
Ok(Self::default_builder()
|
||||
.map_err(Error::from)?
|
||||
.add_source(config::File::from(std::path::PathBuf::from("./conf.toml")).required(false))
|
||||
.add_source(config::Environment::with_prefix("chatbot").separator("__")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Config {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Config")
|
||||
.field("version", &self.version)
|
||||
.finish()
|
||||
pub fn default_builder() -> Result<ConfigBuilder<DefaultState>> {
|
||||
Ok(CConfig::builder()
|
||||
.set_default("version", CURRENT_VERSION)?
|
||||
.set_default("discord", Option::<HashMap<String, config::Value>>::None)?
|
||||
.set_default("open_ai", Option::<HashMap<String, config::Value>>::None)?
|
||||
.set_default("secret", "this is a secret!")?)
|
||||
}
|
||||
|
||||
pub fn defaults() -> Result<Self> {
|
||||
let c = Self::default_builder()?.build()?;
|
||||
Ok(c.try_deserialize()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Config;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn config_does_not_leak_secrets() {
|
||||
let defaults = Config::defaults();
|
||||
fn config_does_not_leak_secrets() -> Result<()> {
|
||||
let defaults = Config::default_builder()?
|
||||
.set_override("discord.bot_token", Secret::new("THIS_IS_MY_BOT_TOKEN"))?
|
||||
.build()?;
|
||||
let s = format!("{defaults:?}");
|
||||
assert!(!s.contains("secret"));
|
||||
println!("{s}");
|
||||
assert!(!s.contains("THIS_IS_MY_BOT_TOKEN"));
|
||||
assert!(!s.contains("this is a secret"));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
41
src/main.rs
41
src/main.rs
|
@ -1,5 +1,6 @@
|
|||
#![forbid(unsafe_code)]
|
||||
|
||||
mod chatbot;
|
||||
mod config;
|
||||
mod minecraft_server_status;
|
||||
mod observe;
|
||||
|
@ -10,22 +11,34 @@ mod webserver;
|
|||
use crate::prelude::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let (conf, conf_err) = Config::load_or_defaults();
|
||||
observe::setup_logging(&conf);
|
||||
|
||||
debug!("Configuration: {conf:?}");
|
||||
if let Some(err) = conf_err {
|
||||
warn!("Error loading configuration: {err}");
|
||||
async fn main() -> Result<()> {
|
||||
let conf: Arc<Config> = match Config::load() {
|
||||
Err(err) => {
|
||||
error!("Error loading configuration: {err}");
|
||||
return Err(err);
|
||||
}
|
||||
Ok(conf) => Arc::new(conf),
|
||||
};
|
||||
observe::setup_logging(conf.clone());
|
||||
debug!("Configuration: {conf:?}");
|
||||
|
||||
// TODO: oh yeah we need an HTTP server to handle minecraft server status stuff
|
||||
let server = webserver::start(&conf);
|
||||
let mut set = tokio::task::JoinSet::new();
|
||||
|
||||
// TODO: family reminders?
|
||||
// TODO: connect to Discord
|
||||
// TODO: handle messages
|
||||
// TODO: data persistence? (sqlite? sled?)
|
||||
set.spawn(webserver::start(conf.clone()));
|
||||
set.spawn(chatbot::start(conf.clone()));
|
||||
|
||||
server.await
|
||||
let result = set.join_next().await;
|
||||
match result {
|
||||
Some(Err(err)) => {
|
||||
error!("One of the JoinSet tasks encountered a JoinError: {err}");
|
||||
Err(err.into())
|
||||
}
|
||||
Some(Ok(Err(err))) => {
|
||||
error!("One of the JoinSet tasks encountered an error: {err}");
|
||||
Err(err)
|
||||
}
|
||||
_ => {
|
||||
unreachable!("One of the primary spawned tasks finished. Exiting...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ use tracing_subscriber::EnvFilter;
|
|||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn setup_logging(_conf: &Config) {
|
||||
pub fn setup_logging(_conf: Arc<Config>) {
|
||||
color_eyre::install().expect("Failed to install color_eyre");
|
||||
|
||||
let filter = EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::TRACE.into())
|
||||
.parse_lossy("trace,chatbot=trace");
|
||||
.parse_lossy("info,chatbot=trace");
|
||||
|
||||
tracing_subscriber::fmt().with_env_filter(filter).init();
|
||||
}
|
||||
|
|
|
@ -6,4 +6,5 @@ pub use anyhow::Error;
|
|||
pub use anyhow::Result;
|
||||
pub use redact::Secret;
|
||||
pub use serde::{Deserialize, Serialize};
|
||||
pub use std::sync::Arc;
|
||||
pub use tracing::{debug, error, info, trace, warn};
|
||||
|
|
|
@ -10,24 +10,38 @@ use reqwest::StatusCode;
|
|||
use crate::{minecraft_server_status::MinecraftServerStatus, prelude::*};
|
||||
|
||||
struct WebserverError(anyhow::Error);
|
||||
type Result<T> = std::result::Result<T, WebserverError>;
|
||||
type WebserverResult<T> = std::result::Result<T, WebserverError>;
|
||||
|
||||
pub async fn start(_conf: &Config) {
|
||||
pub async fn start(_conf: Arc<Config>) -> Result<()> {
|
||||
let app = Router::new()
|
||||
.route("/", get(hello_world))
|
||||
.route("/health", get(health))
|
||||
.route("/minecraft-server-status", get(minecraft_server_status));
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||
info!("Listening on {:?}", listener);
|
||||
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn hello_world() -> impl IntoResponse {
|
||||
"Hello, World!".to_owned()
|
||||
}
|
||||
|
||||
async fn minecraft_server_status() -> Result<impl IntoResponse> {
|
||||
#[derive(Serialize, Debug)]
|
||||
struct Health {
|
||||
status: String,
|
||||
}
|
||||
|
||||
async fn health() -> impl IntoResponse {
|
||||
Json(Health {
|
||||
status: "online".to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
async fn minecraft_server_status() -> WebserverResult<impl IntoResponse> {
|
||||
let c = Arc::new(MinecraftServerStatus::try_new()?);
|
||||
let reqs: Vec<&str> = vec!["h.lyte.dev:26965", "ourcraft.lyte.dev"];
|
||||
let mut futures = Vec::with_capacity(reqs.len());
|
||||
|
|
Loading…
Reference in a new issue