commit c56c423491aec1fcaa976406a0a69d8aeb682228 Author: ChaotiCryptidz Date: Mon Aug 22 16:39:05 2022 +0100 Initial commit diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7179f6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target +dist +build +result +.direnv \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..92b78ae --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1671 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "android_system_properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" +dependencies = [ + "libc", +] + +[[package]] +name = "async-trait" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-tungstenite" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b71b31561643aa8e7df3effe284fa83ab1a840e52294c5f4bd7bfd8b2becbb" +dependencies = [ + "futures-io", + "futures-util", + "log", + "pin-project-lite", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +dependencies = [ + "iana-time-zone", + "num-integer", + "num-traits", + "serde", + "winapi", +] + +[[package]] +name = "clap" +version = "3.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29e724a68d9319343bb3328c9cc2dfde263f4b3142ee1059a9980580171c954b" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13547f7012c01ab4a0e8f8967730ada8f9fdf419e8b6c792788f39cf4e46eefa" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "command_attr" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d999d4e7731150ee14aee8f619c7a9aa9a4385bca0606c4fa95aa2f36a05d9a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1079fb8528d9f9c888b1e8aa651e6e079ade467323d58f75faf1d30b1808f540" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dashmap" +version = "5.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "parking_lot_core", + "serde", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab30e97ab6aacfe635fad58f22c2bb06c8b685f7421eb1e064a729e2a5f481fa" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfc52cbddcfd745bf1740338492bb0bd83d76c67b445f91c5fb29fae29ecaa1" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2acedae88d38235936c3922476b10fced7b2b68136f5e3c03c2d5be348a1115" + +[[package]] +name = "futures-io" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93a66fc6d035a26a3ae255a6d2bca35eda63ae4c5512bef54449113f7a1228e5" + +[[package]] +name = "futures-sink" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0bae1fe9752cf7fd9b0064c674ae63f97b37bc714d745cbde0afb7ec4e6765" + +[[package]] +name = "futures-task" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "842fc63b931f4056a24d59de13fb1272134ce261816e063e634ad0c15cdc5306" + +[[package]] +name = "futures-util" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0828a5471e340229c11c77ca80017937ce3c58cb788a17e5f1c2d5c485a9577" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "h2" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +dependencies = [ + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + +[[package]] +name = "itoa" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "js-sys" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "levenshtein" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" + +[[package]] +name = "libc" +version = "0.2.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[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-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits", +] + +[[package]] +name = "os_str_bytes" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[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", + "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-macro2" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[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", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "reqwest" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustls" +version = "0.20.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +dependencies = [ + "base64", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.143" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.143" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50845f68d5c693aac7d72a25415ddd21cb8182c04eafe447b73af55a05f9e1b" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "serenity" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fd5e7b5858ad96e99d440138f34f5b98e1b959ebcd3a1036203b30e78eb788" +dependencies = [ + "async-trait", + "async-tungstenite", + "base64", + "bitflags", + "bytes", + "cfg-if", + "chrono", + "command_attr", + "dashmap", + "flate2", + "futures", + "levenshtein", + "mime", + "mime_guess", + "parking_lot", + "percent-encoding", + "reqwest", + "serde", + "serde-value", + "serde_json", + "static_assertions", + "time", + "tokio", + "tracing", + "typemap_rev", + "url", + "uwl", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stickerdeploy" +version = "0.1.0" +dependencies = [ + "clap", + "indexmap", + "reqwest", + "serde", + "serde_json", + "serde_with", + "serde_yaml", + "serenity", + "tokio", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "thiserror" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db76ff9fa4b1458b3c7f077f3ff9887394058460d21e634355b273aaf11eea45" +dependencies = [ + "itoa", + "libc", + "num_threads", + "serde", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "tungstenite" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "rustls", + "sha-1", + "thiserror", + "url", + "utf-8", + "webpki", +] + +[[package]] +name = "typemap_rev" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5b74f0a24b5454580a79abb6994393b09adf0ab8070f15827cb666255de155" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "931179334a56395bcf64ba5e0ff56781381c1a5832178280c7d7f91d1679aeb0" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uwl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4bf03e0ca70d626ecc4ba6b0763b934b6f2976e8c744088bb3c1d646fbb1ad0" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" + +[[package]] +name = "web-sys" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d818707 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "stickerdeploy" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1.0" +serde_yaml = "0.9.9" +serde_with = "1.3.1" +serenity = { version = "0.11" } +indexmap = "1.9.1" +reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls-native-roots", "json", "multipart"] } +clap = { version = "3.2.17", features = ["derive"] } diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..80aeb43 --- /dev/null +++ b/default.nix @@ -0,0 +1,6 @@ +(import (let lock = builtins.fromJSON (builtins.readFile ./flake.lock); +in fetchTarball { + url = + "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flake-compat.locked.narHash; +}) { src = ./.; }).defaultNix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..85eb2e3 --- /dev/null +++ b/flake.lock @@ -0,0 +1,60 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1660862418, + "narHash": "sha256-/TT9ETUgMREkW8p1hco/yWkVQ6sGfaXrDswhmJpFYqE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d7a4a9397f769980f5a87f3e2d23acd434c295e3", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-22.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": "nixpkgs", + "utils": "utils" + } + }, + "utils": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..418da17 --- /dev/null +++ b/flake.nix @@ -0,0 +1,56 @@ +{ + description = "A tool for deploying sticker packs"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/release-22.05"; + utils.url = "github:numtide/flake-utils"; + flake-compat = { + url = "github:edolstra/flake-compat"; + flake = false; + }; + }; + + outputs = { self, nixpkgs, utils, ... }: + { + overlay = final: prev: + let system = final.system; + in { + stickerdeploy = final.rustPlatform.buildRustPackage rec { + pname = "stickerdeploy"; + version = "latest"; + + src = ./.; + cargoLock = { lockFile = ./Cargo.lock; }; + + doCheck = false; + nativeBuildInputs = with final.pkgs; [ pkg-config rustc cargo ]; + }; + }; + } // utils.lib.eachSystem (utils.lib.defaultSystems) (system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ self.overlay ]; + }; + in { + defaultPackage = self.packages."${system}".stickerdeploy; + packages.stickerdeploy = pkgs.stickerdeploy; + + apps = rec { + stickerdeploy = { + type = "app"; + program = "${self.defaultPackage.${system}}/bin/stickerdeploy"; + }; + default = stickerdeploy; + }; + + defaultApp = self.apps."${system}".stickerdeploy; + + devShell = pkgs.mkShell { + RUST_SRC_PATH = pkgs.rustPlatform.rustLibSrc; + buildInputs = with pkgs; [ rustc cargo rust-analyzer rustfmt clippy ]; + }; + + lib = pkgs.stickerdeploy.lib; + }); +} diff --git a/src/creds.rs b/src/creds.rs new file mode 100644 index 0000000..f27554a --- /dev/null +++ b/src/creds.rs @@ -0,0 +1,7 @@ +use serde::Deserialize; + +#[derive(Debug, Clone, Deserialize)] +pub struct Creds { + pub discord_bot_token: String, + pub telegram_bot_token: String, +} diff --git a/src/deploy_discord.rs b/src/deploy_discord.rs new file mode 100644 index 0000000..c0e84dc --- /dev/null +++ b/src/deploy_discord.rs @@ -0,0 +1,220 @@ +use crate::creds::Creds; +use crate::sticker_config::{DiscordDeployLocation, Sticker, StickerConfig, StickerType}; +use indexmap::IndexMap; +use serenity::http::client::Http as DiscordClient; +//use serenity::cache::Cache as DiscordCache; + +use serenity::model::prelude::Emoji; +use std::collections::{HashMap, VecDeque}; + +use serde_json::json; + +fn split_by( + pack_contents: &[String], + sticker_type: StickerType, + deploy_locations: &[DiscordDeployLocation], + pack_emojis: &HashMap, +) -> IndexMap> { + let pack_type_emoji_count = pack_emojis + .iter() + .filter(|emoji| emoji.1.r#type == sticker_type) + .count(); + + let max_type_emoji_total: u64 = deploy_locations + .iter() + .map(|loc| { + return match sticker_type { + StickerType::Regular => loc.max_regular_emoji, + StickerType::Gif => loc.max_animated_emoji, + _ => unreachable!("wrong sticker type for discord"), + }; + }) + .sum(); + + if pack_type_emoji_count > max_type_emoji_total.try_into().unwrap() { + panic!("not enough space in servers for emoji, please add more servers to deploy across") + } + + let mut pack_type_emojis: VecDeque<(String, Sticker)> = pack_contents + .iter() + .filter(|emoji| { + return pack_emojis.get(*emoji).unwrap().r#type == sticker_type; + }) + .map(|emoji| { + return (emoji.clone(), pack_emojis.get(emoji).unwrap().clone()); + }) + .collect(); + + let mut emojis_per_server: IndexMap> = IndexMap::new(); + for deploy_location in deploy_locations.iter() { + emojis_per_server.insert(deploy_location.deploy_name.clone(), Vec::new()); + } + + 'outer: for deploy_location in deploy_locations.iter() { + let mut sticker_count = 0; + + let max_type_emoji = match sticker_type { + StickerType::Regular => deploy_location.max_regular_emoji, + StickerType::Gif => deploy_location.max_animated_emoji, + _ => unreachable!("wrong sticker type for discord"), + }; + + while sticker_count < max_type_emoji { + let emoji = pack_type_emojis.pop_front(); + if emoji.is_none() { + break 'outer; + } + + emojis_per_server + .get_mut(&deploy_location.deploy_name) + .unwrap() + .push(emoji.unwrap()); + sticker_count += 1; + } + } + + emojis_per_server +} + +pub async fn deploy_discord( + deploy_id: String, + sticker_config: StickerConfig, + creds: Creds, + base_stickerdb_path: String, +) { + let discord_token = creds.discord_bot_token.as_str(); + let discord_client = DiscordClient::new(discord_token); + //let discord_cache = DiscordCache::new() + + let deploy_where = sticker_config.deploy_where.get(&deploy_id).unwrap(); + let deploy_locations = deploy_where.discord.as_ref().unwrap().clone(); + let deploy_locations_map: HashMap<_, _> = deploy_locations + .iter() + .map(|loc| (loc.deploy_name.clone(), loc)) + .collect(); + + let pack_contents = sticker_config.sticker_sets.get(&deploy_where.pack_id).unwrap(); + let pack_emojis: HashMap = pack_contents + .iter() + .map(|emoji_name| { + return ( + emoji_name.clone(), + sticker_config.stickers.get(emoji_name).unwrap().clone(), + ); + }) + .collect(); + + let mut emojis_per_server: IndexMap> = IndexMap::new(); + for deploy_location in deploy_locations.iter() { + emojis_per_server.insert(deploy_location.deploy_name.clone(), Vec::new()); + } + + // block only so can hide in IDE + { + let regular_emoji_per_server = split_by( + pack_contents, + StickerType::Regular, + &deploy_locations, + &pack_emojis, + ); + + for loc in regular_emoji_per_server.into_iter() { + emojis_per_server + .get_mut(&loc.0) + .unwrap() + .extend(loc.1.into_iter()); + } + + let gif_emoji_per_server = split_by( + pack_contents, + StickerType::Gif, + &deploy_locations, + &pack_emojis, + ); + + for loc in gif_emoji_per_server.into_iter() { + emojis_per_server + .get_mut(&loc.0) + .unwrap() + .extend(loc.1.into_iter()); + } + } + + for server_k_v in emojis_per_server.iter() { + let deploy_name = server_k_v.0.to_owned(); + let deploy_emojis = server_k_v.1.to_owned(); + + println!("Deploying to {}", deploy_name); + + let deploy_location = deploy_locations_map.get(&deploy_name).unwrap(); + + let deploy_emoji_names: Vec = deploy_emojis + .iter() + .map(|deploy_emoji| deploy_emoji.0.clone()) + .collect(); + + let discord_emojis = discord_client + .get_emojis(deploy_location.id) + .await + .expect("could not fetch discord emoji"); + let discord_emojis_names: Vec = discord_emojis + .iter() + .map(|emoji| emoji.name.clone()) + .collect(); + + let invalid_emojis: Vec = discord_emojis + .clone() + .into_iter() + .filter(|emoji| !deploy_emoji_names.contains(&emoji.name)) + .collect(); + + if !invalid_emojis.is_empty() { + for emoji in invalid_emojis.iter() { + println!("Removing Emoji {}", &emoji.name); + discord_client + .delete_emoji(deploy_location.id, emoji.id.0) + .await + .expect("could not delete emoji") + } + } + + let missing_emojis: Vec = deploy_emoji_names + .clone() + .into_iter() + .filter(|emoji| !discord_emojis_names.contains(emoji)) + .collect(); + + if !missing_emojis.is_empty() { + for emoji in missing_emojis.iter() { + println!("Uploading Emoji {}", &emoji); + let emoji_data = pack_emojis.get(emoji).unwrap(); + + let image_path = std::path::PathBuf::from(&base_stickerdb_path) + .join(std::path::PathBuf::from(emoji_data.file.clone())); + let image_data = + serenity::utils::read_image(image_path).expect("could not open emoji file"); + + discord_client + .create_emoji( + deploy_location.id, + &json!({ + "name": emoji, + "image": image_data, + }), + None, + ) + .await + .expect("could not upload emoji"); + } + } + + println!( + "Missing: {:#?}\nInvalid: {:#?}", + missing_emojis, invalid_emojis + ); + } + + //println!("{:#?}", emojis_per_server); + + //println!("{} {} {:?}", max_regular_emoji_total, max_animated_emoji_total, deploy_locations); +} diff --git a/src/deploy_telegram.rs b/src/deploy_telegram.rs new file mode 100644 index 0000000..042b313 --- /dev/null +++ b/src/deploy_telegram.rs @@ -0,0 +1,280 @@ +use std::io::Read; +use std::ops::Index; +use std::{collections::HashMap, error::Error}; + +use crate::{ + creds::Creds, + sticker_config::{Sticker, StickerConfig, StickerType}, + tg_api::{TelegramAPI, TelegramSticker}, +}; + +struct TelegramStickerIDState { + // File ID to Sticker Name + data: HashMap, + base_stickerdb_path: String, +} + +impl TelegramStickerIDState { + pub fn new(base_stickerdb_path: &str) -> Self { + TelegramStickerIDState { + data: HashMap::new(), + base_stickerdb_path: base_stickerdb_path.to_owned(), + } + } + + pub fn load(&mut self) -> Result<(), Box> { + let path = std::path::PathBuf::from(&self.base_stickerdb_path).join("telegram_state.yml"); + let file = std::fs::OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open(path)?; + let data: HashMap = serde_yaml::from_reader(file)?; + self.data.extend(data.into_iter()); + Ok(()) + } + pub fn save(&self) -> Result<(), Box> { + let path = std::path::PathBuf::from(&self.base_stickerdb_path).join("telegram_state.yml"); + let file = std::fs::OpenOptions::new() + .write(true) + .create(true) + .open(path)?; + serde_yaml::to_writer(file, &self.data)?; + Ok(()) + } + + pub fn get(&self, file_id: &String) -> Option<&String> { + self.data.get(file_id) + } + + pub fn set(&mut self, file_id: &str, sticker_name: &str) { + self.data.insert(file_id.to_owned(), sticker_name.to_owned()); + } +} + +pub async fn deploy_telegram( + deploy_id: String, + sticker_config: StickerConfig, + creds: Creds, + base_stickerdb_path: String, +) { + let mut tg_state = TelegramStickerIDState::new(&base_stickerdb_path); + tg_state.load().expect("could not load sticker state"); + + let deploy_where = sticker_config.deploy_where.get(&deploy_id).unwrap(); + + let deploy_location = deploy_where.telegram.as_ref().unwrap(); + + if deploy_location.r#type == StickerType::Gif { + panic!("gif stickers not supported on telegram, bodge it into video") + } + + let pack_contents = sticker_config + .sticker_sets + .get(&deploy_where.pack_id) + .unwrap(); + + let pack_stickers: HashMap = pack_contents + .iter() + .map(|sticker_name| { + return ( + sticker_name.clone(), + sticker_config.stickers.get(sticker_name).unwrap().clone(), + ); + }) + .collect(); + + let contains_invalid_stickers = pack_stickers + .iter() + .find(|sticker| sticker.1.r#type != deploy_location.r#type); + + if contains_invalid_stickers.is_some() { + panic!("pack contains a invalid type of emoji for pack type") + } + + let tg_bot = TelegramAPI::new(creds.telegram_bot_token); + let tg_sticker_set = tg_bot + .get_sticker_set(&deploy_location.name) + .await + .expect("could not get sticker pack"); + + let mut tg_stickers: Vec<(String, TelegramSticker)> = Vec::new(); + + // Delete stickers that arent in state + // add valid stickers to tg_stickers + { + let mut tg_sticker_set_iter = tg_sticker_set.stickers.iter(); + // Skip the first sticker + tg_sticker_set_iter.next(); + for sticker in tg_sticker_set_iter { + match tg_state.get(&sticker.file_unique_id) { + Some(sticker_name) => tg_stickers.push((sticker_name.clone(), sticker.clone())), + None => { + println!( + "Deleting sticker with unique_id {} as is not in state", + &sticker.file_unique_id + ); + tg_bot + .delete_sticker(&sticker.file_id) + .await + .expect("could not delete sticker"); + } + } + } + } + + // Delete stickers that have a name but are no longer in the new pack + { + let invalid_stickers: Vec = tg_stickers + .clone() + .into_iter() + .filter(|sticker| !pack_contents.contains(&sticker.0)) + .map(|sticker| sticker.1) + .collect(); + + for invalid_sticker in invalid_stickers.iter() { + println!( + "Deleting sticker with name {} as is not in pack", + &invalid_sticker.file_unique_id + ); + tg_bot + .delete_sticker(&invalid_sticker.file_id) + .await + .expect("could not delete sticker"); + + tg_stickers.retain(|sticker| { + // keep if true + sticker.1.file_unique_id != invalid_sticker.file_unique_id + }) + } + } + + // +1 for skipping the first sticker + let new_sticker_position_base = tg_stickers.len() + 1; + let mut new_stickers: Vec = Vec::new(); + + // add stickers that arent in tg_stickers + { + let missing_stickers: Vec = pack_contents + .clone() + .into_iter() + .filter(|sticker| { + for tg_sticker in tg_stickers.iter() { + if tg_sticker.0 == sticker.clone() { + return false; + } + } + true + }) + .collect(); + + for sticker_name in missing_stickers.iter() { + println!("Uploading Sticker: {}", sticker_name); + let sticker_data = pack_stickers.get(sticker_name).unwrap(); + + let file_path = std::path::PathBuf::from(&base_stickerdb_path).join(&sticker_data.file); + let mut file = std::fs::File::open(file_path).unwrap(); + let mut file_data: Vec = Vec::new(); + file.read_to_end(&mut file_data) + .expect("could not read file"); + + let mut png_sticker: Option> = None; + let mut tgs_sticker: Option> = None; + let mut webm_sticker: Option> = None; + + match deploy_location.r#type { + StickerType::Regular => { + png_sticker = Some(file_data); + } + StickerType::TelegramVideo => { + webm_sticker = Some(file_data); + } + StickerType::TelegramAnimated => { + tgs_sticker = Some(file_data); + } + _ => {} + } + + tg_bot + .upload_sticker( + deploy_location.user_id, + deploy_location.name.clone(), + Some(sticker_data.emojis.concat()), + png_sticker, + tgs_sticker, + webm_sticker, + ) + .await + .expect("could not upload sticker"); + + new_stickers.push(sticker_name.clone()); + } + + println!("{:#?}", missing_stickers); + } + + // Update tg_stickers with current sticker contents + { + let tg_new_sticker_set = tg_bot + .get_sticker_set(&deploy_location.name) + .await + .expect("could not get sticker pack"); + + for (i, sticker_name) in new_stickers.iter().enumerate() { + let new_sticker = tg_new_sticker_set + .stickers + .index(new_sticker_position_base + i) + .clone(); + + tg_state.set(&new_sticker.file_unique_id, sticker_name); + + tg_stickers.push(( + sticker_name.clone(), + tg_new_sticker_set + .stickers + .index(new_sticker_position_base + i) + .clone(), + )); + } + } + + tg_state.save().expect("could not save state"); + + // Reorder stickers using order of pack_contents + { + for (correct_sticker_i, sticker_name) in pack_contents.iter().enumerate() { + let pack_sticker = sticker_name.clone(); + let tg_sticker = tg_stickers.index(correct_sticker_i).0.clone(); + if pack_sticker != tg_sticker { + println!( + "Sticker in position {} is the wrong sticker", + correct_sticker_i + ); + + let mut sticker_incorrect_pos: Option = None; + for (sticker_i, sticker) in tg_stickers.iter().enumerate() { + if sticker.0 == pack_sticker { + sticker_incorrect_pos = Some(sticker_i); + } + } + if sticker_incorrect_pos.is_none() { + unreachable!() + } + + println!( + "Moving sticker at position {} to {}", + sticker_incorrect_pos.unwrap(), + correct_sticker_i + ); + + let sticker = tg_stickers.remove(sticker_incorrect_pos.unwrap()); + tg_stickers.insert(correct_sticker_i, sticker.clone()); + + tg_bot + .set_sticker_position(sticker.1.file_id.clone(), correct_sticker_i + 1) + .await + .expect("could not move sticker"); + } + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..569bf5f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,57 @@ +pub mod creds; +pub mod deploy_discord; +pub mod deploy_telegram; +pub mod sticker_config; +pub mod tg_api; + +use creds::Creds; +use deploy_discord::deploy_discord; +use deploy_telegram::deploy_telegram; +use sticker_config::StickerConfig; + +use clap::Parser; +use std::fs::File; +use std::path::PathBuf; + +#[derive(Debug, Parser)] +#[clap()] +pub struct CLIArgs { + pub folder: String, + pub deploy_id: String, +} + +#[tokio::main] +async fn main() { + let args = CLIArgs::parse(); + + let base_path = PathBuf::from(&args.folder); + let config_path = base_path.join("stickers.yml"); + let creds_path = base_path.join("../stickerdb/creds.yml"); + + let config_file = File::open(config_path).expect("could not open stickers.yml"); + let creds_file = File::open(creds_path).expect("could not open creds.yml"); + + let config: StickerConfig = + serde_yaml::from_reader(config_file).expect("could not parse stickers.yml"); + let creds: Creds = serde_yaml::from_reader(creds_file).expect("could not parse creds.yml"); + + match config + .deploy_where + .get(&args.deploy_id) + .expect("no deploy config with id specified found") + .deploy_to + .as_str() + { + "discord" => { + println!("deploying {} to discord", &args.deploy_id); + deploy_discord(args.deploy_id, config, creds, args.folder).await; + } + "telegram" => { + println!("deploying {} to telegram", &args.deploy_id); + deploy_telegram(args.deploy_id, config, creds, args.folder).await; + } + _ => { + panic!("deploy_to not set") + } + } +} diff --git a/src/sticker_config.rs b/src/sticker_config.rs new file mode 100644 index 0000000..c6a0a9b --- /dev/null +++ b/src/sticker_config.rs @@ -0,0 +1,99 @@ +use serde::Deserialize; +use std::collections::HashMap; + +#[derive(Debug, Clone, Deserialize)] +pub struct StickerConfig { + pub stickers: HashMap, + pub credits: HashMap, + pub deploy_where: HashMap, + pub sticker_sets: HashMap>, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct DeployWhere { + pub pack_id: String, + pub deploy_to: String, + pub discord: Option>, + pub telegram: Option, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct TelegramDeployLocation { + pub deploy_name: String, + pub r#type: StickerType, + pub name: String, + pub user_id: u64, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct DiscordDeployLocation { + pub deploy_name: String, + pub id: u64, + #[serde(default = "discord_max_regular_emoji_default")] + pub max_regular_emoji: u64, + #[serde(default = "discord_max_animated_emoji_default")] + pub max_animated_emoji: u64, +} + +fn discord_max_regular_emoji_default() -> u64 { + 50 +} + +fn discord_max_animated_emoji_default() -> u64 { + 50 +} + + +#[derive(Debug, Clone, Deserialize)] +pub struct Credit { + pub artist: String, + pub source: Vec, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Sticker { + pub file: String, + pub emojis: Vec, + pub alt_text: Option, + pub credit: Option, + #[serde(default)] + pub r#type: StickerType, +} + +#[derive(Debug, PartialEq, Eq, Clone, serde_with::DeserializeFromStr)] +pub enum StickerType { + Regular, + Gif, + TelegramVideo, + TelegramAnimated, +} + +impl std::str::FromStr for StickerType { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "regular" => Ok(Self::Regular), + "gif" => Ok(Self::Gif), + "telegram_video" => Ok(Self::TelegramVideo), + "telegram_animated" => Ok(Self::TelegramAnimated), + _ => Err(String::from("invalid sticker type")), + } + } +} + +impl std::fmt::Display for StickerType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + StickerType::Regular => write!(f, "regular"), + StickerType::Gif => write!(f, "gif"), + StickerType::TelegramVideo => write!(f, "telegram_video"), + StickerType::TelegramAnimated => write!(f, "telegram_animated"), + } + } +} + +impl Default for StickerType { + fn default() -> Self { + StickerType::Regular + } +} diff --git a/src/tg_api.rs b/src/tg_api.rs new file mode 100644 index 0000000..32b715a --- /dev/null +++ b/src/tg_api.rs @@ -0,0 +1,196 @@ +use std::{collections::HashMap, error::Error}; +use serde::{Deserialize, Serialize}; + +const API_BASE: &str = "https://api.telegram.org"; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TelegramAPIResponse { + pub ok: bool, + pub error_code: Option, + pub description: Option, + pub result: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TelegramStickerSet { + pub name: String, + pub title: String, + pub is_animated: bool, + pub is_video: bool, + pub stickers: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TelegramSticker { + pub file_id: String, + pub file_unique_id: String, + pub is_animated: bool, + pub is_video: bool, + pub emoji: Option, +} + +#[derive(Debug)] +struct TelegramError { + error_code: u16, + description: String, +} + +impl TelegramError { + fn new(error_code: u16, description: String) -> TelegramError { + TelegramError { + error_code, + description, + } + } +} + +impl std::fmt::Display for TelegramError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{} {}", self.error_code, self.description) + } +} + +impl Error for TelegramError { + fn description(&self) -> &str { + self.description.as_str() + } +} + +pub struct TelegramAPI { + token: String, + client: reqwest::Client, +} + +impl TelegramAPI { + pub fn new(token: String) -> Self { + Self { + token, + client: reqwest::Client::new(), + } + } + + pub async fn get_sticker_set( + &self, + pack_name: &str, + ) -> Result> { + let url = format!("{}/bot{}/getStickerSet", API_BASE, self.token); + let res = self + .client + .get(url) + .form(&HashMap::from([("name", pack_name)])) + .send() + .await?; + + let res_json = res + .json::>() + .await?; + + if !res_json.ok { + return Err(Box::new(TelegramError::new( + res_json.error_code.unwrap(), + res_json.description.unwrap(), + ))); + } + + Ok(res_json.result.unwrap()) + } + + pub async fn delete_sticker(&self, sticker_file_id: &str) -> Result> { + let url = format!("{}/bot{}/deleteStickerFromSet", API_BASE, self.token); + let res = self + .client + .get(url) + .form(&HashMap::from([("sticker", sticker_file_id)])) + .send() + .await?; + + let res_json = res.json::>().await?; + + if !res_json.ok { + return Err(Box::new(TelegramError::new( + res_json.error_code.unwrap(), + res_json.description.unwrap(), + ))); + } + + Ok(res_json.result.unwrap()) + } + + pub async fn upload_sticker( + &self, + user_id: u64, + sticker_pack_name: String, + emojis: Option, + png_sticker: Option>, + tgs_sticker: Option>, + webm_sticker: Option>, + ) -> Result> { + let url = format!("{}/bot{}/addStickerToSet", API_BASE, self.token); + + let mut form = reqwest::multipart::Form::new(); + form = form.text("user_id", user_id.to_string()); + form = form.text("name", sticker_pack_name); + if emojis.is_some() { + form = form.text("emojis", emojis.unwrap()); + } + if png_sticker.is_some() { + form = form.part( + "png_sticker", + reqwest::multipart::Part::bytes(png_sticker.unwrap()).file_name(""), + ); + } + if tgs_sticker.is_some() { + form = form.part( + "tgs_sticker", + reqwest::multipart::Part::bytes(tgs_sticker.unwrap()), + ); + } + if webm_sticker.is_some() { + form = form.part( + "webm_sticker", + reqwest::multipart::Part::bytes(webm_sticker.unwrap()), + ); + } + + let res = self.client.get(url).multipart(form).send().await?; + + let res_json = res.json::>().await?; + + if !res_json.ok { + return Err(Box::new(TelegramError::new( + res_json.error_code.unwrap(), + res_json.description.unwrap(), + ))); + } + + Ok(res_json.result.unwrap()) + } + + pub async fn set_sticker_position( + &self, + sticker_file_id: String, + sticker_position: usize, + ) -> Result> { + let url = format!("{}/bot{}/setStickerPositionInSet", API_BASE, self.token); + let res = self + .client + .get(url) + .form(&HashMap::from([ + ("sticker", sticker_file_id), + ("position", sticker_position.to_string()), + ])) + .send() + .await?; + + let res_json = res.json::>().await?; + + if !res_json.ok { + return Err(Box::new(TelegramError::new( + res_json.error_code.unwrap(), + res_json.description.unwrap(), + ))); + } + + Ok(res_json.result.unwrap()) + } +}