diff --git a/.gitignore b/.gitignore index bfe328e..2405fba 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,9 @@ result /result + +*.db + +tmp/ +tmp.* +*.csv diff --git a/Cargo.lock b/Cargo.lock index ca34347..195655f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,6 +71,39 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom 0.2.10", + "once_cell", + "version_check", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anyhow" version = "1.0.75" @@ -97,7 +130,7 @@ dependencies = [ "async-lock", "async-task", "concurrent-queue", - "fastrand", + "fastrand 1.9.0", "futures-lite", "slab", ] @@ -131,7 +164,7 @@ dependencies = [ "log", "parking", "polling", - "rustix", + "rustix 0.37.23", "slab", "socket2 0.4.9", "waker-fn", @@ -205,6 +238,15 @@ dependencies = [ "webpki-roots 0.22.6", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.1" @@ -250,12 +292,27 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +dependencies = [ + "serde", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -284,7 +341,7 @@ dependencies = [ "async-lock", "async-task", "atomic-waker", - "fastrand", + "fastrand 1.9.0", "futures-lite", "log", ] @@ -328,6 +385,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets", +] + [[package]] name = "cipher" version = "0.2.5" @@ -346,6 +417,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "const_fn" version = "0.4.9" @@ -360,15 +437,31 @@ checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" dependencies = [ "aes-gcm", "base64 0.13.1", - "hkdf", - "hmac", + "hkdf 0.10.0", + "hmac 0.10.1", "percent-encoding", "rand 0.8.5", - "sha2", + "sha2 0.9.9", "time 0.2.27", "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + [[package]] name = "cpufeatures" version = "0.2.9" @@ -384,6 +477,21 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + [[package]] name = "crc32fast" version = "1.3.2" @@ -393,6 +501,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.16" @@ -422,6 +540,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "csv" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + [[package]] name = "ctr" version = "0.6.0" @@ -476,6 +615,17 @@ dependencies = [ "serde", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.8" @@ -501,7 +651,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -516,6 +668,31 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +dependencies = [ + "serde", +] + +[[package]] +name = "email-encoding" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfb21b9878cf7a348dcb8559109aabc0ec40d69924bd706fa5149846c4fef75" +dependencies = [ + "base64 0.21.2", + "memchr", +] + +[[package]] +name = "email_address" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2153bd83ebc09db15bcbdc3e2194d901804952e3dc96967e1cd3b0c5c32d112" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -525,6 +702,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.2" @@ -546,6 +729,17 @@ dependencies = [ "libc", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -561,6 +755,18 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + [[package]] name = "flate2" version = "1.0.27" @@ -582,12 +788,39 @@ dependencies = [ "spinning_top", ] +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "pin-project", + "spin 0.9.8", +] + [[package]] name = "fnv" 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.2.0" @@ -627,6 +860,28 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + [[package]] name = "futures-io" version = "0.3.28" @@ -639,7 +894,7 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", @@ -761,7 +1016,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -779,6 +1034,28 @@ name = "hashbrown" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.0", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "hermit-abi" @@ -786,6 +1063,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hkdf" version = "0.10.0" @@ -793,7 +1076,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" dependencies = [ "digest 0.9.0", - "hmac", + "hmac 0.10.1", +] + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac 0.12.1", ] [[package]] @@ -806,6 +1098,35 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.9" @@ -914,6 +1235,39 @@ dependencies = [ "tokio-rustls 0.24.1", ] +[[package]] +name = "iana-time-zone" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.4.0" @@ -934,6 +1288,16 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "infer" version = "0.2.3" @@ -976,7 +1340,7 @@ dependencies = [ "crossbeam-utils", "curl", "curl-sys", - "flume", + "flume 0.9.2", "futures-lite", "http", "log", @@ -989,6 +1353,15 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -1013,12 +1386,50 @@ dependencies = [ "log", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "lettre" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bd09637ae3ec7bd605b8e135e757980b3968430ff2b1a4a94fb7769e50166d" +dependencies = [ + "base64 0.21.2", + "email-encoding", + "email_address", + "fastrand 1.9.0", + "futures-util", + "hostname", + "httpdate", + "idna 0.3.0", + "mime", + "native-tls", + "nom", + "once_cell", + "quoted_printable", + "socket2 0.4.9", + "tokio", +] + [[package]] name = "libc" version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "libnghttp2-sys" version = "0.1.8+1.55.1" @@ -1029,6 +1440,17 @@ dependencies = [ "libc", ] +[[package]] +name = "libsqlite3-sys" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.1.12" @@ -1047,6 +1469,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" + [[package]] name = "lock_api" version = "0.4.10" @@ -1066,6 +1494,43 @@ dependencies = [ "value-bag", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "maud" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0bab19cef8a7fe1c18a43e881793bfc9d4ea984befec3ae5bd0415abf3ecf00" +dependencies = [ + "itoa", + "maud_macros", +] + +[[package]] +name = "maud_macros" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be95d66c3024ffce639216058e5bae17a83ecaf266ffc6e4d060ad447c9eed2" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "memchr" version = "2.5.0" @@ -1088,6 +1553,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.7.1" @@ -1108,6 +1579,72 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -1115,6 +1652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1148,6 +1686,32 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openssl" +version = "0.10.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +dependencies = [ + "bitflags 2.4.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -1156,9 +1720,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.91" +version = "0.9.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" dependencies = [ "cc", "libc", @@ -1204,6 +1768,21 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.0" @@ -1242,6 +1821,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" @@ -1255,7 +1855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", - "bitflags", + "bitflags 1.3.2", "cfg-if", "concurrent-queue", "libc", @@ -1281,6 +1881,30 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -1305,6 +1929,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "quoted_printable" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3866219251662ec3b26fc217e3e05bf9c4f84325234dfb96bf0bf840889e49" + [[package]] name = "rand" version = "0.7.3" @@ -1382,7 +2012,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1436,12 +2066,34 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted", "web-sys", "winapi", ] +[[package]] +name = "rsa" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +dependencies = [ + "byteorder", + "const-oid", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1463,11 +2115,24 @@ version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.7", "windows-sys", ] @@ -1545,6 +2210,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -1562,9 +2250,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.187" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7fe14252655bd1e578af19f5fa00fe02fd0013b100ca6b49fde31c41bae4c" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -1581,9 +2269,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.187" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46b2a6ca578b3f1d4501b12f78ed4692006d79d82a1a7c561c12dbc3d625eb8" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -1633,7 +2321,7 @@ dependencies = [ "async-trait", "async-tungstenite", "base64 0.13.1", - "bitflags", + "bitflags 1.3.2", "bytes 1.4.0", "cfg-if", "dashmap", @@ -1674,6 +2362,17 @@ dependencies = [ "sha1_smol", ] +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha1_smol" version = "1.0.0" @@ -1693,12 +2392,39 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + [[package]] name = "skynet_discord_bot" version = "0.1.0" dependencies = [ + "chrono", + "csv", "dotenvy", + "lettre", + "maud", + "serde", "serenity", + "sqlx", "surf", "tokio", ] @@ -1755,6 +2481,15 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.2.5" @@ -1764,6 +2499,221 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" +dependencies = [ + "itertools", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e58421b6bc416714d5115a2ca953718f6c621a51b68e4f4922aea5a4391a721" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4cef4251aabbae751a3710927945901ee1d97ee96d757f6880ebb9a79bfd53" +dependencies = [ + "ahash", + "atoi", + "byteorder", + "bytes 1.4.0", + "crc", + "crossbeam-queue", + "dotenvy", + "either", + "event-listener", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap 2.0.0", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2 0.10.7", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "208e3165167afd7f3881b16c1ef3f2af69fa75980897aac8874a0696516d12c2" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a4a8336d278c62231d87f24e8a7a74898156e34c1c18942857be2acb29c7dfc" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.7", + "sqlx-core", + "sqlx-mysql", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca69bf415b93b60b80dc8fda3cb4ef52b2336614d8da2de5456cc942a110482" +dependencies = [ + "atoi", + "base64 0.21.2", + "bitflags 2.4.0", + "byteorder", + "bytes 1.4.0", + "crc", + "digest 0.10.7", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf 0.12.3", + "hmac 0.12.1", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1 0.10.5", + "sha2 0.10.7", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0db2df1b8731c3651e204629dd55e52adbae0462fa1bdcbed56a2302c18181e" +dependencies = [ + "atoi", + "base64 0.21.2", + "bitflags 2.4.0", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf 0.12.3", + "hmac 0.12.1", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha1 0.10.5", + "sha2 0.10.7", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2" +dependencies = [ + "atoi", + "flume 0.10.14", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", +] + [[package]] name = "standback" version = "0.2.17" @@ -1812,7 +2762,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "sha1", + "sha1 0.6.1", "syn 1.0.109", ] @@ -1822,6 +2772,17 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "stringprep" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +dependencies = [ + "finl_unicode", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "subtle" version = "2.4.1" @@ -1873,6 +2834,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand 2.0.0", + "redox_syscall", + "rustix 0.38.13", + "windows-sys", +] + [[package]] name = "thiserror" version = "1.0.47" @@ -2023,6 +2997,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.8" @@ -2155,6 +3140,18 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "universal-hash" version = "0.4.1" @@ -2178,7 +3175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", - "idna", + "idna 0.4.0", "percent-encoding", "serde", ] @@ -2348,6 +3345,12 @@ version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +[[package]] +name = "whoami" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" + [[package]] name = "winapi" version = "0.3.9" @@ -2370,6 +3373,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2445,3 +3457,9 @@ dependencies = [ "cfg-if", "windows-sys", ] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index bc2fa7e..5bbb73a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[[bin]] +name = "update_data" + +[[bin]] +name = "update_users" + + [dependencies] serenity = { version = "0.11.6", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } @@ -12,4 +19,19 @@ tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } # to make the http requests surf = "2.3.2" -dotenvy = "0.15.7" \ No newline at end of file +dotenvy = "0.15.7" + +# For sqlite +sqlx = { version = "0.7.1", features = [ "runtime-tokio", "sqlite" ] } + +# fancy time stuff +chrono = "0.4.26" + +# handlign teh csv export from wolves +csv = "1.2" + +# for email +lettre = "0.10.4" +maud = "0.25.0" + +serde = "1.0.188" \ No newline at end of file diff --git a/flake.nix b/flake.nix index e02e454..94270a6 100644 --- a/flake.nix +++ b/flake.nix @@ -52,6 +52,10 @@ LDAP_API = cfg.ldap; DISCORD_TIMING_UPDATE = cfg.discord.timing.update; DISCORD_TIMING_FETCH = cfg.discord.timing.fetch; + + # local details + HOME = cfg.home; + DATABASE = "database.db"; }; in { options.services."${package_name}" = { @@ -66,6 +70,10 @@ type = types.str; description = "ENV file with DISCORD_TOKEN"; }; + mail = mkOption rec { + type = types.str; + description = "ENV file with EMAIL_SMTP, EMAIL_USER, EMAIL_PASS"; + }; }; discord = { @@ -102,9 +110,37 @@ default = "https://api.account.skynet.ie"; description = "Location of the ldap api"; }; + + user = mkOption rec { + type = types.str; + default = "${package_name}"; + description = "The user to run the service"; + }; + + home = mkOption rec { + type = types.str; + default = "/etc/${cfg.prefix}${package_name}"; + description = "The home for the user"; + }; + + prefix = mkOption rec { + type = types.str; + default = "skynet_"; + example = default; + description = "The prefix used to name service/folders"; + }; }; config = mkIf cfg.enable { + + users.groups."${cfg.user}" = { }; + + users.users."${cfg.user}" = { + createHome = true; + isSystemUser = true; + home = "${cfg.home}"; + group = "${cfg.user}"; + }; systemd.services = { # main service @@ -116,13 +152,15 @@ environment = environment_config; serviceConfig = { - DynamicUser = "yes"; + User = "${cfg.user}"; + Group = "${cfg.user}"; Restart = "always"; ExecStart = "${self.defaultPackage."${system}"}/bin/${package_name}"; # can have multiple env files EnvironmentFile = [ "${cfg.env.ldap}" "${cfg.env.discord}" + "${cfg.env.mail}" ]; }; }; diff --git a/src/bin/update_data.rs b/src/bin/update_data.rs new file mode 100644 index 0000000..d4eb3c8 --- /dev/null +++ b/src/bin/update_data.rs @@ -0,0 +1,241 @@ +use skynet_discord_bot::{db_init, get_config, get_server_config_bulk, Accounts, Config, Servers}; + +use serde::Deserialize; +use serenity::model::id::GuildId; +use sqlx::{Pool, Sqlite}; + +#[tokio::main] +async fn main() { + let config = get_config(); + let db = match db_init(&config).await { + Ok(x) => x, + Err(_) => return, + }; + + // handle wolves api here + get_wolves_csv(&db, &config).await; + // handle wolves api here + get_wolves(&db).await; + // get from skynet for the compsoc server only + get_skynet(&db, &config).await; +} + +async fn get_wolves_csv(db: &Pool, config: &Config) { + if let Ok(accounts) = get_csv(config) { + for account in accounts { + add_users_wolves_csv(db, &config.skynet_server, &account).await; + } + } +} + +#[derive(Debug, serde::Deserialize)] +struct RecordCSV { + #[serde(rename = "MemID")] + mem_id: String, + #[serde(rename = "Contact Email")] + email: String, + #[serde(rename = "Expiry")] + expiry: String, +} + +impl From for Accounts { + fn from(input: RecordCSV) -> Self { + Self { + server: Default::default(), + id_wolves: "".to_string(), + id_member: input.mem_id, + email: input.email, + expiry: input.expiry, + discord: None, + minecraft: None, + } + } +} + +fn get_csv(config: &Config) -> Result, Box> { + let mut records: Vec = vec![]; + + let csv = format!("{}/{}", &config.home, &config.csv); + if let Ok(mut rdr) = csv::Reader::from_path(csv) { + for result in rdr.deserialize() { + // Notice that we need to provide a type hint for automatic + // deserialization. + let record: RecordCSV = result?; + if record.mem_id.is_empty() { + continue; + } + records.push(Accounts::from(record)); + } + } + + Ok(records) +} +async fn add_users_wolves_csv(db: &Pool, server: &GuildId, user: &Accounts) { + let existing = match sqlx::query_as::<_, Accounts>( + r#" + SELECT * + FROM accounts + WHERE server = ? AND id_member = ? + "#, + ) + .bind(*server.as_u64() as i64) + .bind(&user.id_member) + .fetch_one(db) + .await + { + Ok(acc) => acc.id_wolves, + Err(_) => String::new(), + }; + + match sqlx::query_as::<_, Accounts>( + " + INSERT OR REPLACE INTO accounts (server, id_wolves, id_member, email, expiry) + VALUES (?1, ?2, ?3, ?4, ?5) + ", + ) + .bind(*server.as_u64() as i64) + .bind(&existing) + .bind(&user.id_member) + .bind(&user.email) + .bind(&user.expiry) + .fetch_optional(db) + .await + { + Ok(_) => {} + Err(e) => { + println!("Failure to insert into {} {:?}", server.as_u64(), user); + println!("{:?}", e); + } + } +} + +#[derive(Debug, Deserialize)] +pub struct SkynetResult { + discord: String, + id_wolves: String, + id_member: String, +} +async fn get_skynet(db: &Pool, config: &Config) { + let url = format!("{}/ldap/discord?auth={}", &config.ldap_api, &config.auth); + if let Ok(result) = surf::get(url).recv_json::>().await { + for user in result { + add_users_skynet(db, &config.skynet_server, &user).await; + } + } +} +async fn add_users_skynet(db: &Pool, server: &GuildId, user: &SkynetResult) { + if !user.id_wolves.is_empty() { + match sqlx::query_as::<_, Accounts>( + " + UPDATE accounts + SET discord = ? + WHERE server = ? AND id_wolves = ? + ", + ) + .bind(&user.discord) + .bind(*server.as_u64() as i64) + .bind(&user.id_wolves) + .fetch_optional(db) + .await + { + Ok(_) => {} + Err(e) => { + println!("Failure to insert into {} {:?}", server.as_u64(), user); + println!("{:?}", e); + } + } + } + if !user.id_member.is_empty() { + match sqlx::query_as::<_, Accounts>( + " + UPDATE accounts + SET discord = ? + WHERE server = ? AND id_member = ? + ", + ) + .bind(&user.discord) + .bind(*server.as_u64() as i64) + .bind(&user.id_member) + .fetch_optional(db) + .await + { + Ok(_) => {} + Err(e) => { + println!("Failure to insert into {} {:?}", server.as_u64(), user); + println!("{:?}", e); + } + } + } +} + +#[derive(Debug, Deserialize)] +struct WolvesResult { + pub id_wolves: String, + pub id_member: String, + pub email: String, + pub expiry: String, +} +async fn get_wolves(db: &Pool) { + for server_config in get_server_config_bulk(db).await { + let Servers { + server, + //wolves_api, + .. + } = server_config; + + // get the data here + let result: Vec = vec![WolvesResult { + id_wolves: "12345".to_string(), + id_member: "166425".to_string(), + email: "ul.wolves2@brendan.ie".to_string(), + expiry: "2024-08-31".to_string(), + }]; + + for user in result { + add_users_wolves(db, &server, &user).await; + } + } +} + +async fn add_users_wolves(db: &Pool, server: &GuildId, user: &WolvesResult) { + match sqlx::query_as::<_, Accounts>( + " + UPDATE accounts + SET id_wolves = ? + WHERE server = ? AND id_member = ? + ", + ) + .bind(&user.id_wolves) + .bind(*server.as_u64() as i64) + .bind(&user.id_member) + .fetch_optional(db) + .await + { + Ok(_) => {} + Err(e) => { + println!("Failure to update into {} {:?}", server.as_u64(), user); + println!("{:?}", e); + } + } + + match sqlx::query_as::<_, Accounts>( + " + INSERT OR REPLACE INTO accounts (server, id_wolves, id_member, email, expiry) + VALUES (?1, ?2, ?3, ?4, ?5) + ", + ) + .bind(*server.as_u64() as i64) + .bind(&user.id_wolves) + .bind(&user.id_member) + .bind(&user.email) + .bind(&user.expiry) + .fetch_optional(db) + .await + { + Ok(_) => {} + Err(e) => { + println!("Failure to insert into {} {:?}", server.as_u64(), user); + println!("{:?}", e); + } + } +} diff --git a/src/bin/update_users.rs b/src/bin/update_users.rs new file mode 100644 index 0000000..e4c6c28 --- /dev/null +++ b/src/bin/update_users.rs @@ -0,0 +1,169 @@ +use serenity::{ + async_trait, + client::{Context, EventHandler}, + model::{ + gateway::{GatewayIntents, Ready}, + id::GuildId, + }, + Client, +}; +use skynet_discord_bot::{db_init, get_config, get_now_iso, get_server_config_bulk, Accounts, Config, DataBase, Servers}; +use sqlx::{Pool, Sqlite}; +use std::{process, sync::Arc}; +use tokio::sync::RwLock; + +#[tokio::main] +async fn main() { + let config = get_config(); + let db = match db_init(&config).await { + Ok(x) => x, + Err(_) => return, + }; + + // Intents are a bitflag, bitwise operations can be used to dictate which intents to use + let intents = GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT | GatewayIntents::GUILD_MEMBERS; + // Build our client. + let mut client = Client::builder(&config.discord_token, intents) + .event_handler(Handler {}) + .await + .expect("Error creating client"); + + { + let mut data = client.data.write().await; + + data.insert::(Arc::new(RwLock::new(config))); + data.insert::(Arc::new(RwLock::new(db))); + } + + if let Err(why) = client.start().await { + println!("Client error: {:?}", why); + } +} + +struct Handler; +#[async_trait] +impl EventHandler for Handler { + async fn ready(&self, ctx: Context, ready: Ready) { + let ctx = Arc::new(ctx); + println!("{} is connected!", ready.user.name); + + bulk_check(Arc::clone(&ctx)).await; + + // finish up + process::exit(0); + } +} + +async fn bulk_check(ctx: Arc) { + let db_lock = { + let data_read = ctx.data.read().await; + data_read.get::().expect("Expected Config in TypeMap.").clone() + }; + + let db = db_lock.read().await; + + for server_config in get_server_config_bulk(&db).await { + let Servers { + server, + role_past, + role_current, + .. + } = server_config; + + let mut roles_set = [0, 0, 0]; + let mut members = vec![]; + + for member in get_server_member_bulk(&db, &server).await { + if let Some(x) = member.discord { + members.push(x); + } + } + let mut members_all = members.len(); + + if let Ok(x) = server.members(&ctx, None, None).await { + for mut member in x { + if members.contains(&member.user.name) { + let mut roles = vec![]; + + if let Some(role) = &role_past { + if !member.roles.contains(role) { + roles_set[0] += 1; + roles.push(role.to_owned()); + } + } + + if let Some(role) = &role_current { + if !member.roles.contains(role) { + roles_set[1] += 1; + roles.push(role.to_owned()); + } + } + + if let Err(e) = member.add_roles(&ctx, &roles).await { + println!("{:?}", e); + } + } else { + // old and never + + if let Some(role) = &role_past { + if member.roles.contains(role) { + members_all += 1; + } + } + + if let Some(role) = &role_current { + if member.roles.contains(role) { + roles_set[2] += 1; + // if theya re not a current member and have the role then remove it + if let Err(e) = member.remove_role(&ctx, role).await { + println!("{:?}", e); + } + } + } + } + } + } + + set_server_numbers(&db, &server, members_all as i64, members.len() as i64).await; + + // small bit of logging to note changes over time + println!("{:?} Changes: New: +{}, Current: +{}/-{}", server.as_u64(), roles_set[0], roles_set[1], roles_set[2]); + } +} + +async fn get_server_member_bulk(db: &Pool, server: &GuildId) -> Vec { + sqlx::query_as::<_, Accounts>( + r#" + SELECT * + FROM accounts + WHERE server = ? AND discord IS NOT NULL AND expiry > ? + "#, + ) + .bind(*server.as_u64() as i64) + .bind(get_now_iso(true)) + .fetch_all(db) + .await + .unwrap_or_default() +} + +async fn set_server_numbers(db: &Pool, server: &GuildId, past: i64, current: i64) { + match sqlx::query_as::<_, Accounts>( + " + UPDATE servers + SET member_past = ?, member_current = ? + WHERE server = ? + ", + ) + .bind(past) + .bind(current) + .bind(*server.as_u64() as i64) + .fetch_optional(db) + .await + { + Ok(_) => {} + Err(e) => { + println!("Failure to insert into {}", server.as_u64()); + println!("{:?}", e); + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4a33b54 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,270 @@ +use dotenvy::dotenv; +use serde::{Deserialize, Serialize}; +use serenity::{ + model::{ + guild, + id::{GuildId, RoleId}, + }, + prelude::TypeMapKey, +}; + +use chrono::{Datelike, SecondsFormat, Utc}; +use sqlx::{ + sqlite::{SqliteConnectOptions, SqlitePoolOptions, SqliteRow}, + Error, FromRow, Pool, Row, Sqlite, +}; +use std::{env, str::FromStr, sync::Arc}; +use tokio::sync::RwLock; + +pub struct Config { + pub skynet_server: GuildId, + pub ldap_api: String, + pub auth: String, + pub timing_update: u64, + pub timing_fetch: u64, + pub discord_token: String, + + pub home: String, + pub database: String, + pub csv: String, + + pub mail_smtp: String, + pub mail_user: String, + pub mail_pass: String, +} +impl TypeMapKey for Config { + type Value = Arc>; +} + +pub struct DataBase; +impl TypeMapKey for DataBase { + type Value = Arc>>; +} + +pub fn get_config() -> Config { + dotenv().ok(); + + // reasonable defaults + let mut config = Config { + skynet_server: Default::default(), + ldap_api: "https://api.account.skynet.ie".to_string(), + auth: "".to_string(), + timing_update: 0, + timing_fetch: 0, + discord_token: "".to_string(), + + home: ".".to_string(), + database: "database.db".to_string(), + csv: "wolves.csv".to_string(), + + mail_smtp: "".to_string(), + mail_user: "".to_string(), + mail_pass: "".to_string(), + }; + + if let Ok(x) = env::var("SKYNET_SERVER") { + config.skynet_server = GuildId::from(str_to_num::(&x)); + } + if let Ok(x) = env::var("LDAP_API") { + config.ldap_api = x.trim().to_string(); + } + if let Ok(x) = env::var("LDAP_DISCORD_AUTH") { + config.auth = x.trim().to_string(); + } + if let Ok(x) = env::var("DISCORD_TIMING_UPDATE") { + config.timing_update = str_to_num::(&x); + } + if let Ok(x) = env::var("DISCORD_TIMING_FETCH") { + config.timing_fetch = str_to_num::(&x); + } + if let Ok(x) = env::var("DISCORD_TOKEN") { + config.discord_token = x.trim().to_string(); + } + + if let Ok(x) = env::var("HOME") { + config.home = x.trim().to_string(); + } + if let Ok(x) = env::var("DATABASE") { + config.database = x.trim().to_string(); + } + if let Ok(x) = env::var("CSV") { + config.csv = x.trim().to_string(); + } + + if let Ok(x) = env::var("EMAIL_SMTP") { + config.mail_smtp = x.trim().to_string(); + } + if let Ok(x) = env::var("EMAIL_USER") { + config.mail_user = x.trim().to_string(); + } + if let Ok(x) = env::var("EMAIL_PASS") { + config.mail_pass = x.trim().to_string(); + } + + config +} + +fn str_to_num(x: &str) -> T { + x.trim().parse::().unwrap_or_default() +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Accounts { + pub server: GuildId, + pub id_wolves: String, + pub id_member: String, + pub email: String, + pub expiry: String, + pub discord: Option, + pub minecraft: Option, +} + +impl<'r> FromRow<'r, SqliteRow> for Accounts { + fn from_row(row: &'r SqliteRow) -> Result { + let server_tmp: i64 = row.try_get("server")?; + let server = GuildId::from(server_tmp as u64); + + Ok(Self { + server, + id_wolves: row.try_get("id_wolves")?, + id_member: row.try_get("id_member")?, + email: row.try_get("email")?, + expiry: row.try_get("expiry")?, + discord: row.try_get("discord")?, + minecraft: row.try_get("minecraft")?, + }) + } +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Servers { + pub server: GuildId, + pub wolves_api: String, + pub role_past: Option, + pub role_current: Option, + pub member_past: i64, + pub member_current: i64, +} +impl<'r> FromRow<'r, SqliteRow> for Servers { + fn from_row(row: &'r SqliteRow) -> Result { + let server_tmp: i64 = row.try_get("server")?; + let server = GuildId::from(server_tmp as u64); + let role_past = match row.try_get("role_past") { + Ok(x) => { + let tmp: i64 = x; + Some(RoleId::from(tmp as u64)) + } + _ => None, + }; + let role_current = match row.try_get("role_current") { + Ok(x) => { + let tmp: i64 = x; + Some(RoleId::from(tmp as u64)) + } + _ => None, + }; + + Ok(Self { + server, + wolves_api: row.try_get("wolves_api")?, + role_past, + role_current, + member_past: row.try_get("member_past")?, + member_current: row.try_get("member_current")?, + }) + } +} + +pub async fn db_init(config: &Config) -> Result, Error> { + let database = format!("{}/{}", &config.home, &config.database); + + let pool = SqlitePoolOptions::new() + .max_connections(5) + .connect_with(SqliteConnectOptions::from_str(&format!("sqlite://{}", database))?.create_if_missing(true)) + .await?; + + sqlx::query( + "CREATE TABLE IF NOT EXISTS accounts ( + server integer not null, + id_wolves text DEFAULT '', + id_member text DEFAULT '', + email text not null, + expiry text not null, + discord text, + minecraft text, + PRIMARY KEY(server,id_wolves,id_member) + )", + ) + .execute(&pool) + .await?; + + sqlx::query("CREATE INDEX IF NOT EXISTS index_server ON accounts (server)").execute(&pool).await?; + sqlx::query("CREATE INDEX IF NOT EXISTS index_id_wolves ON accounts (id_wolves)") + .execute(&pool) + .await?; + + sqlx::query( + "CREATE TABLE IF NOT EXISTS servers ( + server integer key, + wolves_api text not null, + role_past integer, + role_current integer, + member_past integer DEFAULT 0, + member_current integer DEFAULT 0 + )", + ) + .execute(&pool) + .await?; + + Ok(pool) +} + +pub async fn get_server_config(db: &Pool, server: &GuildId) -> Option { + sqlx::query_as::<_, Servers>( + r#" + SELECT * + FROM servers + WHERE server = ? + "#, + ) + .bind(*server.as_u64() as i64) + .fetch_one(db) + .await + .ok() +} + +pub async fn get_server_member(db: &Pool, server: &GuildId, member: &guild::Member) -> Option { + sqlx::query_as::<_, Accounts>( + r#" + SELECT * + FROM accounts + WHERE server = ? AND discord = ? + "#, + ) + .bind(*server.as_u64() as i64) + .bind(&member.user.name) + .fetch_one(db) + .await + .ok() +} + +pub async fn get_server_config_bulk(db: &Pool) -> Vec { + sqlx::query_as::<_, Servers>( + r#" + SELECT * + FROM servers + "#, + ) + .fetch_all(db) + .await + .unwrap_or_default() +} + +pub fn get_now_iso(short: bool) -> String { + let now = Utc::now(); + if short { + format!("{}-{:02}-{:02}", now.year(), now.month(), now.day()) + } else { + now.to_rfc3339_opts(SecondsFormat::Millis, true) + } +} diff --git a/src/main.rs b/src/main.rs index 6b3936a..63431be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,53 +1,46 @@ -use dotenvy::dotenv; use serenity::{ async_trait, client::{Context, EventHandler}, model::{ gateway::{GatewayIntents, Ready}, - guild::Member, - id::GuildId, - prelude::RoleId, + guild, }, - prelude::TypeMapKey, Client, }; -use std::{ - env, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, - time::Duration, -}; +use std::sync::Arc; + +use skynet_discord_bot::{db_init, get_config, get_server_config, get_server_member, Config, DataBase}; use tokio::sync::RwLock; -struct Handler { - is_loop_running: AtomicBool, -} +struct Handler; #[async_trait] impl EventHandler for Handler { - async fn guild_member_addition(&self, ctx: Context, mut new_member: Member) { - let config_lock = { + async fn guild_member_addition(&self, ctx: Context, mut new_member: guild::Member) { + let db_lock = { let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Config in TypeMap.").clone() + data_read.get::().expect("Expected Config in TypeMap.").clone() }; - let config = config_lock.read().await; - let members_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Members in TypeMap.").clone() + let db = db_lock.read().await; + let config = match get_server_config(&db, &new_member.guild_id).await { + None => return, + Some(x) => x, }; - let members = members_lock.read().await; - if members.contains(&new_member.user.name) { + if get_server_member(&db, &new_member.guild_id, &new_member).await.is_some() { let mut roles = vec![]; - if !new_member.roles.contains(&config.member_role_past) { - roles.push(config.member_role_past); + if let Some(role) = &config.role_past { + if !new_member.roles.contains(role) { + roles.push(role.to_owned()); + } } - if !new_member.roles.contains(&config.member_role_current) { - roles.push(config.member_role_current); + + if let Some(role) = &config.role_current { + if !new_member.roles.contains(role) { + roles.push(role.to_owned()); + } } if let Err(e) = new_member.add_roles(&ctx, &roles).await { @@ -56,171 +49,32 @@ impl EventHandler for Handler { } } - async fn ready(&self, ctx: Context, ready: Ready) { - let ctx = Arc::new(ctx); - println!("{} is connected!", ready.user.name); - - let config_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Config in TypeMap.").clone() - }; - let config = config_lock.read().await; - let timing_update = config.timing_update; - let timing_fetch = config.timing_fetch; - - if !self.is_loop_running.load(Ordering::Relaxed) { - // We have to clone the Arc, as it gets moved into the new thread. - let ctx1 = Arc::clone(&ctx); - // tokio::spawn creates a new green thread that can run in parallel with the rest of - // the application. - tokio::spawn(async move { - loop { - // We clone Context again here, because Arc is owned, so it moves to the - // new function. - bulk_check(Arc::clone(&ctx1)).await; - tokio::time::sleep(Duration::from_secs(timing_update)).await; - } - }); - - let ctx2 = Arc::clone(&ctx); - tokio::spawn(async move { - loop { - fetch_accounts(Arc::clone(&ctx2)).await; - tokio::time::sleep(Duration::from_secs(timing_fetch)).await; - } - }); - - // Now that the loop is running, we set the bool to true - self.is_loop_running.swap(true, Ordering::Relaxed); - } - } -} - -#[derive(Default, Debug)] -struct MembersCount { - members: i32, - members_current: i32, -} -struct MemberCounter; -impl TypeMapKey for MemberCounter { - type Value = Arc>; -} - -struct Members; -impl TypeMapKey for Members { - type Value = Arc>>; -} -async fn bulk_check(ctx: Arc) { - let config_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Config in TypeMap.").clone() - }; - let config = config_lock.read().await; - - let members_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Members in TypeMap.").clone() - }; - let members = members_lock.read().await; - - let mut roles_set = [0, 0, 0]; - let mut res = MembersCount { - members: 0, - members_current: 0, - }; - if let Ok(x) = config.server.members(&ctx, None, None).await { - for mut member in x { - if members.contains(&member.user.name) { - let mut roles = vec![]; - - if !member.roles.contains(&config.member_role_past) { - roles_set[0] += 1; - roles.push(config.member_role_past); - } - if !member.roles.contains(&config.member_role_current) { - roles_set[1] += 1; - roles.push(config.member_role_current); - } - - if let Err(e) = member.add_roles(&ctx, &roles).await { - println!("{:?}", e); - } - } else if member.roles.contains(&config.member_role_current) { - roles_set[2] += 1; - // if theya re not a current member and have the role then remove it - if let Err(e) = member.remove_role(&ctx, &config.member_role_current).await { - println!("{:?}", e); - } - } - - if member.roles.contains(&config.member_role_past) { - res.members += 1; - } - if member.roles.contains(&config.member_role_current) { - res.members_current += 1; - } - } - } - // small bit of logging to note changes over time - println!("Changes: New: +{}, Current: +{}/-{}", roles_set[0], roles_set[1], roles_set[2]); - - { - let data_read = ctx.data.read().await; - let counter_lock = data_read.get::().expect("Expected MemberCounter in TypeMap.").clone(); - // The HashMap of CommandCounter is wrapped in an RwLock; since we want to write to it, we will - // open the lock in write mode. - let mut counter = counter_lock.write().await; - - // And we write the amount of times the command has been called to it. - counter.members_current = res.members_current; - counter.members = res.members; - }; -} - -async fn fetch_accounts(ctx: Arc) { - let config_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Config in TypeMap.").clone() - }; - let config = config_lock.read().await; - let auth = &config.auth; - let ldap_api = &config.ldap_api; - let url = format!("{}/ldap/discord?auth={}", ldap_api, auth); - if let Ok(result) = surf::get(url).recv_json::>().await { - let members_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Members in TypeMap.").clone() - }; - let mut accounts = members_lock.write().await; - *accounts = result; + async fn ready(&self, _ctx: Context, ready: Ready) { + println!("[Main] {} is connected!", ready.user.name); } } #[tokio::main] async fn main() { let config = get_config(); + let db = match db_init(&config).await { + Ok(x) => x, + Err(_) => return, + }; // Intents are a bitflag, bitwise operations can be used to dictate which intents to use let intents = GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT | GatewayIntents::GUILD_MEMBERS; // Build our client. let mut client = Client::builder(&config.discord_token, intents) - .event_handler(Handler { - is_loop_running: AtomicBool::new(false), - }) + .event_handler(Handler {}) .await .expect("Error creating client"); { let mut data = client.data.write().await; - // will keep track of how many past and current members we have - data.insert::(Arc::new(RwLock::new(MembersCount::default()))); - - // a list of all current members - data.insert::(Arc::new(RwLock::new(vec![]))); - - // make config available top all, strangely its easier to keep it in a shared lock state. data.insert::(Arc::new(RwLock::new(config))); + data.insert::(Arc::new(RwLock::new(db))); } // Finally, start a single shard, and start listening to events. @@ -231,62 +85,3 @@ async fn main() { println!("Client error: {:?}", why); } } - -struct Config { - server: GuildId, - member_role_current: RoleId, - member_role_past: RoleId, - ldap_api: String, - auth: String, - timing_update: u64, - timing_fetch: u64, - discord_token: String, -} -impl TypeMapKey for Config { - type Value = Arc>; -} -fn get_config() -> Config { - dotenv().ok(); - - // reasonable defaults - let mut config = Config { - server: Default::default(), - member_role_current: Default::default(), - member_role_past: Default::default(), - ldap_api: "https://api.account.skynet.ie".to_string(), - auth: "".to_string(), - timing_update: 0, - timing_fetch: 0, - discord_token: "".to_string(), - }; - - if let Ok(x) = env::var("DISCORD_SERVER") { - config.server = GuildId::from(str_to_num::(&x)); - } - if let Ok(x) = env::var("DISCORD_ROLE_CURRENT") { - config.member_role_current = RoleId::from(str_to_num::(&x)); - } - if let Ok(x) = env::var("DISCORD_ROLE_PAST") { - config.member_role_past = RoleId::from(str_to_num::(&x)); - } - if let Ok(x) = env::var("LDAP_API") { - config.ldap_api = x.trim().to_string(); - } - if let Ok(x) = env::var("LDAP_DISCORD_AUTH") { - config.auth = x.trim().to_string(); - } - if let Ok(x) = env::var("DISCORD_TIMING_UPDATE") { - config.timing_update = str_to_num::(&x); - } - if let Ok(x) = env::var("DISCORD_TIMING_FETCH") { - config.timing_fetch = str_to_num::(&x); - } - if let Ok(x) = env::var("DISCORD_TOKEN") { - config.discord_token = x.trim().to_string(); - } - config -} - -fn str_to_num(x: &str) -> T { - x.trim().parse::().unwrap_or_default() -}