forked from projectmoon/tenebrous-dicebot
Implement Actix for state, refactor bot code.
Instead of using an Arc Mutex for state management embedded directly into the bot, utilize actor pattern, with the idea that this will be much more useful than simply logging a message once in the future. This also refactors the bot code so that instead of a single run_bot function, the DiceBot struct now has a run() method attached to it. This also necessitated changes and cleanup to the dicebot main, which is for the better anyhow. The error and config types are also now in their own files, and implemented for more in-depth use cases.
This commit is contained in:
parent
a5ec5c1e12
commit
938107feae
|
@ -1,5 +1,96 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "actix"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1be241f88f3b1e7e9a3fbe3b5a8a0f6915b5a1d7ee0d9a248d3376d01068cc60"
|
||||||
|
dependencies = [
|
||||||
|
"actix-rt",
|
||||||
|
"actix_derive",
|
||||||
|
"bitflags",
|
||||||
|
"bytes",
|
||||||
|
"crossbeam-channel",
|
||||||
|
"derive_more",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-util",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot",
|
||||||
|
"pin-project",
|
||||||
|
"smallvec",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"trust-dns-proto",
|
||||||
|
"trust-dns-resolver",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix-macros"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a60f9ba7c4e6df97f3aacb14bb5c0cd7d98a49dcbaed0d7f292912ad9a6a3ed2"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix-rt"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "143fcc2912e0d1de2bcf4e2f720d2a60c28652ab4179685a1ee159e0fb3db227"
|
||||||
|
dependencies = [
|
||||||
|
"actix-macros",
|
||||||
|
"actix-threadpool",
|
||||||
|
"copyless",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-util",
|
||||||
|
"smallvec",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix-threadpool"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d209f04d002854b9afd3743032a27b066158817965bf5d036824d19ac2cc0e30"
|
||||||
|
dependencies = [
|
||||||
|
"derive_more",
|
||||||
|
"futures-channel",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"num_cpus",
|
||||||
|
"parking_lot",
|
||||||
|
"threadpool",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix_derive"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b95aceadaf327f18f0df5962fedc1bde2f870566a0b9f65c89508a3b1f79334c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "addr2line"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
@ -112,6 +203,20 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.51"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec1931848a574faa8f7c71a12ea00453ff5effbb5f51afe7f77d7a48cace6ac1"
|
||||||
|
dependencies = [
|
||||||
|
"addr2line",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"miniz_oxide",
|
||||||
|
"object",
|
||||||
|
"rustc-demangle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
|
@ -169,6 +274,8 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
name = "chronicle-dicebot"
|
name = "chronicle-dicebot"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"actix",
|
||||||
|
"actix-rt",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"dirs",
|
"dirs",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
@ -200,6 +307,15 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cloudabi"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cmake"
|
name = "cmake"
|
||||||
version = "0.1.44"
|
version = "0.1.44"
|
||||||
|
@ -235,6 +351,12 @@ version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "copyless"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -251,6 +373,16 @@ version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
|
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
"maybe-uninit",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-queue"
|
name = "crossbeam-queue"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
@ -284,6 +416,17 @@ dependencies = [
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more"
|
||||||
|
version = "0.99.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "3.0.1"
|
version = "3.0.1"
|
||||||
|
@ -331,6 +474,18 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-as-inner"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -542,6 +697,12 @@ dependencies = [
|
||||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gimli"
|
||||||
|
version = "0.22.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gloo-timers"
|
name = "gloo-timers"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -604,6 +765,17 @@ version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hostname"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"match_cfg",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -735,6 +907,18 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipconfig"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7"
|
||||||
|
dependencies = [
|
||||||
|
"socket2",
|
||||||
|
"widestring",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
"winreg 0.6.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
|
@ -820,6 +1004,21 @@ dependencies = [
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
|
||||||
|
dependencies = [
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.11"
|
version = "0.4.11"
|
||||||
|
@ -829,12 +1028,27 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lru-cache"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "maplit"
|
name = "maplit"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "match_cfg"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matches"
|
name = "matches"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
@ -981,6 +1195,16 @@ dependencies = [
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.6.22"
|
version = "0.6.22"
|
||||||
|
@ -1073,6 +1297,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "olm-rs"
|
name = "olm-rs"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -1133,6 +1363,32 @@ dependencies = [
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cloudabi",
|
||||||
|
"instant",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -1345,7 +1601,17 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winreg",
|
"winreg 0.7.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "resolv-conf"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "11834e137f3b14e309437a8276714eed3a80d1ef894869e510f2c0c0b98b9f4a"
|
||||||
|
dependencies = [
|
||||||
|
"hostname",
|
||||||
|
"quick-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1607,6 +1873,12 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
@ -1623,6 +1895,12 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
|
@ -1711,6 +1989,12 @@ version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.3.15"
|
version = "0.3.15"
|
||||||
|
@ -1911,6 +2195,15 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "threadpool"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
||||||
|
dependencies = [
|
||||||
|
"num_cpus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.1.44"
|
version = "0.1.44"
|
||||||
|
@ -1980,6 +2273,7 @@ checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"log",
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
@ -2043,6 +2337,46 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "trust-dns-proto"
|
||||||
|
version = "0.19.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cdd7061ba6f4d4d9721afedffbfd403f20f39a4301fee1b70d6fcd09cca69f28"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"backtrace",
|
||||||
|
"enum-as-inner",
|
||||||
|
"futures 0.3.5",
|
||||||
|
"idna",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"rand",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "trust-dns-resolver"
|
||||||
|
version = "0.19.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f23cdfdc3d8300b3c50c9e84302d3bd6d860fb9529af84ace6cf9665f181b77"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
"cfg-if",
|
||||||
|
"futures 0.3.5",
|
||||||
|
"ipconfig",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"lru-cache",
|
||||||
|
"resolv-conf",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"trust-dns-proto",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "try-lock"
|
name = "try-lock"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
@ -2226,6 +2560,12 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "widestring"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a763e303c0e0f23b0da40888724762e802a8ffefbc22de4127ef42493c2ea68c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
@ -2269,6 +2609,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
|
|
@ -22,6 +22,8 @@ async-trait = "0.1"
|
||||||
url = "2.1"
|
url = "2.1"
|
||||||
dirs = "3.0"
|
dirs = "3.0"
|
||||||
indoc = "1.0"
|
indoc = "1.0"
|
||||||
|
actix = "0.10"
|
||||||
|
actix-rt = "1.1"
|
||||||
|
|
||||||
# The versioning of the matrix SDK follows its Cargo.toml. The SDK and
|
# The versioning of the matrix SDK follows its Cargo.toml. The SDK and
|
||||||
# macros are on master, but it imports the common and base from 0.1.0.
|
# macros are on master, but it imports the common and base from 0.1.0.
|
||||||
|
@ -37,4 +39,4 @@ features = ['derive']
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
version = "0.2"
|
version = "0.2"
|
||||||
features = ["rt-core", "macros", "time", "signal"]
|
features = ["rt-core", "rt-util", "macros", "time", "signal"]
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
use chronicle_dicebot::bot::run_bot;
|
//Needed for nested Result handling from tokio. Probably can go away after 1.47.0.
|
||||||
use chronicle_dicebot::bot::Config;
|
#![type_length_limit = "7605144"]
|
||||||
|
use actix::prelude::*;
|
||||||
|
use chronicle_dicebot::bot::DiceBot;
|
||||||
|
use chronicle_dicebot::config::*;
|
||||||
|
use chronicle_dicebot::error::BotError;
|
||||||
|
use chronicle_dicebot::state::DiceBotState;
|
||||||
use env_logger::Env;
|
use env_logger::Env;
|
||||||
|
use log::error;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn read_config<P: Into<PathBuf>>(config_path: P) -> Result<Config, Box<dyn std::error::Error>> {
|
fn read_config<P: Into<PathBuf>>(config_path: P) -> Result<Config, BotError> {
|
||||||
let config_path = config_path.into();
|
let config_path = config_path.into();
|
||||||
let config = {
|
let config = {
|
||||||
let contents = fs::read_to_string(&config_path)?;
|
let contents = fs::read_to_string(&config_path)?;
|
||||||
|
@ -14,13 +20,20 @@ fn read_config<P: Into<PathBuf>>(config_path: P) -> Result<Config, Box<dyn std::
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_config(contents: &str) -> Result<Config, Box<dyn std::error::Error>> {
|
fn deserialize_config(contents: &str) -> Result<Config, BotError> {
|
||||||
let config = { toml::from_str(&contents)? };
|
let config = toml::from_str(&contents)?;
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[actix_rt::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() {
|
||||||
|
match run().await {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => error!("Error: {:?}", e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() -> Result<(), BotError> {
|
||||||
env_logger::from_env(Env::default().default_filter_or("chronicle_dicebot=info")).init();
|
env_logger::from_env(Env::default().default_filter_or("chronicle_dicebot=info")).init();
|
||||||
|
|
||||||
let config_path = std::env::args()
|
let config_path = std::env::args()
|
||||||
|
@ -29,8 +42,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.expect("Need a config as an argument");
|
.expect("Need a config as an argument");
|
||||||
|
|
||||||
let cfg = read_config(config_path)?;
|
let cfg = read_config(config_path)?;
|
||||||
|
let bot_state = DiceBotState::new(&cfg).start();
|
||||||
|
|
||||||
run_bot(cfg).await?;
|
match DiceBot::new(&cfg, bot_state) {
|
||||||
|
Ok(bot) => bot.run().await?,
|
||||||
|
Err(e) => println!("Error connecting: {:?}", e),
|
||||||
|
};
|
||||||
|
|
||||||
|
System::current().stop();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
303
src/bot.rs
303
src/bot.rs
|
@ -1,4 +1,8 @@
|
||||||
use crate::commands::parse_command;
|
use crate::commands::parse_command;
|
||||||
|
use crate::config::*;
|
||||||
|
use crate::error::BotError;
|
||||||
|
use crate::state::{DiceBotState, LogSkippedOldMessages};
|
||||||
|
use actix::Addr;
|
||||||
use dirs;
|
use dirs;
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
|
@ -11,135 +15,102 @@ use matrix_sdk::{
|
||||||
Client, ClientConfig, EventEmitter, JsonStore, SyncRoom, SyncSettings,
|
Client, ClientConfig, EventEmitter, JsonStore, SyncRoom, SyncSettings,
|
||||||
};
|
};
|
||||||
use matrix_sdk_common_macros::async_trait;
|
use matrix_sdk_common_macros::async_trait;
|
||||||
use serde::{self, Deserialize, Serialize};
|
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::path::PathBuf;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
use thiserror::Error;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
//TODO move the config structs and read_config into their own file.
|
/// The DiceBot struct represents an active dice bot. The bot is not
|
||||||
|
/// connected to Matrix until its run() function is called.
|
||||||
/// The "matrix" section of the config, which gives home server, login information, and etc.
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub struct MatrixConfig {
|
|
||||||
/// Your homeserver of choice, as an FQDN without scheme or path
|
|
||||||
pub home_server: String,
|
|
||||||
|
|
||||||
/// Username to login as. Only the localpart.
|
|
||||||
pub username: String,
|
|
||||||
|
|
||||||
/// Bot account password.
|
|
||||||
pub password: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEFAULT_OLDEST_MESSAGE_AGE: u64 = 15 * 60;
|
|
||||||
|
|
||||||
/// The "bot" section of the config file, for bot settings.
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub struct BotConfig {
|
|
||||||
/// How far back from current time should we process a message?
|
|
||||||
oldest_message_age: Option<u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BotConfig {
|
|
||||||
pub fn new() -> BotConfig {
|
|
||||||
BotConfig {
|
|
||||||
oldest_message_age: Some(DEFAULT_OLDEST_MESSAGE_AGE),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determine the oldest allowable message age, in seconds. If the
|
|
||||||
/// setting is defined, use that value. If it is not defined, fall
|
|
||||||
/// back to DEFAULT_OLDEST_MESSAGE_AGE (15 minutes).
|
|
||||||
pub fn oldest_message_age(&self) -> u64 {
|
|
||||||
match self.oldest_message_age {
|
|
||||||
Some(seconds) => seconds,
|
|
||||||
None => DEFAULT_OLDEST_MESSAGE_AGE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the toml config file for the dicebot.
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub struct Config {
|
|
||||||
pub matrix: MatrixConfig,
|
|
||||||
pub bot: Option<BotConfig>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The DiceBot struct itself is the core of the program, essentially the entrypoint
|
|
||||||
/// to the bot.
|
|
||||||
pub struct DiceBot {
|
pub struct DiceBot {
|
||||||
/// A reference to the configuration read in on application start.
|
/// A reference to the configuration read in on application start.
|
||||||
config: Config,
|
config: Config,
|
||||||
|
|
||||||
/// The matrix SDK client.
|
/// The matrix client.
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|
||||||
/// Current state of the dice bot. Held in an Arc because it
|
/// Current state of the dice bot. Actor ref to the core state
|
||||||
/// accessed by the multi-threaded matrix SDK event handlers.
|
/// actor.
|
||||||
state: Arc<Mutex<DiceBotState>>,
|
state: Addr<DiceBotState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cache_dir() -> Result<PathBuf, BotError> {
|
||||||
|
let mut dir = dirs::cache_dir().ok_or(BotError::NoCacheDirectoryError)?;
|
||||||
|
dir.push("matrix-dicebot");
|
||||||
|
Ok(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the matrix client.
|
||||||
|
fn create_client(config: &Config) -> Result<Client, BotError> {
|
||||||
|
let cache_dir = cache_dir()?;
|
||||||
|
let store = JsonStore::open(&cache_dir)?;
|
||||||
|
let client_config = ClientConfig::new().state_store(Box::new(store));
|
||||||
|
let homeserver_url = Url::parse(&config.matrix.home_server)?;
|
||||||
|
|
||||||
|
Ok(Client::new_with_config(homeserver_url, client_config)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiceBot {
|
impl DiceBot {
|
||||||
/// Create a new dicebot with the given Matrix configuration and
|
/// Create a new dicebot with the given configuration and state
|
||||||
/// client. The dice bot is iniitalized with a fresh state.
|
/// actor. This function returns a Result because it is possible
|
||||||
pub fn new(config: Config, client: Client) -> Self {
|
/// for client creation to fail for some reason (e.g. invalid
|
||||||
DiceBot {
|
/// homeserver URL).
|
||||||
config: config,
|
pub fn new(config: &Config, state_actor: Addr<DiceBotState>) -> Result<Self, BotError> {
|
||||||
client: client,
|
Ok(DiceBot {
|
||||||
state: Arc::new(Mutex::new(DiceBotState::new())),
|
client: create_client(&config)?,
|
||||||
}
|
config: config.clone(),
|
||||||
}
|
state: state_actor,
|
||||||
}
|
})
|
||||||
|
|
||||||
/// Holds state of the dice bot, for anything requiring mutable
|
|
||||||
/// transitions. This is a simple mutable trait whose values represent
|
|
||||||
/// the current state of the dicebot. It provides mutable methods to
|
|
||||||
/// change state.
|
|
||||||
//#[derive(Clone, Copy)]
|
|
||||||
pub struct DiceBotState {
|
|
||||||
logged_skipped_old_message: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DiceBotState {
|
|
||||||
/// Create initial dice bot state.
|
|
||||||
fn new() -> DiceBotState {
|
|
||||||
DiceBotState {
|
|
||||||
logged_skipped_old_message: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Log and record that we have skipped some old messages. This
|
/// Logs the bot into Matrix and listens for events until program
|
||||||
/// method will log once, and then no-op from that point on.
|
/// terminated, or a panic occurs. Originally adapted from the
|
||||||
fn skipped_old_messages(&mut self) {
|
/// matrix-rust-sdk command bot example.
|
||||||
if !self.logged_skipped_old_message {
|
pub async fn run(self) -> Result<(), BotError> {
|
||||||
info!("Skipped some messages received while offline because they are too old.");
|
let username = &self.config.matrix.username;
|
||||||
|
let password = &self.config.matrix.password;
|
||||||
|
|
||||||
|
//TODO provide a device id from config.
|
||||||
|
let mut client = self.client.clone();
|
||||||
|
client
|
||||||
|
.login(username, password, None, Some("matrix dice bot"))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
info!("Logged in as {}", username);
|
||||||
|
|
||||||
|
//If the local json store has not been created yet, we need to do a single initial sync.
|
||||||
|
//It stores data under username's localpart.
|
||||||
|
let should_sync = {
|
||||||
|
let username = &self.config.matrix.username;
|
||||||
|
let mut cache = cache_dir()?;
|
||||||
|
cache.push(username);
|
||||||
|
!cache.exists()
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_sync {
|
||||||
|
info!("Performing initial sync");
|
||||||
|
self.client.sync(SyncSettings::default()).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.logged_skipped_old_message = true;
|
//Attach event handler.
|
||||||
|
client.add_event_emitter(Box::new(self)).await;
|
||||||
|
info!("Listening for commands");
|
||||||
|
|
||||||
|
let token = client
|
||||||
|
.sync_token()
|
||||||
|
.await
|
||||||
|
.ok_or(BotError::SyncTokenRequired)?;
|
||||||
|
|
||||||
|
let settings = SyncSettings::default().token(token);
|
||||||
|
|
||||||
|
//this keeps state from the server streaming in to the dice bot via the EventEmitter trait
|
||||||
|
//TODO somehow figure out how to "sync_until" instead of sync_forever... copy code and modify?
|
||||||
|
client.sync_forever(settings, |_| async {}).await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Figure out the allowed oldest message age, in seconds. This will
|
|
||||||
/// be the defined oldest message age in the bot config, if the bot
|
|
||||||
/// configuration and associated "oldest_message_age" setting are
|
|
||||||
/// defined. If the bot config or the message setting are not defined,
|
|
||||||
/// it will defualt to 15 minutes.
|
|
||||||
fn get_oldest_message_age(config: &Config) -> u64 {
|
|
||||||
let none_cfg;
|
|
||||||
let bot_cfg = match &config.bot {
|
|
||||||
Some(cfg) => cfg,
|
|
||||||
None => {
|
|
||||||
none_cfg = BotConfig::new();
|
|
||||||
&none_cfg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bot_cfg.oldest_message_age()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if a message is recent enough to actually process. If the
|
/// Check if a message is recent enough to actually process. If the
|
||||||
/// message is within "oldest_message_age" seconds, this function
|
/// message is within "oldest_message_age" seconds, this function
|
||||||
/// returns true. If it's older than that, it returns false and logs a
|
/// returns true. If it's older than that, it returns false and logs a
|
||||||
|
@ -215,14 +186,16 @@ impl EventEmitter for DiceBot {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Ignore messages that are older than configured duration.
|
//Ignore messages that are older than configured duration.
|
||||||
if !check_message_age(event, get_oldest_message_age(&self.config)) {
|
if !check_message_age(event, self.config.get_oldest_message_age()) {
|
||||||
let mut state = match self.state.lock() {
|
let res = self.state.send(LogSkippedOldMessages).await;
|
||||||
Ok(state) => state,
|
|
||||||
Err(poisoned) => poisoned.into_inner(),
|
|
||||||
};
|
|
||||||
|
|
||||||
(*state).skipped_old_messages();
|
match res {
|
||||||
return;
|
Ok(_) => return,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Actix error: {:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (plain, html) = match parse_command(&msg_body) {
|
let (plain, html) = match parse_command(&msg_body) {
|
||||||
|
@ -257,103 +230,3 @@ impl EventEmitter for DiceBot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum BotError {
|
|
||||||
/// Sync token couldn't be found.
|
|
||||||
#[error("the sync token could not be retrieved")]
|
|
||||||
SyncTokenRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the matrix dice bot until program terminated, or a panic occurs.
|
|
||||||
/// Originally adapted from the matrix-rust-sdk command bot example.
|
|
||||||
pub async fn run_bot(config: Config) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let homeserver_url = &config.matrix.home_server;
|
|
||||||
let username = &config.matrix.username;
|
|
||||||
let password = &config.matrix.password;
|
|
||||||
|
|
||||||
let mut cache_dir = dirs::cache_dir().expect("no cache directory found");
|
|
||||||
cache_dir.push("matrix-dicebot");
|
|
||||||
|
|
||||||
//If the local json store has not been created yet, we need to do a single initial sync.
|
|
||||||
//It stores data under username's localpart.
|
|
||||||
let should_sync = {
|
|
||||||
let mut cache = cache_dir.clone();
|
|
||||||
cache.push(username.clone());
|
|
||||||
!cache.exists()
|
|
||||||
};
|
|
||||||
|
|
||||||
let store = JsonStore::open(&cache_dir)?;
|
|
||||||
let client_config = ClientConfig::new().state_store(Box::new(store));
|
|
||||||
|
|
||||||
let homeserver_url = Url::parse(homeserver_url).expect("Couldn't parse the homeserver URL");
|
|
||||||
let mut client = Client::new_with_config(homeserver_url, client_config).unwrap();
|
|
||||||
|
|
||||||
client
|
|
||||||
.login(username, password, None, Some("matrix dice bot"))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Logged in as {}", username);
|
|
||||||
|
|
||||||
if should_sync {
|
|
||||||
info!("Performing initial sync");
|
|
||||||
client.sync(SyncSettings::default()).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Attach event handler.
|
|
||||||
info!("Listening for commands");
|
|
||||||
info!(
|
|
||||||
"Oldest allowable message time is {} seconds ago",
|
|
||||||
get_oldest_message_age(&config)
|
|
||||||
);
|
|
||||||
|
|
||||||
client
|
|
||||||
.add_event_emitter(Box::new(DiceBot::new(config, client.clone())))
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let token = client
|
|
||||||
.sync_token()
|
|
||||||
.await
|
|
||||||
.ok_or(BotError::SyncTokenRequired)?;
|
|
||||||
let settings = SyncSettings::default().token(token);
|
|
||||||
|
|
||||||
//this keeps state from the server streaming in to the dice bot via the EventEmitter trait
|
|
||||||
client.sync_forever(settings, |_| async {}).await;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn oldest_message_default_no_setting_test() {
|
|
||||||
let cfg = Config {
|
|
||||||
matrix: MatrixConfig {
|
|
||||||
home_server: "".to_owned(),
|
|
||||||
username: "".to_owned(),
|
|
||||||
password: "".to_owned(),
|
|
||||||
},
|
|
||||||
bot: Some(BotConfig {
|
|
||||||
oldest_message_age: None,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(15 * 60, get_oldest_message_age(&cfg));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn oldest_message_default_no_bot_config_test() {
|
|
||||||
let cfg = Config {
|
|
||||||
matrix: MatrixConfig {
|
|
||||||
home_server: "".to_owned(),
|
|
||||||
username: "".to_owned(),
|
|
||||||
password: "".to_owned(),
|
|
||||||
},
|
|
||||||
bot: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(15 * 60, get_oldest_message_age(&cfg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
use serde::{self, Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// The "matrix" section of the config, which gives home server, login information, and etc.
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct MatrixConfig {
|
||||||
|
/// Your homeserver of choice, as an FQDN without scheme or path
|
||||||
|
pub home_server: String,
|
||||||
|
|
||||||
|
/// Username to login as. Only the localpart.
|
||||||
|
pub username: String,
|
||||||
|
|
||||||
|
/// Bot account password.
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_OLDEST_MESSAGE_AGE: u64 = 15 * 60;
|
||||||
|
|
||||||
|
/// The "bot" section of the config file, for bot settings.
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct BotConfig {
|
||||||
|
/// How far back from current time should we process a message?
|
||||||
|
oldest_message_age: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BotConfig {
|
||||||
|
pub fn new() -> BotConfig {
|
||||||
|
BotConfig {
|
||||||
|
oldest_message_age: Some(DEFAULT_OLDEST_MESSAGE_AGE),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine the oldest allowable message age, in seconds. If the
|
||||||
|
/// setting is defined, use that value. If it is not defined, fall
|
||||||
|
/// back to DEFAULT_OLDEST_MESSAGE_AGE (15 minutes).
|
||||||
|
pub fn oldest_message_age(&self) -> u64 {
|
||||||
|
match self.oldest_message_age {
|
||||||
|
Some(seconds) => seconds,
|
||||||
|
None => DEFAULT_OLDEST_MESSAGE_AGE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the toml config file for the dicebot.
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct Config {
|
||||||
|
pub matrix: MatrixConfig,
|
||||||
|
pub bot: Option<BotConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn bot(self) -> BotConfig {
|
||||||
|
let none_cfg;
|
||||||
|
let bot_cfg = match self.bot {
|
||||||
|
Some(cfg) => cfg,
|
||||||
|
None => {
|
||||||
|
none_cfg = BotConfig::new();
|
||||||
|
none_cfg
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bot_cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Figure out the allowed oldest message age, in seconds. This will
|
||||||
|
/// be the defined oldest message age in the bot config, if the bot
|
||||||
|
/// configuration and associated "oldest_message_age" setting are
|
||||||
|
/// defined. If the bot config or the message setting are not defined,
|
||||||
|
/// it will defualt to 15 minutes.
|
||||||
|
pub fn get_oldest_message_age(&self) -> u64 {
|
||||||
|
self.bot
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&BotConfig::new())
|
||||||
|
.oldest_message_age()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn oldest_message_default_no_setting_test() {
|
||||||
|
let cfg = Config {
|
||||||
|
matrix: MatrixConfig {
|
||||||
|
home_server: "".to_owned(),
|
||||||
|
username: "".to_owned(),
|
||||||
|
password: "".to_owned(),
|
||||||
|
},
|
||||||
|
bot: Some(BotConfig {
|
||||||
|
oldest_message_age: None,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(15 * 60, cfg.get_oldest_message_age());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn oldest_message_default_no_bot_config_test() {
|
||||||
|
let cfg = Config {
|
||||||
|
matrix: MatrixConfig {
|
||||||
|
home_server: "".to_owned(),
|
||||||
|
username: "".to_owned(),
|
||||||
|
password: "".to_owned(),
|
||||||
|
},
|
||||||
|
bot: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(15 * 60, cfg.get_oldest_message_age());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum BotError {
|
||||||
|
/// Sync token couldn't be found.
|
||||||
|
#[error("the sync token could not be retrieved")]
|
||||||
|
SyncTokenRequired,
|
||||||
|
|
||||||
|
#[error("no cache directory found")]
|
||||||
|
NoCacheDirectoryError,
|
||||||
|
|
||||||
|
#[error("could not parse URL")]
|
||||||
|
UrlParseError(#[from] url::ParseError),
|
||||||
|
|
||||||
|
#[error("uncategorized matrix SDK error")]
|
||||||
|
MatrixError(#[from] matrix_sdk::Error),
|
||||||
|
|
||||||
|
#[error("uncategorized matrix SDK base error")]
|
||||||
|
MatrixBaseError(#[from] matrix_sdk::BaseError),
|
||||||
|
|
||||||
|
#[error("future canceled")]
|
||||||
|
FutureCanceledError,
|
||||||
|
|
||||||
|
#[error("tokio task join error")]
|
||||||
|
TokioTaskJoinError(#[from] tokio::task::JoinError),
|
||||||
|
|
||||||
|
//de = deserialization
|
||||||
|
#[error("toml parsing error")]
|
||||||
|
TomlParsingError(#[from] toml::de::Error),
|
||||||
|
|
||||||
|
#[error("i/o error")]
|
||||||
|
IoError(#[from] std::io::Error),
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
pub mod bot;
|
pub mod bot;
|
||||||
pub mod cofd;
|
pub mod cofd;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
|
pub mod config;
|
||||||
pub mod dice;
|
pub mod dice;
|
||||||
|
pub mod error;
|
||||||
mod help;
|
mod help;
|
||||||
mod parser;
|
mod parser;
|
||||||
pub mod roll;
|
pub mod roll;
|
||||||
|
pub mod state;
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
use crate::config::*;
|
||||||
|
use actix::prelude::*;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "bool")]
|
||||||
|
pub struct LogSkippedOldMessages;
|
||||||
|
|
||||||
|
/// Holds state of the dice bot, for anything requiring mutable
|
||||||
|
/// transitions. This is a simple mutable trait whose values represent
|
||||||
|
/// the current state of the dicebot. It provides mutable methods to
|
||||||
|
/// change state.
|
||||||
|
pub struct DiceBotState {
|
||||||
|
logged_skipped_old_messages: bool,
|
||||||
|
config: Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Actor for DiceBotState {
|
||||||
|
type Context = Context<Self>;
|
||||||
|
|
||||||
|
fn started(&mut self, _ctx: &mut Self::Context) {
|
||||||
|
info!(
|
||||||
|
"Oldest allowable message time is {} seconds ago",
|
||||||
|
&self.config.get_oldest_message_age()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiceBotState {
|
||||||
|
/// Create initial dice bot state.
|
||||||
|
pub fn new(config: &Config) -> DiceBotState {
|
||||||
|
DiceBotState {
|
||||||
|
logged_skipped_old_messages: false,
|
||||||
|
config: config.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log and record that we have skipped some old messages. This
|
||||||
|
/// method will log once, and then no-op from that point on.
|
||||||
|
pub fn skipped_old_messages(&mut self) {
|
||||||
|
if !self.logged_skipped_old_messages {
|
||||||
|
info!("Skipped some messages received while offline because they are too old.");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.logged_skipped_old_messages = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<LogSkippedOldMessages> for DiceBotState {
|
||||||
|
type Result = bool;
|
||||||
|
|
||||||
|
fn handle(&mut self, _msg: LogSkippedOldMessages, _ctx: &mut Context<Self>) -> Self::Result {
|
||||||
|
self.skipped_old_messages();
|
||||||
|
self.logged_skipped_old_messages
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue