Soo much bootstrapping
This commit is contained in:
parent
06ac88f6ff
commit
3455f323fc
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
/target
|
||||
/result
|
||||
/.env
|
||||
state.yml
|
||||
|
|
522
Cargo.lock
generated
522
Cargo.lock
generated
|
@ -17,6 +17,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.6.1"
|
||||
|
@ -281,7 +290,7 @@ version = "2.33.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"ansi_term 0.11.0",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
|
@ -310,6 +319,22 @@ dependencies = [
|
|||
"cache-padded",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.1"
|
||||
|
@ -321,9 +346,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
|
||||
checksum = "3825b1e8580894917dc4468cb634a1b4e9745fddc854edad72d9c04644c0319f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
@ -363,6 +388,12 @@ version = "0.15.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.29"
|
||||
|
@ -419,6 +450,21 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.1"
|
||||
|
@ -431,12 +477,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca"
|
||||
checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
|
@ -445,9 +492,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
|
||||
checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
|
@ -455,15 +502,26 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
|
||||
checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
|
||||
checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
|
@ -482,12 +540,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb"
|
||||
checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
|
@ -495,23 +551,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
|
||||
checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
|
||||
checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
|
||||
checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
|
@ -521,8 +576,6 @@ dependencies = [
|
|||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
|
@ -547,17 +600,34 @@ dependencies = [
|
|||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glados"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dotenv",
|
||||
"influx_db_client",
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"rcon",
|
||||
"rustbreak",
|
||||
"serde",
|
||||
"serenity",
|
||||
"structopt",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -646,9 +716,9 @@ checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
|
|||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
|
||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
|
@ -689,6 +759,19 @@ dependencies = [
|
|||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"hyper",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
|
@ -710,6 +793,19 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "influx_db_client"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1a5abf7f7759f14075abcc0140d79a339729e50042ddf93fc0de9d11ddb1f"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"futures",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "input_buffer"
|
||||
version = "0.3.1"
|
||||
|
@ -766,9 +862,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.107"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
|
||||
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
|
@ -780,6 +882,15 @@ dependencies = [
|
|||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.9"
|
||||
|
@ -808,6 +919,12 @@ dependencies = [
|
|||
"unicase",
|
||||
]
|
||||
|
||||
[[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.4.4"
|
||||
|
@ -840,6 +957,35 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
|
@ -890,6 +1036,39 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.0.0"
|
||||
|
@ -934,6 +1113,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.2.0"
|
||||
|
@ -977,18 +1162,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
|
@ -1013,11 +1186,23 @@ version = "0.7.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.1.16",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.3",
|
||||
"rand_hc 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1027,7 +1212,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1036,7 +1231,16 @@ version = "0.5.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.1.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1045,20 +1249,71 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
||||
dependencies = [
|
||||
"rand_core 0.6.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rcon"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "465a6f903164a399084787547a026b83e7937bc576d8acdbd9e41ebf5de90a85"
|
||||
checksum = "6b7fdd146f86bd90fa2d4cf83a28b45f058e90bcf11ed0cce134e757928771e6"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"bytes 1.1.0",
|
||||
"err-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.6"
|
||||
|
@ -1074,12 +1329,14 @@ dependencies = [
|
|||
"http-body",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-tls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"native-tls",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
|
@ -1087,6 +1344,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
|
@ -1111,6 +1369,18 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustbreak"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460d97902465327d69ecfe8cefdb5972c6f94d6127ac9e992acdb51458bebc27"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.19.1"
|
||||
|
@ -1136,6 +1406,16 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.6.1"
|
||||
|
@ -1146,6 +1426,29 @@ dependencies = [
|
|||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
|
@ -1168,9 +1471,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.70"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3"
|
||||
checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -1189,6 +1492,18 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af"
|
||||
dependencies = [
|
||||
"dtoa",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serenity"
|
||||
version = "0.10.9"
|
||||
|
@ -1229,12 +1544,27 @@ dependencies = [
|
|||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.2"
|
||||
|
@ -1310,6 +1640,20 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"rand 0.8.4",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
|
@ -1340,13 +1684,21 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
name = "thread_local"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -1392,6 +1744,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.22.0"
|
||||
|
@ -1456,6 +1818,35 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507ec620f809cdf07cccb5bc57b13069a88031b795efd4079b1c71b66c1613d"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"lazy_static",
|
||||
"matchers",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.3"
|
||||
|
@ -1475,7 +1866,7 @@ dependencies = [
|
|||
"httparse",
|
||||
"input_buffer",
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.7.3",
|
||||
"sha-1",
|
||||
"url",
|
||||
"utf-8",
|
||||
|
@ -1575,6 +1966,12 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
|
@ -1611,9 +2008,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
|
@ -1758,3 +2155,12 @@ checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
|
|||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
|
|
@ -12,9 +12,15 @@ toolchain = "nightly"
|
|||
dotenv = "0.15.0"
|
||||
lazy_static = "1.4.0"
|
||||
rcon = "0.5.1"
|
||||
rustbreak = { version = "2.0.0", features = [ "yaml_enc" ] }
|
||||
serde = { version = "1.0.130", features = [ "derive" ] }
|
||||
serenity = "0.10.9"
|
||||
structopt = "0.3.25"
|
||||
thiserror = "1.0.30"
|
||||
tracing = "0.1.29"
|
||||
tracing-subscriber = { version = "0.3.2", features = [ "env-filter" ] }
|
||||
influx_db_client = "0.5.0"
|
||||
nom = "7.1.0"
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1.14.0"
|
||||
|
|
12
flake.lock
12
flake.lock
|
@ -22,11 +22,11 @@
|
|||
"rustOverlay": "rustOverlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1637129418,
|
||||
"narHash": "sha256-bO6rLgIiqK6pdeF2ewKyD6c+hNAcBEfXDqiTRaWzNmo=",
|
||||
"lastModified": 1637302206,
|
||||
"narHash": "sha256-X82LW/R35vCxNSk9jcddZFbjO6ZMjsq+KhIGC/GMkJg=",
|
||||
"owner": "yusdacra",
|
||||
"repo": "nix-cargo-integration",
|
||||
"rev": "1faede2be6c28a68a00b3479b77c849720324511",
|
||||
"rev": "a25206065a3a19d3dbcb2192d9bd273eea5cd919",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -59,11 +59,11 @@
|
|||
"rustOverlay": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1637115307,
|
||||
"narHash": "sha256-G+RKZeE1yLrnq+ExHF+HnSJsT+QJWebGhssgZHz3B00=",
|
||||
"lastModified": 1637288133,
|
||||
"narHash": "sha256-x5XWEK333KEhy2WL3TafE1vSa8/A1sGdbirTIV2bmSc=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "8a2e5fa870df3d34667d28fb3383d19516d182e4",
|
||||
"rev": "ccc467eff80b2fbb8000cf425e999ef14fbe200c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
73
src/conf.rs
73
src/conf.rs
|
@ -1,7 +1,8 @@
|
|||
use std::collections::HashSet;
|
||||
use std::{collections::HashSet, path::PathBuf};
|
||||
|
||||
use influx_db_client::reqwest::Url;
|
||||
use lazy_static::lazy_static;
|
||||
use serenity::model::id::UserId;
|
||||
use serenity::model::id::{ChannelId, GuildId, UserId};
|
||||
use structopt::StructOpt;
|
||||
|
||||
lazy_static! {
|
||||
|
@ -14,17 +15,29 @@ pub struct Args {
|
|||
short = "t",
|
||||
value_name = "TOKEN",
|
||||
validator = validate_token,
|
||||
env = "DISCORD_TOKEN")]
|
||||
env = "DISCORD_TOKEN",
|
||||
hide_env_values = true)]
|
||||
pub discord_token: String,
|
||||
|
||||
#[structopt(long, value_name = "URL", env = "RCON_ADDRESS")]
|
||||
pub rcon_address: String,
|
||||
|
||||
#[structopt(long, value_name = "PASSWORD", env = "RCON_PASSWORD")]
|
||||
#[structopt(
|
||||
long,
|
||||
value_name = "PASSWORD",
|
||||
env = "RCON_PASSWORD",
|
||||
hide_env_values = true
|
||||
)]
|
||||
pub rcon_password: String,
|
||||
|
||||
#[structopt(long, short, value_name = "ID", env = "DISCORD_OWNERS")]
|
||||
pub owners: Vec<UserId>,
|
||||
#[structopt(
|
||||
long,
|
||||
short,
|
||||
value_name = "ID",
|
||||
env = "DISCORD_OWNERS",
|
||||
use_delimiter = true
|
||||
)]
|
||||
pub owner: Vec<UserId>,
|
||||
|
||||
#[structopt(
|
||||
long,
|
||||
|
@ -34,6 +47,36 @@ pub struct Args {
|
|||
default_value = "~"
|
||||
)]
|
||||
pub prefix: String,
|
||||
|
||||
#[structopt(
|
||||
long = "db",
|
||||
short,
|
||||
value_name = "PATH",
|
||||
env = "DB_PATH",
|
||||
default_value = "state.yml"
|
||||
)]
|
||||
pub database_path: PathBuf,
|
||||
|
||||
#[structopt(long, short, value_name = "ID", env = "GUILD_ID")]
|
||||
pub guild_id: u64,
|
||||
|
||||
#[structopt(long, value_name = "ID", env = "GUILD_ADMIN_CHANNEL")]
|
||||
pub admin_channel: u64,
|
||||
|
||||
#[structopt(long, value_name = "ID", env = "GUILD_INFO_CHANNEL")]
|
||||
pub info_channel: u64,
|
||||
|
||||
#[structopt(long, value_name = "URL", env = "INFLUX_HOST")]
|
||||
pub influx_host: Url,
|
||||
|
||||
#[structopt(long, value_name = "DB", env = "INFLUX_DB")]
|
||||
pub influx_db: String,
|
||||
|
||||
#[structopt(long, value_name = "USER", env = "INFLUX_USER")]
|
||||
pub influx_user: String,
|
||||
|
||||
#[structopt(long, value_name = "PW", env = "INFLUX_PW", hide_env_values = true)]
|
||||
pub influx_password: String,
|
||||
}
|
||||
|
||||
fn validate_token(raw: String) -> std::result::Result<(), String> {
|
||||
|
@ -42,9 +85,21 @@ fn validate_token(raw: String) -> std::result::Result<(), String> {
|
|||
|
||||
impl Args {
|
||||
pub fn owners(&self) -> HashSet<UserId> {
|
||||
if self.owners.is_empty() {
|
||||
eprintln!("You should probably specify at least one `--owner`");
|
||||
if self.owner.is_empty() {
|
||||
tracing::warn!("You should probably specify at least one `--owner`");
|
||||
}
|
||||
self.owners.iter().cloned().collect()
|
||||
self.owner.iter().cloned().collect()
|
||||
}
|
||||
|
||||
pub fn guild_id(&self) -> GuildId {
|
||||
self.guild_id.into()
|
||||
}
|
||||
|
||||
pub fn admin_channel(&self) -> ChannelId {
|
||||
self.admin_channel.into()
|
||||
}
|
||||
|
||||
pub fn info_channel(&self) -> ChannelId {
|
||||
self.info_channel.into()
|
||||
}
|
||||
}
|
||||
|
|
16
src/data.rs
Normal file
16
src/data.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use rustbreak::deser::Yaml;
|
||||
use serenity::prelude::TypeMapKey;
|
||||
|
||||
use crate::{rcon::RconHandle, state::State};
|
||||
|
||||
pub struct StateKey;
|
||||
|
||||
impl TypeMapKey for StateKey {
|
||||
type Value = rustbreak::FileDatabase<State, Yaml>;
|
||||
}
|
||||
|
||||
pub struct Rcon;
|
||||
|
||||
impl TypeMapKey for Rcon {
|
||||
type Value = RconHandle;
|
||||
}
|
|
@ -1,33 +1,55 @@
|
|||
use serenity::{
|
||||
framework::{standard::macros::group, StandardFramework},
|
||||
Client,
|
||||
};
|
||||
//! # Workflows
|
||||
//!
|
||||
//! - `~ping`
|
||||
//! - Pong!
|
||||
//!
|
||||
//! - `~invite Random#1234`
|
||||
//! - Invite someone into the guild
|
||||
//!
|
||||
//! - Member_add
|
||||
//! - Notify guild about new member
|
||||
//!
|
||||
//! - Member_leave
|
||||
//! - Notify guild about leave
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use serenity::{client::bridge::gateway::GatewayIntents, Client};
|
||||
|
||||
use crate::{
|
||||
conf::ARGS,
|
||||
data,
|
||||
error::{Error, Result},
|
||||
influx::{InfluxDb, InfluxKey},
|
||||
rcon::RconHandle,
|
||||
state::State,
|
||||
};
|
||||
|
||||
pub struct Api {
|
||||
mod framework;
|
||||
mod handler;
|
||||
mod util;
|
||||
|
||||
use self::handler::Handler;
|
||||
|
||||
lazy_static! {
|
||||
static ref INTENTS: GatewayIntents = {
|
||||
use GatewayIntents as GI;
|
||||
GI::DIRECT_MESSAGES | GI::DIRECT_MESSAGE_REACTIONS | GI::GUILD_MEMBERS | GI::GUILD_MESSAGES
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Bot {
|
||||
client: Client,
|
||||
}
|
||||
|
||||
#[group]
|
||||
#[owners_only]
|
||||
struct Owner;
|
||||
|
||||
impl Api {
|
||||
impl Bot {
|
||||
pub async fn init() -> Result<Self> {
|
||||
let framework = StandardFramework::new()
|
||||
.configure(|c| {
|
||||
c.with_whitespace(true)
|
||||
.owners(ARGS.owners())
|
||||
.prefix(&ARGS.prefix)
|
||||
.delimiters(vec![", ", ","])
|
||||
})
|
||||
.group(&OWNER_GROUP);
|
||||
let client = Client::builder(&ARGS.discord_token)
|
||||
.framework(framework)
|
||||
.framework(framework::init())
|
||||
.intents(*INTENTS)
|
||||
.event_handler(Handler::default())
|
||||
.type_map_insert::<data::Rcon>(RconHandle::init().await)
|
||||
.type_map_insert::<InfluxKey>(InfluxDb::init())
|
||||
.type_map_insert::<data::StateKey>(State::load().await?)
|
||||
.await
|
||||
.map_err(Error::CreatingDiscordClient)?;
|
||||
Ok(Self { client })
|
||||
|
|
67
src/discord/framework.rs
Normal file
67
src/discord/framework.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use serenity::{
|
||||
client::Context,
|
||||
framework::{
|
||||
standard::{
|
||||
help_commands,
|
||||
macros::{command, group, help},
|
||||
Args, CommandGroup, CommandResult, HelpOptions,
|
||||
},
|
||||
StandardFramework,
|
||||
},
|
||||
model::{channel::Message, id::UserId},
|
||||
};
|
||||
|
||||
use crate::conf::ARGS;
|
||||
|
||||
pub fn init() -> StandardFramework {
|
||||
StandardFramework::new()
|
||||
.configure(|c| {
|
||||
c.with_whitespace(true)
|
||||
.owners(ARGS.owners())
|
||||
.prefix(&ARGS.prefix)
|
||||
.delimiters(vec![", ", ","])
|
||||
})
|
||||
.help(&BOT_HELP)
|
||||
.group(&OWNER_GROUP)
|
||||
.group(&GENERAL_GROUP)
|
||||
}
|
||||
|
||||
#[group]
|
||||
#[owners_only]
|
||||
#[commands(ping, invite)]
|
||||
struct Owner;
|
||||
|
||||
#[group]
|
||||
struct General;
|
||||
|
||||
#[command]
|
||||
#[description = "Ping the bot to see if it's online"]
|
||||
async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
|
||||
msg.reply(&ctx.http, "Pong!").await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
#[description = "Invite a new member to the guild"]
|
||||
async fn invite(ctx: &Context, msg: &Message) -> CommandResult {
|
||||
msg.reply(&ctx.http, "TBD").await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[help]
|
||||
#[max_levenshtein_distance(3)]
|
||||
#[lacking_permissions = "Hide"]
|
||||
#[lacking_role = "Nothing"]
|
||||
async fn bot_help(
|
||||
context: &Context,
|
||||
msg: &Message,
|
||||
args: Args,
|
||||
help_options: &'static HelpOptions,
|
||||
groups: &[&'static CommandGroup],
|
||||
owners: HashSet<UserId>,
|
||||
) -> CommandResult {
|
||||
let _ = help_commands::with_embeds(context, msg, args, help_options, groups, owners).await;
|
||||
Ok(())
|
||||
}
|
57
src/discord/handler.rs
Normal file
57
src/discord/handler.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use serenity::{
|
||||
client::{Context, EventHandler},
|
||||
model::{
|
||||
guild::Member,
|
||||
id::GuildId,
|
||||
prelude::{Ready, User},
|
||||
},
|
||||
};
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::{conf::ARGS, error::ResultExt, tracking::track_server_status};
|
||||
|
||||
use super::util::{initial_state_sanitization, workflow_member_add, workflow_member_removal};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Handler {
|
||||
setup_done: AtomicBool,
|
||||
}
|
||||
|
||||
#[serenity::async_trait]
|
||||
impl EventHandler for Handler {
|
||||
async fn ready(&self, ctx: Context, _data_about_bot: Ready) {
|
||||
// Only do this once!
|
||||
if !self.setup_done.load(Ordering::Relaxed) {
|
||||
let ctx_clone = ctx.clone();
|
||||
|
||||
initial_state_sanitization(&ctx_clone)
|
||||
.await
|
||||
.log_warn("sanitizing state at startup");
|
||||
|
||||
tokio::spawn(track_server_status(ctx_clone));
|
||||
|
||||
self.setup_done.swap(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
async fn guild_member_addition(&self, ctx: Context, guild_id: GuildId, new_member: Member) {
|
||||
if guild_id != ARGS.guild_id {
|
||||
return;
|
||||
}
|
||||
workflow_member_add(&ctx, new_member).await;
|
||||
}
|
||||
|
||||
async fn guild_member_removal(
|
||||
&self,
|
||||
ctx: Context,
|
||||
guild_id: GuildId,
|
||||
user: User,
|
||||
_member_data: Option<Member>,
|
||||
) {
|
||||
if guild_id != ARGS.guild_id {
|
||||
return;
|
||||
}
|
||||
workflow_member_removal(&ctx, user).await;
|
||||
}
|
||||
}
|
107
src/discord/util.rs
Normal file
107
src/discord/util.rs
Normal file
|
@ -0,0 +1,107 @@
|
|||
use serenity::{
|
||||
client::Context,
|
||||
model::{guild::Member, prelude::User},
|
||||
};
|
||||
|
||||
use core::fmt;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{
|
||||
conf::ARGS,
|
||||
error::{Result, ResultExt},
|
||||
state::{GuildMember, State},
|
||||
};
|
||||
|
||||
pub async fn initial_state_sanitization(ctx: &Context) -> Result {
|
||||
catch_up_on_guild_members(ctx).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn workflow_member_add(ctx: &Context, new_member: Member) {
|
||||
tracing::info!("Adding new member {:?}", new_member.user.name);
|
||||
// Keep track of the new member
|
||||
State::write(ctx, |state| {
|
||||
state.guild_members.insert(new_member.user.id.into())
|
||||
})
|
||||
.await
|
||||
.log_warn("adding new member to guild list");
|
||||
// Notify about new arrival
|
||||
admin_channel_say(ctx, format!("{} joined the guild!", new_member.user))
|
||||
.await
|
||||
.log_warn("notifying about new guild member");
|
||||
// Greet the new member with a DM
|
||||
welcome_new_member(ctx, &new_member)
|
||||
.await
|
||||
.log_warn("welcoming new member");
|
||||
}
|
||||
|
||||
pub async fn workflow_member_removal(ctx: &Context, user: User) {
|
||||
let old_member: Option<GuildMember> =
|
||||
State::write(ctx, |state| state.guild_members.take(&user.id))
|
||||
.await
|
||||
.log_warn("removing ex-guild-member")
|
||||
.flatten();
|
||||
if old_member.is_some() {
|
||||
admin_channel_say(ctx, format!("{} left the server!", user))
|
||||
.await
|
||||
.log_warn("notifying guild about leaving member");
|
||||
}
|
||||
}
|
||||
|
||||
async fn welcome_new_member(ctx: &Context, member: &Member) -> Result {
|
||||
let channel = member.user.create_dm_channel(ctx.http.clone()).await?;
|
||||
channel.send_message(ctx.http.clone(), |m| {
|
||||
m.content(format!(r#"Hey {},
|
||||
Welcome to the CCQCraft Server! Most information can be found in the {info_channel} channel! If you have any questions message either megamanmalte or Gim. Not me, I'm just a bot :)"#,
|
||||
member.user.name,
|
||||
info_channel=ARGS.info_channel()))
|
||||
}).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn admin_channel_say(ctx: &Context, what: impl fmt::Display) -> Result {
|
||||
ARGS.admin_channel().say(ctx.http.clone(), what).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn catch_up_on_guild_members(ctx: &Context) -> Result {
|
||||
let actual_members: HashSet<_> = ARGS
|
||||
.guild_id()
|
||||
.members(ctx.http.clone(), None, None)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|member| member.user.id)
|
||||
.collect();
|
||||
let known_members: HashSet<_> = State::read(ctx, |state| {
|
||||
state.guild_members.iter().map(|member| member.id).collect()
|
||||
})
|
||||
.await?;
|
||||
|
||||
for old in known_members.difference(&actual_members) {
|
||||
let old_user = match old
|
||||
.to_user(ctx.http.clone())
|
||||
.await
|
||||
.log_warn("retrieving user based on id")
|
||||
{
|
||||
Some(member) => member,
|
||||
None => continue,
|
||||
};
|
||||
workflow_member_removal(ctx, old_user).await;
|
||||
}
|
||||
|
||||
for new in actual_members.difference(&known_members) {
|
||||
let new_member = match ARGS
|
||||
.guild_id()
|
||||
.member(ctx.http.clone(), new)
|
||||
.await
|
||||
.log_warn("retrieving member based on id")
|
||||
{
|
||||
Some(member) => member,
|
||||
None => continue,
|
||||
};
|
||||
workflow_member_add(ctx, new_member).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
53
src/error.rs
53
src/error.rs
|
@ -1,11 +1,11 @@
|
|||
use core::fmt;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
pub type Result<T = ()> = ::std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("Configuration key {_0:?} is missing. Try setting it through args or the environment")]
|
||||
MissingConfiguration(String),
|
||||
#[error("Failed to initialize RCON: {_0}")]
|
||||
InitializingRcon(#[source] rcon::Error),
|
||||
#[error("Failed to execute RCON command {_0:?}: {_1}")]
|
||||
|
@ -14,4 +14,53 @@ pub enum Error {
|
|||
CreatingDiscordClient(#[source] serenity::Error),
|
||||
#[error("Error while listening for Discord events: {_0}")]
|
||||
Serenity(#[from] serenity::Error),
|
||||
#[error("Error while handling database: {_0}")]
|
||||
Rustbreak(#[from] rustbreak::error::RustbreakError),
|
||||
#[error("Error while talking to Influx db: {_0}")]
|
||||
Influx(#[from] influx_db_client::Error),
|
||||
#[error("Parsing results of `tps` command: {_0}")]
|
||||
RconTpsCmd(#[source] nom::Err<nom::error::Error<String>>),
|
||||
#[error("Parsing results of `list` command: {_0}")]
|
||||
RconListCmd(#[source] nom::Err<nom::error::Error<String>>),
|
||||
}
|
||||
|
||||
pub trait ResultExt<T> {
|
||||
fn log_info(self, when: &str) -> Option<T>;
|
||||
fn log_warn(self, when: &str) -> Option<T>;
|
||||
fn log_error(self, when: &str) -> Option<T>;
|
||||
}
|
||||
|
||||
impl<T, E> ResultExt<T> for std::result::Result<T, E>
|
||||
where
|
||||
E: fmt::Display,
|
||||
{
|
||||
fn log_info(self, when: &str) -> Option<T> {
|
||||
match self {
|
||||
Ok(val) => Some(val),
|
||||
Err(why) => {
|
||||
tracing::info!("Error occured while {}: {}", when, why);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn log_warn(self, when: &str) -> Option<T> {
|
||||
match self {
|
||||
Ok(val) => Some(val),
|
||||
Err(why) => {
|
||||
tracing::warn!("Error occured while {}: {}", when, why);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn log_error(self, when: &str) -> Option<T> {
|
||||
match self {
|
||||
Ok(val) => Some(val),
|
||||
Err(why) => {
|
||||
tracing::error!("Error occured while {}: {}", when, why);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
44
src/influx.rs
Normal file
44
src/influx.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use influx_db_client::{Client, Point};
|
||||
use serenity::{client::Context, prelude::TypeMapKey};
|
||||
|
||||
use crate::{conf::ARGS, error::Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InfluxDb {
|
||||
inner: Client,
|
||||
}
|
||||
|
||||
pub struct InfluxKey;
|
||||
|
||||
impl TypeMapKey for InfluxKey {
|
||||
type Value = InfluxDb;
|
||||
}
|
||||
|
||||
impl InfluxDb {
|
||||
pub fn init() -> Self {
|
||||
let inner = Client::new(ARGS.influx_host.clone(), &ARGS.influx_db)
|
||||
.set_authentication(&ARGS.influx_user, &ARGS.influx_password);
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
//pub async fn write_point(point: Point, ctx: &Context) -> Result {
|
||||
// let client = ctx.data.read().await;
|
||||
// let client = client
|
||||
// .get::<InfluxKey>()
|
||||
// .expect("BUG: No Influx client present");
|
||||
// client.inner.write_point(point, None, None).await?;
|
||||
// Ok(())
|
||||
//}
|
||||
|
||||
pub async fn write_points<T>(points: T, ctx: &Context) -> Result
|
||||
where
|
||||
T: Iterator<Item = Point>,
|
||||
{
|
||||
let client = ctx.data.read().await;
|
||||
let client = client
|
||||
.get::<InfluxKey>()
|
||||
.expect("BUG: No Influx client present");
|
||||
client.inner.write_points(points, None, None).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -3,13 +3,16 @@
|
|||
//! Helper tool for my minecraft instance.
|
||||
|
||||
mod conf;
|
||||
mod data;
|
||||
mod discord;
|
||||
mod error;
|
||||
mod influx;
|
||||
mod rcon;
|
||||
mod state;
|
||||
mod tracking;
|
||||
|
||||
use discord::Bot;
|
||||
use error::Result;
|
||||
use state::State;
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
|
@ -21,7 +24,7 @@ async fn main() {
|
|||
|
||||
async fn real_main() -> Result {
|
||||
dotenv::dotenv().ok();
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let state = State::init().await?;
|
||||
state.run_bot().await
|
||||
Bot::init().await?.start().await
|
||||
}
|
||||
|
|
78
src/rcon.rs
78
src/rcon.rs
|
@ -1,33 +1,69 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use serenity::client::Context;
|
||||
|
||||
use crate::{
|
||||
conf::ARGS,
|
||||
error::{Error, Result},
|
||||
data,
|
||||
error::{Error, Result, ResultExt},
|
||||
};
|
||||
|
||||
pub struct Rcon {
|
||||
inner: ::rcon::Connection,
|
||||
pub struct RconHandle {
|
||||
inner: Option<::rcon::Connection>,
|
||||
}
|
||||
|
||||
impl Rcon {
|
||||
pub async fn init() -> Result<Self> {
|
||||
pub trait RconCommand {
|
||||
type Output;
|
||||
fn as_string(&self) -> String;
|
||||
fn parse(&self, raw: String) -> Result<Self::Output>;
|
||||
}
|
||||
|
||||
impl RconHandle {
|
||||
pub async fn init() -> Self {
|
||||
let mut handle = Self { inner: None };
|
||||
handle.connect().await;
|
||||
handle
|
||||
}
|
||||
|
||||
pub async fn cmd<C>(cmd: &C, ctx: &Context) -> Result<C::Output>
|
||||
where
|
||||
C: RconCommand,
|
||||
{
|
||||
let mut rcon = ctx.data.write().await;
|
||||
let rcon = rcon.get_mut::<data::Rcon>().expect("BUG: No rcon client");
|
||||
rcon.reconnect_until_success().await;
|
||||
let cmd_str = cmd.as_string();
|
||||
let raw_output = rcon
|
||||
.inner
|
||||
.as_mut()
|
||||
// We must be connected here
|
||||
.unwrap()
|
||||
.cmd(&cmd_str)
|
||||
.await
|
||||
.map_err(|why| Error::RconCommand(cmd_str, why))?;
|
||||
cmd.parse(raw_output)
|
||||
}
|
||||
|
||||
async fn reconnect_until_success(&mut self) {
|
||||
let mut wait = Duration::from_secs(1);
|
||||
if self.inner.is_none() {
|
||||
self.connect().await;
|
||||
}
|
||||
while self.inner.is_none() {
|
||||
tokio::time::sleep(wait).await;
|
||||
self.connect().await;
|
||||
wait *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
async fn connect(&mut self) {
|
||||
let addr = &ARGS.rcon_address;
|
||||
let password = &ARGS.rcon_password;
|
||||
let inner = rcon::Connection::builder()
|
||||
self.inner = rcon::Connection::builder()
|
||||
.enable_minecraft_quirks(true)
|
||||
.connect(addr, &password)
|
||||
.connect(addr, password)
|
||||
.await
|
||||
.map_err(Error::InitializingRcon)?;
|
||||
Ok(Self { inner })
|
||||
}
|
||||
|
||||
pub async fn cmd(&mut self, cmd: &str) -> Result<String> {
|
||||
self.inner
|
||||
.cmd(cmd)
|
||||
.await
|
||||
.map_err(|why| Error::RconCommand(cmd.into(), why))
|
||||
}
|
||||
|
||||
pub async fn greet(&mut self) -> Result {
|
||||
let _ = self.cmd("say GLaDOS is now online").await?;
|
||||
Ok(())
|
||||
.map_err(Error::InitializingRcon)
|
||||
.log_warn("initializing rcon connection");
|
||||
}
|
||||
}
|
||||
|
|
95
src/state.rs
95
src/state.rs
|
@ -1,18 +1,95 @@
|
|||
use crate::{discord::Api, error::Result, rcon::Rcon};
|
||||
use rustbreak::{deser::Yaml, FileDatabase};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::{client::Context, model::id::UserId};
|
||||
|
||||
use std::{borrow::Borrow, collections::HashSet, hash::Hash};
|
||||
|
||||
use crate::{
|
||||
conf::ARGS,
|
||||
data,
|
||||
error::{Error, Result, ResultExt},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct State {
|
||||
pub rcon: Rcon,
|
||||
pub api: Api,
|
||||
/// Keeps track of the current guild members
|
||||
pub guild_members: HashSet<GuildMember>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GuildMember {
|
||||
/// Discord ID of the member
|
||||
pub id: UserId,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub async fn init() -> Result<Self> {
|
||||
let rcon = Rcon::init().await?;
|
||||
let api = Api::init().await?;
|
||||
Ok(State { rcon, api })
|
||||
pub async fn load() -> Result<FileDatabase<Self, Yaml>> {
|
||||
let db = FileDatabase::load_from_path_or_default(&ARGS.database_path)?;
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
pub async fn run_bot(self) -> Result {
|
||||
self.api.start().await
|
||||
pub async fn save(ctx: &Context) -> Result {
|
||||
ctx.data
|
||||
.read()
|
||||
.await
|
||||
.get::<data::StateKey>()
|
||||
.expect("BUG: Missing state in TypeMap")
|
||||
.save()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn read<F, R>(ctx: &Context, f: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&State) -> R,
|
||||
{
|
||||
ctx.data
|
||||
.read()
|
||||
.await
|
||||
.get::<data::StateKey>()
|
||||
.expect("BUG: Missing state in TypeMap")
|
||||
.read(f)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
pub async fn write<F, R>(ctx: &Context, f: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&mut State) -> R,
|
||||
{
|
||||
let res = ctx
|
||||
.data
|
||||
.read()
|
||||
.await
|
||||
.get::<data::StateKey>()
|
||||
.expect("BUG: Missing state in TypeMap")
|
||||
.write(f)
|
||||
.map_err(Error::from);
|
||||
State::save(ctx).await.log_warn("saving state data to disk");
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UserId> for GuildMember {
|
||||
fn from(id: UserId) -> Self {
|
||||
Self { id }
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for GuildMember {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for GuildMember {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id.eq(&other.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for GuildMember {}
|
||||
|
||||
impl Borrow<UserId> for GuildMember {
|
||||
fn borrow(&self) -> &UserId {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
|
26
src/tracking.rs
Normal file
26
src/tracking.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use serenity::client::Context;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
mod status;
|
||||
|
||||
use crate::{error::ResultExt, tracking::status::Status};
|
||||
|
||||
const TIME_BETWEEN_TRACKS: Duration = Duration::from_secs(60);
|
||||
|
||||
pub async fn track_server_status(ctx: Context) {
|
||||
loop {
|
||||
tracing::info!("Collecting status information");
|
||||
// Fetch status via rcon and if successful, push it to the influx db
|
||||
if let Some(status) = Status::get_from_rcon(&ctx)
|
||||
.await
|
||||
.log_warn("fetching status via rcon")
|
||||
{
|
||||
status
|
||||
.send_to_influx_db(&ctx)
|
||||
.await
|
||||
.log_warn("sending status to influx endpoint");
|
||||
}
|
||||
tokio::time::sleep(TIME_BETWEEN_TRACKS).await;
|
||||
}
|
||||
}
|
40
src/tracking/status.rs
Normal file
40
src/tracking/status.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use influx_db_client::Point;
|
||||
use serenity::client::Context;
|
||||
|
||||
mod player_info;
|
||||
mod tps;
|
||||
|
||||
use crate::{error::Result, influx::InfluxDb, rcon::RconHandle};
|
||||
|
||||
use self::{
|
||||
player_info::{ListCmd, PlayerInfo},
|
||||
tps::{Tps, TpsCmd},
|
||||
};
|
||||
|
||||
pub struct Status {
|
||||
pub tps: Tps,
|
||||
pub player_info: PlayerInfo,
|
||||
}
|
||||
|
||||
impl Status {
|
||||
pub async fn get_from_rcon(ctx: &Context) -> Result<Self> {
|
||||
let tps = RconHandle::cmd(&TpsCmd, ctx).await?;
|
||||
let player_info = RconHandle::cmd(&ListCmd, ctx).await?;
|
||||
Ok(Status { tps, player_info })
|
||||
}
|
||||
|
||||
pub async fn send_to_influx_db(&self, ctx: &Context) -> Result {
|
||||
let mut points = vec![];
|
||||
let status = Point::new("status")
|
||||
.add_field("tps", self.tps.min1)
|
||||
// Safe, since we started with u32
|
||||
.add_field("player_count", self.player_info.amount_online as i64);
|
||||
points.push(status);
|
||||
for player in &self.player_info.players {
|
||||
let point = Point::new("activity").add_tag("user_id", player.uuid.clone());
|
||||
points.push(point);
|
||||
}
|
||||
|
||||
InfluxDb::write_points(points.into_iter(), ctx).await
|
||||
}
|
||||
}
|
68
src/tracking/status/player_info.rs
Normal file
68
src/tracking/status/player_info.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use nom::{
|
||||
bytes::complete::{is_not, tag},
|
||||
character::complete::{self, char},
|
||||
combinator::{all_consuming, map},
|
||||
multi::separated_list0,
|
||||
sequence::{delimited, tuple},
|
||||
IResult,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
rcon::RconCommand,
|
||||
};
|
||||
|
||||
pub struct ListCmd;
|
||||
|
||||
pub struct PlayerInfo {
|
||||
pub amount_online: u32,
|
||||
pub players: Vec<Player>,
|
||||
}
|
||||
|
||||
pub struct Player {
|
||||
pub uuid: String,
|
||||
}
|
||||
|
||||
impl RconCommand for ListCmd {
|
||||
type Output = PlayerInfo;
|
||||
|
||||
fn as_string(&self) -> String {
|
||||
"minecraft:list uuids".into()
|
||||
}
|
||||
|
||||
/// Expected:
|
||||
/// ```
|
||||
/// There are 6 of a max of 20 players online: SomeName (00000000-0000-0000-0000-000000000000), ...
|
||||
/// ```
|
||||
fn parse(&self, raw: String) -> Result<Self::Output> {
|
||||
parse_list_result(&raw)
|
||||
.map(|(_, info)| info)
|
||||
.map_err(|why| Error::RconListCmd(why.to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_list_result(inp: &str) -> IResult<&str, PlayerInfo> {
|
||||
all_consuming(map(
|
||||
tuple((
|
||||
tag("There are "),
|
||||
complete::u32,
|
||||
tag(" of a max of "),
|
||||
complete::u32,
|
||||
tag(" players online: "),
|
||||
separated_list0(tag(", "), parse_player),
|
||||
)),
|
||||
|(_, num, _, _max, _, players)| PlayerInfo {
|
||||
amount_online: num,
|
||||
players,
|
||||
},
|
||||
))(inp)
|
||||
}
|
||||
|
||||
fn parse_player(inp: &str) -> IResult<&str, Player> {
|
||||
map(
|
||||
tuple((is_not(" "), delimited(char('('), is_not(")"), char(')')))),
|
||||
|(_name, uuid): (&str, &str)| Player {
|
||||
uuid: uuid.to_owned(),
|
||||
},
|
||||
)(inp)
|
||||
}
|
58
src/tracking/status/tps.rs
Normal file
58
src/tracking/status/tps.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
use nom::{
|
||||
bytes::complete::tag,
|
||||
combinator::{all_consuming, map, opt},
|
||||
number::complete::double,
|
||||
sequence::{preceded, tuple},
|
||||
IResult,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
rcon::RconCommand,
|
||||
};
|
||||
|
||||
pub struct TpsCmd;
|
||||
|
||||
pub struct Tps {
|
||||
pub min1: f64,
|
||||
pub min5: f64,
|
||||
pub min15: f64,
|
||||
}
|
||||
|
||||
impl RconCommand for TpsCmd {
|
||||
type Output = Tps;
|
||||
|
||||
fn as_string(&self) -> String {
|
||||
"spigot:tps".into()
|
||||
}
|
||||
|
||||
/// Expected:
|
||||
/// ```
|
||||
/// TPS from last 1m, 5m, 15m: 20.0, 20.0, 20.0
|
||||
/// ```
|
||||
fn parse(&self, raw: String) -> Result<Self::Output> {
|
||||
parse_tps_result(&raw)
|
||||
.map(|(_, tps)| tps)
|
||||
.map_err(|why| Error::RconTpsCmd(why.to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_tps_result(inp: &str) -> IResult<&str, Tps> {
|
||||
let start = tag("§6TPS from last 1m, 5m, 15m: §a");
|
||||
all_consuming(map(
|
||||
tuple((
|
||||
start,
|
||||
tps_value,
|
||||
tag(", §a"),
|
||||
tps_value,
|
||||
tag(", §a"),
|
||||
tps_value,
|
||||
tag("\n"),
|
||||
)),
|
||||
|(_, min1, _, min5, _, min15, _)| Tps { min1, min5, min15 },
|
||||
))(inp)
|
||||
}
|
||||
|
||||
fn tps_value(inp: &str) -> IResult<&str, f64> {
|
||||
preceded(opt(tag("*")), double)(inp)
|
||||
}
|
Loading…
Reference in a new issue