diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index a69aff6..547e2e8 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -101,7 +101,7 @@ jobs: run: | rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.93" --force GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" wasm-chrome: runs-on: ubuntu-latest @@ -130,5 +130,5 @@ jobs: run: | rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.93" --force CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" diff --git a/Cargo.lock b/Cargo.lock index 0ed4864..2d79f4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aead" version = "0.5.2" @@ -77,7 +83,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -122,7 +128,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -151,6 +157,20 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bigdecimal" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -189,15 +209,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.0" +version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" +checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -207,13 +230,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chorus" -version = "0.15.0" +version = "0.16.0" dependencies = [ "async-trait", "base64 0.21.7", @@ -236,7 +259,7 @@ dependencies = [ "rand", "regex", "reqwest", - "rustls", + "rustls 0.21.12", "serde", "serde-aux", "serde_json", @@ -244,6 +267,7 @@ dependencies = [ "serde_with", "simple_logger", "sqlx", + "sqlx-pg-uint", "thiserror", "tokio", "tokio-tungstenite", @@ -258,11 +282,11 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.4.1" +version = "0.5.0" dependencies = [ "async-trait", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -328,15 +352,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -433,7 +457,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -444,7 +468,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -560,18 +584,18 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -667,7 +691,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -742,7 +766,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -751,9 +775,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -761,7 +785,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -908,9 +932,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -925,7 +949,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -974,9 +998,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -994,21 +1018,21 @@ dependencies = [ "futures-util", "http 0.2.12", "hyper 0.14.30", - "rustls", + "rustls 0.21.12", "tokio", "tokio-rustls", ] [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "hyper 1.4.1", "pin-project-lite", "tokio", @@ -1066,9 +1090,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -1107,9 +1131,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1139,9 +1163,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -1151,9 +1175,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" -version = "0.28.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -1220,6 +1244,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "minicov" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1236,10 +1270,19 @@ dependencies = [ ] [[package]] -name = "mio" -version = "1.0.1" +name = "miniz_oxide" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", @@ -1267,9 +1310,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -1358,9 +1401,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.1" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -1401,7 +1444,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "smallvec", "windows-targets 0.52.6", ] @@ -1517,9 +1560,9 @@ dependencies = [ [[package]] name = "poem" -version = "3.0.1" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88b6912ed1e8833d7c22c9c986c517f4518d7d37e3c04566d917c789aaea591" +checksum = "f1ba1c27f8f89e1bccdda0c680f72790545a11a8d8555819472f5839d7a8ca9d" dependencies = [ "bytes", "futures-util", @@ -1551,14 +1594,14 @@ dependencies = [ [[package]] name = "poem-derive" -version = "3.0.0" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2b961d58a6c53380c20236394381d9292fda03577f902b158f1638932964dcf" +checksum = "a62fea1692d80a000126f9b28d865012a160b80000abb53ccf152b428222c155" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -1580,9 +1623,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro-crate" @@ -1613,9 +1659,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1661,18 +1707,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -1721,8 +1767,8 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -1834,10 +1880,24 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.102.6", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -1848,10 +1908,20 @@ dependencies = [ ] [[package]] -name = "rustls-pki-types" -version = "1.7.0" +name = "rustls-pemfile" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -1863,6 +1933,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "ryu" version = "1.0.18" @@ -1878,6 +1959,15 @@ dependencies = [ "cipher", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1914,9 +2004,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] @@ -1934,22 +2024,23 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1962,7 +2053,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -1987,7 +2078,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.4.0", "serde", "serde_derive", "serde_json", @@ -2004,7 +2095,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -2029,6 +2120,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -2126,9 +2223,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27144619c6e5802f1380337a209d2ac1c431002dd74c6e60aebff3c506dc4f0c" +checksum = "fcfa89bea9500db4a0d038513d7a060566bfc51d46d1c014847049a45cce85e8" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2139,11 +2236,12 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a999083c1af5b5d6c071d34a708a19ba3e02106ad82ef7bbd69f5e48266b613b" +checksum = "d06e2f2bd861719b1f3f0c7dbe1d80c30bf59e76cf019f07d9014ed7eefb8e08" dependencies = [ "atoi", + "bigdecimal", "byteorder", "bytes", "chrono", @@ -2159,15 +2257,15 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.2.6", + "indexmap 2.4.0", "ipnetwork", "log", "memchr", "once_cell", "paste", "percent-encoding", - "rustls", - "rustls-pemfile", + "rustls 0.23.12", + "rustls-pemfile 2.1.3", "serde", "serde_json", "sha2", @@ -2178,27 +2276,27 @@ dependencies = [ "tokio-stream", "tracing", "url", - "webpki-roots 0.25.4", + "webpki-roots 0.26.3", ] [[package]] name = "sqlx-macros" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23217eb7d86c584b8cbe0337b9eacf12ab76fe7673c513141ec42565698bb88" +checksum = "2f998a9defdbd48ed005a89362bd40dd2117502f15294f61c8d47034107dbbdc" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] name = "sqlx-macros-core" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a099220ae541c5db479c6424bdf1b200987934033c2584f79a0e1693601e776" +checksum = "3d100558134176a2629d46cec0c8891ba0be8910f7896abfdb75ef4ab6f4e7ce" dependencies = [ "dotenvy", "either", @@ -2214,7 +2312,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.70", + "syn 2.0.76", "tempfile", "tokio", "url", @@ -2222,12 +2320,13 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5afe4c38a9b417b6a9a5eeffe7235d0a106716495536e7727d1c7f4b1ff3eba6" +checksum = "936cac0ab331b14cb3921c62156d913e4c15b74fb6ec0f3146bd4ef6e4fb3c12" dependencies = [ "atoi", "base64 0.22.1", + "bigdecimal", "bitflags 2.6.0", "byteorder", "bytes", @@ -2264,13 +2363,37 @@ dependencies = [ ] [[package]] -name = "sqlx-postgres" -version = "0.8.0" +name = "sqlx-pg-uint" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1dbb157e65f10dbe01f729339c06d239120221c9ad9fa0ba8408c4cc18ecf21" +checksum = "ae1cfe6c40c1cd0053b9029a41729a533ceb32093052df626aa8bfbba45e45f6" +dependencies = [ + "bigdecimal", + "serde", + "sqlx", + "sqlx-pg-uint-macros", + "thiserror", +] + +[[package]] +name = "sqlx-pg-uint-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae3447aced07f8bc71d73dc8dd1c6d25c2f4d10ea62a22ceabc12af8410d7e2" +dependencies = [ + "quote", + "syn 2.0.76", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9734dbce698c67ecf67c442f768a5e90a49b2a4d61a9f1d59f73874bd4cf0710" dependencies = [ "atoi", "base64 0.22.1", + "bigdecimal", "bitflags 2.6.0", "byteorder", "chrono", @@ -2290,6 +2413,7 @@ dependencies = [ "log", "md-5", "memchr", + "num-bigint", "once_cell", "rand", "serde", @@ -2305,9 +2429,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2cdd83c008a622d94499c0006d8ee5f821f36c89b7d625c900e5dc30b5c5ee" +checksum = "a75b419c3c1b1697833dd927bdc4c6545a620bc1bbafabd44e1efbe9afcd337e" dependencies = [ "atoi", "chrono", @@ -2363,9 +2487,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.70" +version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", @@ -2410,14 +2534,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2437,7 +2562,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -2488,9 +2613,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", @@ -2510,7 +2635,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -2519,7 +2644,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", "tokio", ] @@ -2542,7 +2667,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.21.12", "tokio", "tokio-rustls", "tungstenite", @@ -2564,9 +2689,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" @@ -2574,16 +2699,16 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.4.0", "toml_datetime", "winnow", ] [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -2605,7 +2730,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -2636,7 +2761,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls", + "rustls 0.21.12", "sha1", "thiserror", "url", @@ -2690,9 +2815,9 @@ dependencies = [ [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "unicode_categories" @@ -2747,9 +2872,19 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "want" @@ -2774,34 +2909,35 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -2811,9 +2947,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2821,31 +2957,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-bindgen-test" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" +checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" dependencies = [ "console_error_panic_hook", "js-sys", + "minicov", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -2854,13 +2991,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" +checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] @@ -2879,9 +3016,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -2934,6 +3071,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2967,6 +3113,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3132,6 +3287,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -3143,7 +3299,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.76", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 83b7e9d..6d4830e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "chorus" description = "A library for interacting with multiple Spacebar-compatible Instances at once." -version = "0.15.0" +version = "0.16.0" license = "MPL-2.0" edition = "2021" repository = "https://github.com/polyphony-chat/chorus" @@ -13,18 +13,19 @@ rust-version = "1.70.0" [features] default = ["client", "rt-multi-thread"] -backend = ["poem", "sqlx"] +backend = ["poem", "sqlx", "sqlx-pg-uint"] rt-multi-thread = ["tokio/rt-multi-thread"] rt = ["tokio/rt"] client = ["flate2"] voice = ["voice_udp", "voice_gateway"] voice_udp = ["dep:discortp", "dep:crypto_secretbox"] voice_gateway = [] +sqlx-pg-uint = ["dep:sqlx-pg-uint", "sqlx-pg-uint/serde"] [dependencies] -tokio = { version = "1.38.1", features = ["macros", "sync"] } -serde = { version = "1.0.204", features = ["derive", "rc"] } -serde_json = { version = "1.0.120", features = ["raw_value"] } +tokio = { version = "1.39.3", features = ["macros", "sync"] } +serde = { version = "1.0.209", features = ["derive", "rc"] } +serde_json = { version = "1.0.127", features = ["raw_value"] } serde-aux = "4.5.0" serde_with = "3.9.0" serde_repr = "0.1.19" @@ -35,7 +36,7 @@ reqwest = { features = [ ], version = "=0.11.26", default-features = false } url = "2.5.2" chrono = { version = "0.4.38", features = ["serde"] } -regex = "1.10.5" +regex = "1.10.6" custom_error = "1.9.2" futures-util = "0.3.30" http = "0.2.12" @@ -48,14 +49,13 @@ jsonwebtoken = "8.3.0" log = "0.4.22" async-trait = "0.1.81" chorus-macros = { path = "./chorus-macros", version = "0" } # Note: version here is used when releasing. This will use the latest release. Make sure to republish the crate when code in macros is changed! -sqlx = { version = "0.8.0", features = [ - "mysql", - "sqlite", +sqlx = { version = "0.8.1", features = [ "json", "chrono", "ipnetwork", "runtime-tokio-rustls", - "any", + "postgres", + "bigdecimal", ], optional = true } discortp = { version = "0.5.0", optional = true, features = [ "rtp", @@ -64,9 +64,10 @@ discortp = { version = "0.5.0", optional = true, features = [ ] } crypto_secretbox = { version = "0.1.1", optional = true } rand = "0.8.5" -flate2 = { version = "1.0.30", optional = true } +flate2 = { version = "1.0.33", optional = true } webpki-roots = "0.26.3" pubserve = { version = "1.1.0", features = ["async", "send"] } +sqlx-pg-uint = { version = "0.5.0", features = ["serde"], optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.12" @@ -79,13 +80,13 @@ getrandom = { version = "0.2.15" } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2.15", features = ["js"] } ws_stream_wasm = "0.7.4" -wasm-bindgen-futures = "0.4.42" +wasm-bindgen-futures = "0.4.43" wasmtimer = "0.2.0" [dev-dependencies] lazy_static = "1.5.0" -wasm-bindgen-test = "0.3.42" -wasm-bindgen = "0.2.92" +wasm-bindgen-test = "0.3.43" +wasm-bindgen = "0.2.93" simple_logger = { version = "5.0.0", default-features = false } [lints.rust] diff --git a/README.md b/README.md index 413ec34..afed9b2 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,15 @@ -Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/) -and Discord. It is designed to be easy to use, and to be compatible with both Discord and Spacebar Chat. +Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/), +Discord and our own Polyphony. Its high-level API is designed to be easy to use, while still providing the +flexibility one would expect from a library like this. You can establish as many connections to as many servers as you want, and you can use them all at the same time. ## A Tour of Chorus -Chorus combines all the required functionalities of a user-centric Spacebar library into one package. +Chorus combines all the required functionalities of an API wrapper for chat services into one modular library. The library handles various aspects on your behalf, such as rate limiting, authentication and maintaining a WebSocket connection to the Gateway. This means that you can focus on building your application, instead of worrying about the underlying implementation details. @@ -44,19 +45,19 @@ To get started with Chorus, import it into your project by adding the following ```toml [dependencies] -chorus = "0.15.0" +chorus = "0.16.0" ``` ### Establishing a Connection -To connect to a Spacebar compatible server, you need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: +To connect to a Polyphony/Spacebar compatible server, you'll need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: ```rs use chorus::instance::Instance; #[tokio::main] async fn main() { - let instance = Instance::new("https://example.com") + let instance = Instance::new("https://example.com", None) .await .expect("Failed to connect to the Spacebar server"); // You can create as many instances of `Instance` as you want, but each `Instance` should likely be unique. @@ -81,7 +82,7 @@ let login_schema = LoginSchema { password: "Correct-Horse-Battery-Staple".to_string(), ..Default::default() }; -// Each user connects to the Gateway. The Gateway connection lives on a separate thread. Depending on +// Each user connects to the Gateway. Each users' Gateway connection lives on a separate thread. Depending on // the runtime feature you choose, this can potentially take advantage of all of your computers' threads. let user = instance .login_account(login_schema) @@ -148,98 +149,23 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read See [CONTRIBUTING.md](./CONTRIBUTING.md). -
- Progress Tracker/Roadmap - - ### Core Functionality - - [x] Rate Limiter (hint: couldn't be fully tested due to [an Issue with the Spacebar Server](https://github.com/spacebarchat/server/issues/1022)) - - [x] [Login (the conventional way)](https://github.com/polyphony-chat/chorus/issues/1) - - [ ] [2FA](https://github.com/polyphony-chat/chorus/issues/40) - - [x] [Registration](https://github.com/polyphony-chat/chorus/issues/1) - - ### Messaging - - [x] [Sending messages](https://github.com/polyphony-chat/chorus/issues/23) - - [x] [Events (Message, User, Channel, etc.)](https://github.com/polyphony-chat/chorus/issues/51) - - [x] Channel creation - - [x] Channel deletion - - [x] [Channel management (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/48) - - [x] [Join and Leave Guilds](https://github.com/polyphony-chat/chorus/issues/45) - - [x] [Start DMs](https://github.com/polyphony-chat/chorus/issues/45) - - [x] [Group DM creation, deletion and member management](https://github.com/polyphony-chat/chorus/issues/89) - - [ ] [Deleting messages](https://github.com/polyphony-chat/chorus/issues/91) - - [ ] [Message threads](https://github.com/polyphony-chat/chorus/issues/90) - - [x] [Reactions](https://github.com/polyphony-chat/chorus/issues/85) - - [ ] Message Search - - [ ] Message history - - [ ] Emoji - - [ ] Stickers - - [ ] [Forum channels](https://github.com/polyphony-chat/chorus/issues/90) - - ### User Management - - [ ] [User profile customization](https://github.com/polyphony-chat/chorus/issues/41) - - [x] Gettings users and user profiles - - [x] [Friend requests](https://github.com/polyphony-chat/chorus/issues/92) - - [x] [Blocking users](https://github.com/polyphony-chat/chorus/issues/92) - - [ ] User presence (online, offline, idle, etc.) - - [ ] User status (custom status, etc.) - - [x] Account deletion - - ### Additional Features - - [ ] Server discovery - - [ ] Server templates - - ### Voice and Video - - [ ] [Voice chat support](https://github.com/polyphony-chat/chorus/issues/49) - - [ ] [Video chat support](https://github.com/polyphony-chat/chorus/issues/49) - - ### Permissions and Roles - - [x] [Role management](https://github.com/polyphony-chat/chorus/issues/46) (creation, deletion, modification) - - [x] [Permission management](https://github.com/polyphony-chat/chorus/issues/46) (assigning and revoking permissions) - - [x] [Channel-specific permissions](https://github.com/polyphony-chat/chorus/issues/88) - - [x] Role-based access control - - ### Guild Management - - [x] Guild creation - - [x] Guild deletion - - [ ] [Guild settings (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/43) - - [ ] Guild invites - - ### Moderation - - [ ] Channel moderation (slow mode, etc.) - - [ ] User sanctions (mute, kick, ban) - - [ ] Audit logs - - ### Embeds and Rich Content - - [x] Sending rich content in messages (links, images, videos) - - [ ] Customizing embed appearance (title, description, color, fields) - - ### Webhooks - - [ ] Webhook creation and management - - [ ] Handling incoming webhook events - - ### Documentation and Examples - - [ ] Comprehensive documentation - - [ ] Example usage and code snippets - - [ ] Tutorials and guides - - [Rust]: https://img.shields.io/badge/Rust-orange?style=plastic&logo=rust - [Rust-url]: https://www.rust-lang.org/ - [build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/build_and_test.yml?style=flat - [build-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/build_and_test.yml - [clippy-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/clippy.yml?style=flat - [clippy-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/clippy.yml - [contributors-shield]: https://img.shields.io/github/contributors/polyphony-chat/chorus.svg?style=flat - [contributors-url]: https://github.com/polyphony-chat/chorus/graphs/contributors - [coverage-shield]: https://coveralls.io/repos/github/polyphony-chat/chorus/badge.svg?branch=main - [coverage-url]: https://coveralls.io/github/polyphony-chat/chorus?branch=main - [forks-shield]: https://img.shields.io/github/forks/polyphony-chat/chorus.svg?style=flat - [forks-url]: https://github.com/polyphony-chat/chorus/network/members - [stars-shield]: https://img.shields.io/github/stars/polyphony-chat/chorus.svg?style=flat - [stars-url]: https://github.com/polyphony-chat/chorus/stargazers - [issues-shield]: https://img.shields.io/github/issues/polyphony-chat/chorus.svg?style=flat - [issues-url]: https://github.com/polyphony-chat/chorus/issues - [license-shield]: https://img.shields.io/github/license/polyphony-chat/chorus.svg?style=f;at - [license-url]: https://github.com/polyphony-chat/chorus/blob/master/LICENSE - [Discord]: https://dcbadge.vercel.app/api/server/m3FpcapGDD?style=flat - [Discord-invite]: https://discord.com/invite/m3FpcapGDD -
+[Rust]: https://img.shields.io/badge/Rust-orange?style=plastic&logo=rust +[Rust-url]: https://www.rust-lang.org/ +[build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/build_and_test.yml?style=flat +[build-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/build_and_test.yml +[clippy-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/clippy.yml?style=flat +[clippy-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/clippy.yml +[contributors-shield]: https://img.shields.io/github/contributors/polyphony-chat/chorus.svg?style=flat +[contributors-url]: https://github.com/polyphony-chat/chorus/graphs/contributors +[coverage-shield]: https://coveralls.io/repos/github/polyphony-chat/chorus/badge.svg?branch=main +[coverage-url]: https://coveralls.io/github/polyphony-chat/chorus?branch=main +[forks-shield]: https://img.shields.io/github/forks/polyphony-chat/chorus.svg?style=flat +[forks-url]: https://github.com/polyphony-chat/chorus/network/members +[stars-shield]: https://img.shields.io/github/stars/polyphony-chat/chorus.svg?style=flat +[stars-url]: https://github.com/polyphony-chat/chorus/stargazers +[issues-shield]: https://img.shields.io/github/issues/polyphony-chat/chorus.svg?style=flat +[issues-url]: https://github.com/polyphony-chat/chorus/issues +[license-shield]: https://img.shields.io/github/license/polyphony-chat/chorus.svg?style=f;at +[license-url]: https://github.com/polyphony-chat/chorus/blob/master/LICENSE +[Discord]: https://dcbadge.vercel.app/api/server/m3FpcapGDD?style=flat +[Discord-invite]: https://discord.com/invite/m3FpcapGDD diff --git a/chorus-macros/Cargo.toml b/chorus-macros/Cargo.toml index 6aa416a..4efc372 100644 --- a/chorus-macros/Cargo.toml +++ b/chorus-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chorus-macros" -version = "0.4.1" +version = "0.5.0" edition = "2021" license = "MPL-2.0" description = "Macros for the chorus crate." diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index 1c3a8bd..d2797e7 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -164,24 +164,23 @@ pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { quote!{ #[cfg(feature = "sqlx")] - impl sqlx::Type for #name { - fn type_info() -> sqlx::any::AnyTypeInfo { - as sqlx::Type>::type_info() + impl sqlx::Type for #name { + fn type_info() -> sqlx::postgres::PgTypeInfo { + >::type_info() } } #[cfg(feature = "sqlx")] - impl<'q> sqlx::Encode<'q, sqlx::Any> for #name { - fn encode_by_ref(&self, buf: &mut ::ArgumentBuffer<'q>) -> Result { - as sqlx::Encode>::encode_by_ref(&self.bits().to_be_bytes().into(), buf) + impl<'q> sqlx::Encode<'q, sqlx::Postgres> for #name { + fn encode_by_ref(&self, buf: &mut ::ArgumentBuffer<'q>) -> Result { + >::encode_by_ref(&self.bits().into(), buf) } } #[cfg(feature = "sqlx")] - impl<'q> sqlx::Decode<'q, sqlx::Any> for #name { - fn decode(value: ::ValueRef<'q>) -> Result { - let vec = as sqlx::Decode>::decode(value)?; - Ok(Self::from_bits(vec_u8_to_u64(vec)).unwrap()) + impl<'q> sqlx::Decode<'q, sqlx::Postgres> for #name { + fn decode(value: ::ValueRef<'q>) -> Result { + >::decode(value).map(|v| Self::from_bits_truncate(v.to_uint())) } } diff --git a/examples/gateway_observers.rs b/examples/gateway_observers.rs index a43d17c..8137179 100644 --- a/examples/gateway_observers.rs +++ b/examples/gateway_observers.rs @@ -52,7 +52,7 @@ impl Subscriber for ExampleObserver { #[tokio::main(flavor = "current_thread")] async fn main() { - let gateway_websocket_url = GATEWAY_URL.to_string(); + let gateway_websocket_url = GATEWAY_URL; // These options specify the encoding format, compression, etc // diff --git a/examples/gateway_simple.rs b/examples/gateway_simple.rs index 7f66287..aa6e0e0 100644 --- a/examples/gateway_simple.rs +++ b/examples/gateway_simple.rs @@ -25,8 +25,8 @@ use wasmtimer::tokio::sleep; /// This example creates a simple gateway connection and a session with an Identify event #[tokio::main(flavor = "current_thread")] async fn main() { - let gateway_websocket_url = GATEWAY_URL.to_string(); - + let gateway_websocket_url = GATEWAY_URL; + // These options specify the encoding format, compression, etc // // For most cases the defaults should work, though some implementations @@ -34,7 +34,9 @@ async fn main() { let options = GatewayOptions::default(); // Initiate the gateway connection, starting a listener in one thread and a heartbeat handler in another - let gateway = Gateway::spawn(gateway_websocket_url, options).await.unwrap(); + let gateway = Gateway::spawn(gateway_websocket_url, options) + .await + .unwrap(); // At this point, we are connected to the server and are sending heartbeats, however we still haven't authenticated diff --git a/examples/instance.rs b/examples/instance.rs index 0bbdc17..5f685f9 100644 --- a/examples/instance.rs +++ b/examples/instance.rs @@ -6,7 +6,7 @@ use chorus::instance::Instance; #[tokio::main(flavor = "current_thread")] async fn main() { - let instance = Instance::new("https://example.com/") + let instance = Instance::new("https://example.com/", None) .await .expect("Failed to connect to the Spacebar server"); dbg!(instance.instance_info); diff --git a/examples/login.rs b/examples/login.rs index e89d8d2..f9ebcf0 100644 --- a/examples/login.rs +++ b/examples/login.rs @@ -7,7 +7,7 @@ use chorus::types::LoginSchema; #[tokio::main(flavor = "current_thread")] async fn main() { - let mut instance = Instance::new("https://example.com/") + let mut instance = Instance::new("https://example.com/", None) .await .expect("Failed to connect to the Spacebar server"); // Assume, you already have an account created on this instance. Registering an account works diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 1242953..ab78a99 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -30,13 +30,12 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since login is an instance wide limit), which is why we are just cloning the // instances' limits to pass them on as user_rate_limits later. - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; + let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; let login_result = chorus_request .deserialize_response::(&mut user) .await?; - user.set_token(login_result.token); + user.set_token(&login_result.token); user.settings = login_result.settings; let object = User::get_current(&mut user).await?; diff --git a/src/api/auth/mod.rs b/src/api/auth/mod.rs index 3aa8b3b..9649135 100644 --- a/src/api/auth/mod.rs +++ b/src/api/auth/mod.rs @@ -22,9 +22,8 @@ pub mod register; impl Instance { /// Logs into an existing account on the spacebar server, using only a token. - pub async fn login_with_token(&mut self, token: String) -> ChorusResult { - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; + pub async fn login_with_token(&mut self, token: &str) -> ChorusResult { + let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; let object = User::get_current(&mut user).await?; let settings = User::get_settings(&mut user).await?; diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index 34e628a..d978e0f 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -37,14 +37,14 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since register is an instance wide limit), which is why we are just cloning // the instances' limits to pass them on as user_rate_limits later. - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; + let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; let token = chorus_request .deserialize_response::(&mut user) .await? .token; - user.set_token(token); + + user.set_token(&token); let object = User::get_current(&mut user).await?; let settings = User::get_settings(&mut user).await?; diff --git a/src/api/channels/messages.rs b/src/api/channels/messages.rs index feabc37..a682c21 100644 --- a/src/api/channels/messages.rs +++ b/src/api/channels/messages.rs @@ -16,6 +16,7 @@ use crate::types::{ }; impl Message { + #[allow(clippy::useless_conversion)] /// Sends a message in the channel with the provided channel_id. /// Returns the sent message. /// @@ -40,7 +41,7 @@ impl Message { chorus_request.deserialize_response::(user).await } else { for (index, attachment) in message.attachments.iter_mut().enumerate() { - attachment.get_mut(index).unwrap().id = Some(index as i16); + attachment.get_mut(index).unwrap().id = Some((index as u64).into()); } let mut form = reqwest::multipart::Form::new(); let payload_json = to_string(&message).unwrap(); @@ -111,7 +112,7 @@ impl Message { let result = request.send_request(user).await?; let result_json = result.json::().await.unwrap(); if !result_json.is_object() { - return Err(search_error(result_json.to_string())); + return Err(search_error(result_json.to_string().as_str())); } let value_map = result_json.as_object().unwrap(); if let Some(messages) = value_map.get("messages") { @@ -122,7 +123,7 @@ impl Message { } // The code below might be incorrect. We'll cross that bridge when we come to it if !value_map.contains_key("code") || !value_map.contains_key("retry_after") { - return Err(search_error(result_json.to_string())); + return Err(search_error(result_json.to_string().as_str())); } let code = value_map.get("code").unwrap().as_u64().unwrap(); let retry_after = value_map.get("retry_after").unwrap().as_u64().unwrap(); @@ -481,7 +482,7 @@ impl Message { } } -fn search_error(result_text: String) -> ChorusError { +fn search_error(result_text: &str) -> ChorusError { ChorusError::InvalidResponse { error: format!( "Got unexpected Response, or Response which is not valid JSON. Response: \n{}", diff --git a/src/gateway/backends/tungstenite.rs b/src/gateway/backends/tungstenite.rs index 34dc825..4464f8d 100644 --- a/src/gateway/backends/tungstenite.rs +++ b/src/gateway/backends/tungstenite.rs @@ -9,8 +9,10 @@ use futures_util::{ }; use tokio::net::TcpStream; use tokio_tungstenite::{ - connect_async_tls_with_config, tungstenite, Connector, MaybeTlsStream, WebSocketStream, + connect_async_tls_with_config, connect_async_with_config, tungstenite, Connector, + MaybeTlsStream, WebSocketStream, }; +use url::Url; use crate::gateway::{GatewayMessage, RawGatewayMessage}; @@ -32,38 +34,60 @@ impl TungsteniteBackend { pub async fn connect( websocket_url: &str, ) -> Result<(TungsteniteSink, TungsteniteStream), TungsteniteBackendError> { - let certs = webpki_roots::TLS_SERVER_ROOTS; - let roots = rustls::RootCertStore { - roots: certs - .iter() - .map(|cert| { - rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( - cert.subject.to_vec(), - cert.subject_public_key_info.to_vec(), - cert.name_constraints.as_ref().map(|der| der.to_vec()), - ) - }) - .collect(), - }; - let (websocket_stream, _) = match connect_async_tls_with_config( - websocket_url, - None, - false, - Some(Connector::Rustls( - rustls::ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(roots) - .with_no_client_auth() - .into(), - )), - ) - .await - { - Ok(websocket_stream) => websocket_stream, - Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }), - }; + let websocket_url_parsed = + Url::parse(websocket_url).map_err(|_| TungsteniteBackendError::TungsteniteError { + error: tungstenite::error::Error::Url( + tungstenite::error::UrlError::UnsupportedUrlScheme, + ), + })?; + if websocket_url_parsed.scheme() == "ws" { + let (websocket_stream, _) = + match connect_async_with_config(websocket_url, None, false).await { + Ok(websocket_stream) => websocket_stream, + Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }), + }; - Ok(websocket_stream.split()) + Ok(websocket_stream.split()) + } else if websocket_url_parsed.scheme() == "wss" { + let certs = webpki_roots::TLS_SERVER_ROOTS; + let roots = rustls::RootCertStore { + roots: certs + .iter() + .map(|cert| { + rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( + cert.subject.to_vec(), + cert.subject_public_key_info.to_vec(), + cert.name_constraints.as_ref().map(|der| der.to_vec()), + ) + }) + .collect(), + }; + let (websocket_stream, _) = match connect_async_tls_with_config( + websocket_url, + None, + false, + Some(Connector::Rustls( + rustls::ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(roots) + .with_no_client_auth() + .into(), + )), + ) + .await + { + Ok(websocket_stream) => websocket_stream, + Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }), + }; + + Ok(websocket_stream.split()) + } else { + Err(TungsteniteBackendError::TungsteniteError { + error: tungstenite::error::Error::Url( + tungstenite::error::UrlError::UnsupportedUrlScheme, + ), + }) + } } } diff --git a/src/gateway/gateway.rs b/src/gateway/gateway.rs index 33804b3..20f8640 100644 --- a/src/gateway/gateway.rs +++ b/src/gateway/gateway.rs @@ -48,7 +48,7 @@ impl Gateway { /// # Note /// The websocket url should begin with the prefix wss:// or ws:// (for unsecure connections) pub async fn spawn( - websocket_url: String, + websocket_url: &str, options: GatewayOptions, ) -> Result { let url = options.add_to_url(websocket_url); diff --git a/src/gateway/handle.rs b/src/gateway/handle.rs index 6bcdba8..98a7731 100644 --- a/src/gateway/handle.rs +++ b/src/gateway/handle.rs @@ -10,9 +10,10 @@ use std::fmt::Debug; use super::{events::Events, *}; use crate::types::{self, Composite, Shared}; -/// Represents a handle to a Gateway connection. A Gateway connection will create observable -/// [`GatewayEvents`](GatewayEvent), which you can subscribe to. Gateway events include all currently -/// implemented types with the trait [`WebSocketEvent`] +/// Represents a handle to a Gateway connection. +/// +/// A Gateway connection will create observable [`Events`], which you can subscribe to. +/// /// Using this handle you can also send Gateway Events directly. #[derive(Debug, Clone)] pub struct GatewayHandle { diff --git a/src/gateway/options.rs b/src/gateway/options.rs index 23942b2..4ff6178 100644 --- a/src/gateway/options.rs +++ b/src/gateway/options.rs @@ -25,8 +25,8 @@ impl GatewayOptions { /// Adds the options to an existing gateway url /// /// Returns the new url - pub(crate) fn add_to_url(&self, url: String) -> String { - let mut url = url; + pub(crate) fn add_to_url(&self, url: &str) -> String { + let mut url = url.to_string(); let mut parameters = Vec::with_capacity(2); diff --git a/src/instance.rs b/src/instance.rs index f826ab5..a8671e0 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -69,8 +69,13 @@ impl Instance { /// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle). /// + /// If `options` is `None`, the default [`GatewayOptions`] will be used. + /// /// To create an Instance from one singular url, use [`Instance::new()`]. - pub async fn from_url_bundle(urls: UrlBundle) -> ChorusResult { + pub async fn from_url_bundle( + urls: UrlBundle, + options: Option, + ) -> ChorusResult { let is_limited: Option = Instance::is_limited(&urls.api).await?; let limit_information; @@ -89,7 +94,7 @@ impl Instance { instance_info: GeneralConfiguration::default(), limits_information: limit_information, client: Client::new(), - gateway_options: GatewayOptions::default(), + gateway_options: options.unwrap_or_default(), }; instance.instance_info = match instance.general_configuration_schema().await { Ok(schema) => schema, @@ -103,14 +108,16 @@ impl Instance { /// Creates a new [`Instance`] by trying to get the [relevant instance urls](UrlBundle) from a root url. /// + /// If `options` is `None`, the default [`GatewayOptions`] will be used. + /// /// Shorthand for `Instance::from_url_bundle(UrlBundle::from_root_domain(root_domain).await?)`. - pub async fn new(root_url: &str) -> ChorusResult { + pub async fn new(root_url: &str, options: Option) -> ChorusResult { let urls = UrlBundle::from_root_url(root_url).await?; - Instance::from_url_bundle(urls).await + Instance::from_url_bundle(urls, options).await } pub async fn is_limited(api_url: &str) -> ChorusResult> { - let api_url = UrlBundle::parse_url(api_url.to_string()); + let api_url = UrlBundle::parse_url(api_url); let client = Client::new(); let request = client .get(format!("{}/policies/instance/limits", &api_url)) @@ -163,8 +170,8 @@ impl ChorusUser { self.token.clone() } - pub fn set_token(&mut self, token: String) { - self.token = token; + pub fn set_token(&mut self, token: &str) { + self.token = token.to_string(); } /// Creates a new [ChorusUser] from existing data. @@ -195,16 +202,15 @@ impl ChorusUser { /// registering or logging in to the Instance, where you do not yet have a User object, but still /// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify /// first. - pub(crate) async fn shell(instance: Shared, token: String) -> ChorusUser { + pub(crate) async fn shell(instance: Shared, token: &str) -> ChorusUser { let settings = Arc::new(RwLock::new(UserSettings::default())); let object = Arc::new(RwLock::new(User::default())); - let wss_url = instance.read().unwrap().urls.wss.clone(); + let wss_url = &instance.read().unwrap().urls.wss.clone(); + let gateway_options = instance.read().unwrap().gateway_options; // Dummy gateway object - let gateway = Gateway::spawn(wss_url, GatewayOptions::default()) - .await - .unwrap(); + let gateway = Gateway::spawn(wss_url, gateway_options).await.unwrap(); ChorusUser { - token, + token: token.to_string(), belongs_to: instance.clone(), limits: instance .read() diff --git a/src/lib.rs b/src/lib.rs index 7767480..c4aa3ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,27 +3,29 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. /*! -Chorus combines all the required functionalities of a user-centric Spacebar library into one package. +Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/), +Discord and our own Polyphony. Its high-level API is designed to be easy to use, while still providing the +flexibility one would expect from a library like this. + +You can establish as many connections to as many servers as you want, and you can use them all at the same time. + +## A Tour of Chorus + +Chorus combines all the required functionalities of an API wrapper for chat services into one modular library. The library handles various aspects on your behalf, such as rate limiting, authentication and maintaining a WebSocket connection to the Gateway. This means that you can focus on building your application, instead of worrying about the underlying implementation details. ### Establishing a Connection -To connect to a Spacebar compatible server, you need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: +To connect to a Polyphony/Spacebar compatible server, you'll need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: ```rs use chorus::instance::Instance; -use chorus::UrlBundle; #[tokio::main] async fn main() { - let bundle = UrlBundle::new( - "https://example.com/api".to_string(), - "wss://example.com/".to_string(), - "https://example.com/cdn".to_string(), - ); - let instance = Instance::new(bundle) + let instance = Instance::new("https://example.com") .await .expect("Failed to connect to the Spacebar server"); // You can create as many instances of `Instance` as you want, but each `Instance` should likely be unique. @@ -36,7 +38,7 @@ This Instance can now be used to log in, register and from there on, interact wi ### Logging In -Logging in correctly provides you with an instance of [`ChorusUser`](https://docs.rs/chorus/latest/chorus/instance/struct.ChorusUser.html), with which you can interact with the server and +Logging in correctly provides you with an instance of `ChorusUser`, with which you can interact with the server and manipulate the account. Assuming you already have an account on the server, you can log in like this: ```rs @@ -48,7 +50,7 @@ let login_schema = LoginSchema { password: "Correct-Horse-Battery-Staple".to_string(), ..Default::default() }; -// Each user connects to the Gateway. The Gateway connection lives on a separate thread. Depending on +// Each user connects to the Gateway. Each users' Gateway connection lives on a separate thread. Depending on // the runtime feature you choose, this can potentially take advantage of all of your computers' threads. let user = instance .login_account(login_schema) @@ -64,15 +66,33 @@ All major desktop operating systems (Windows, macOS (aarch64/x86_64), Linux (aar `wasm32-unknown-unknown` is a supported compilation target on versions `0.12.0` and up. This allows you to use Chorus in your browser, or in any other environment that supports WebAssembly. -We recommend checking out the examples directory, as well as the documentation for more information. +To compile for `wasm32-unknown-unknown`, execute the following command: + +```sh +cargo build --target=wasm32-unknown-unknown --no-default-features +``` + +The following features are supported on `wasm32-unknown-unknown`: + +| Feature | WASM Support | +| ----------------- | ------------ | +| `client` | ✅ | +| `rt` | ✅ | +| `rt-multi-thread` | ❌ | +| `backend` | ❌ | +| `voice` | ❌ | +| `voice_udp` | ❌ | +| `voice_gateway` | ✅ | + +We recommend checking out the "examples" directory, as well as the documentation for more information. ## MSRV (Minimum Supported Rust Version) -Rust **1.67.1**. This number might change at any point while Chorus is not yet at version 1.0.0. +Rust **1.70.0**. This number might change at any point while Chorus is not yet at version 1.0.0. ## Development Setup -Make sure that you have at least Rust 1.67.1 installed. You can check your Rust version by running `cargo --version` +Make sure that you have at least Rust 1.70.0 installed. You can check your Rust version by running `cargo --version` in your terminal. To compile for `wasm32-unknown-unknown`, you need to install the `wasm32-unknown-unknown` target. You can do this by running `rustup target add wasm32-unknown-unknown`. @@ -86,12 +106,16 @@ like "proxy connection checking" are already disabled on this version, which oth ### wasm To test for wasm, you will need to `cargo install wasm-pack`. You can then run -`wasm-pack test -- --headless -- --target wasm32-unknown-unknown --features="rt, client" --no-default-features` +`wasm-pack test -- --headless -- --target wasm32-unknown-unknown --features="rt, client, voice_gateway" --no-default-features` to run the tests for wasm. ## Versioning This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read the specification [here](https://semver.org/spec/v2.0.0.html). + +## Contributing + +See [CONTRIBUTING.md](./CONTRIBUTING.md). !*/ #![doc( html_logo_url = "https://raw.githubusercontent.com/polyphony-chat/design/main/branding/polyphony-chorus-round-8bit.png" @@ -101,8 +125,7 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read clippy::extra_unused_lifetimes, clippy::from_over_into, clippy::needless_borrow, - clippy::new_without_default, - clippy::useless_conversion + clippy::new_without_default )] #![warn( clippy::todo, @@ -111,7 +134,8 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read clippy::print_stdout, clippy::print_stderr, missing_debug_implementations, - missing_copy_implementations + missing_copy_implementations, + clippy::useless_conversion )] #[cfg(all(feature = "rt", feature = "rt_multi_thread"))] compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time"); @@ -139,6 +163,27 @@ pub mod types; ))] pub mod voice; +#[cfg(not(feature = "sqlx"))] +pub type UInt128 = u128; +#[cfg(feature = "sqlx")] +pub type UInt128 = sqlx_pg_uint::PgU128; +#[cfg(not(feature = "sqlx"))] +pub type UInt64 = u64; +#[cfg(feature = "sqlx")] +pub type UInt64 = sqlx_pg_uint::PgU64; +#[cfg(not(feature = "sqlx"))] +pub type UInt32 = u32; +#[cfg(feature = "sqlx")] +pub type UInt32 = sqlx_pg_uint::PgU32; +#[cfg(not(feature = "sqlx"))] +pub type UInt16 = u16; +#[cfg(feature = "sqlx")] +pub type UInt16 = sqlx_pg_uint::PgU16; +#[cfg(not(feature = "sqlx"))] +pub type UInt8 = u8; +#[cfg(feature = "sqlx")] +pub type UInt8 = sqlx_pg_uint::PgU8; + #[derive(Clone, Default, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] /// A URLBundle bundles together the API-, Gateway- and CDN-URLs of a Spacebar instance. /// @@ -165,7 +210,7 @@ pub struct UrlBundle { impl UrlBundle { /// Creates a new UrlBundle from the relevant urls. - pub fn new(root: String, api: String, wss: String, cdn: String) -> Self { + pub fn new(root: &str, api: &str, wss: &str, cdn: &str) -> Self { Self { root: UrlBundle::parse_url(root), api: UrlBundle::parse_url(api), @@ -182,17 +227,17 @@ impl UrlBundle { /// let url = parse_url("localhost:3000"); /// ``` /// `-> Outputs "http://localhost:3000".` - pub fn parse_url(url: String) -> String { - let url = match Url::parse(&url) { + pub fn parse_url(url: &str) -> String { + let url = match Url::parse(url) { Ok(url) => { if url.scheme() == "localhost" { - return UrlBundle::parse_url(format!("http://{}", url)); + return UrlBundle::parse_url(&format!("http://{}", url)); } url } Err(ParseError::RelativeUrlWithoutBase) => { let url_fmt = format!("http://{}", url); - return UrlBundle::parse_url(url_fmt); + return UrlBundle::parse_url(&url_fmt); } Err(_) => panic!("Invalid URL"), // TODO: should not panic here }; @@ -215,7 +260,7 @@ impl UrlBundle { /// of the above approaches fail, it is very likely that the instance is misconfigured, unreachable, or that /// a wrong URL was provided. pub async fn from_root_url(url: &str) -> ChorusResult { - let parsed = UrlBundle::parse_url(url.to_string()); + let parsed = UrlBundle::parse_url(url); let client = reqwest::Client::new(); let request_wellknown = client .get(format!("{}/.well-known/spacebar", &parsed)) @@ -253,10 +298,10 @@ impl UrlBundle { .await { Ok(UrlBundle::new( - url.to_string(), - body.api_endpoint, - body.gateway, - body.cdn, + url, + &body.api_endpoint, + &body.gateway, + &body.cdn, )) } else { Err(ChorusError::RequestFailed { @@ -273,13 +318,13 @@ mod lib { #[test] fn test_parse_url() { - let mut result = UrlBundle::parse_url(String::from("localhost:3000/")); - assert_eq!(result, String::from("http://localhost:3000")); - result = UrlBundle::parse_url(String::from("https://some.url.com/")); - assert_eq!(result, String::from("https://some.url.com")); - result = UrlBundle::parse_url(String::from("https://some.url.com/")); - assert_eq!(result, String::from("https://some.url.com")); - result = UrlBundle::parse_url(String::from("https://some.url.com")); + let mut result = UrlBundle::parse_url("localhost:3000/"); + assert_eq!(result, "http://localhost:3000"); + result = UrlBundle::parse_url("https://some.url.com/"); assert_eq!(result, String::from("https://some.url.com")); + result = UrlBundle::parse_url("https://some.url.com/"); + assert_eq!(result, "https://some.url.com"); + result = UrlBundle::parse_url("https://some.url.com"); + assert_eq!(result, "https://some.url.com"); } } diff --git a/src/types/config/types/guild_configuration.rs b/src/types/config/types/guild_configuration.rs index fc07d1c..95bf6c4 100644 --- a/src/types/config/types/guild_configuration.rs +++ b/src/types/config/types/guild_configuration.rs @@ -162,11 +162,11 @@ impl Display for GuildFeaturesList { } #[cfg(feature = "sqlx")] -impl<'r> sqlx::Decode<'r, sqlx::Any> for GuildFeaturesList { +impl<'r> sqlx::Decode<'r, sqlx::Postgres> for GuildFeaturesList { fn decode( - value: ::ValueRef<'r>, + value: ::ValueRef<'r>, ) -> Result { - let v = >::decode(value)?; + let v = >::decode(value)?; Ok(Self( v.split(',') .filter(|f| !f.is_empty()) @@ -177,10 +177,10 @@ impl<'r> sqlx::Decode<'r, sqlx::Any> for GuildFeaturesList { } #[cfg(feature = "sqlx")] -impl<'q> sqlx::Encode<'q, sqlx::Any> for GuildFeaturesList { +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for GuildFeaturesList { fn encode_by_ref( &self, - buf: &mut ::ArgumentBuffer<'q>, + buf: &mut ::ArgumentBuffer<'q>, ) -> Result> { if self.is_empty() { return Ok(sqlx::encode::IsNull::Yes); @@ -191,18 +191,18 @@ impl<'q> sqlx::Encode<'q, sqlx::Any> for GuildFeaturesList { .collect::>() .join(","); - >::encode_by_ref(&features, buf) + >::encode_by_ref(&features, buf) } } #[cfg(feature = "sqlx")] -impl sqlx::Type for GuildFeaturesList { - fn type_info() -> sqlx::any::AnyTypeInfo { - >::type_info() +impl sqlx::Type for GuildFeaturesList { + fn type_info() -> ::TypeInfo { + >::type_info() } - fn compatible(ty: &sqlx::any::AnyTypeInfo) -> bool { - >::compatible(ty) + fn compatible(ty: &::TypeInfo) -> bool { + >::compatible(ty) } } diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index 9c81c19..512a031 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -224,7 +224,8 @@ pub struct ApplicationCommandOptionChoice { #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, PartialEq, Eq, Hash)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(i32)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// # Reference /// See pub enum ApplicationCommandOptionType { @@ -294,7 +295,8 @@ pub struct ApplicationCommandPermission { Ord, )] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum ApplicationCommandPermissionType { #[default] diff --git a/src/types/entities/attachment.rs b/src/types/entities/attachment.rs index f2e221d..acd0d62 100644 --- a/src/types/entities/attachment.rs +++ b/src/types/entities/attachment.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::types::utils::Snowflake; +use crate::UInt64; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, PartialOrd)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -16,11 +17,11 @@ pub struct Attachment { /// Max 1024 characters pub description: Option, pub content_type: Option, - pub size: u64, + pub size: UInt64, pub url: String, pub proxy_url: String, - pub height: Option, - pub width: Option, + pub height: Option, + pub width: Option, pub ephemeral: Option, /// The duration of the audio file (only for voice messages) pub duration_secs: Option, @@ -37,12 +38,12 @@ pub struct Attachment { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct PartialDiscordFileAttachment { - pub id: Option, + pub id: Option, pub filename: String, /// Max 1024 characters pub description: Option, pub content_type: Option, - pub size: Option, + pub size: Option, pub url: Option, pub proxy_url: Option, pub height: Option, diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index 7c821fc..97676d3 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -12,6 +12,7 @@ use crate::types::utils::Snowflake; use crate::types::{ AutoModerationRuleTriggerType, IntegrationType, PermissionOverwriteType, Shared, }; +use crate::UInt64; #[derive(Serialize, Deserialize, Debug, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -108,7 +109,8 @@ pub struct AuditLogChange { PartialOrd, Ord, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] /// # Reference: /// See @@ -251,16 +253,16 @@ pub struct AuditEntryInfo { pub auto_moderation_rule_trigger_type: Option, pub channel_id: Option, // #[serde(option_string)] - pub count: Option, + pub count: Option, // #[serde(option_string)] - pub delete_member_days: Option, + pub delete_member_days: Option, /// The ID of the overwritten entity pub id: Option, pub integration_type: Option, // #[serde(option_string)] - pub members_removed: Option, + pub members_removed: Option, // #[serde(option_string)] - pub message_id: Option, + pub message_id: Option, pub role_name: Option, #[serde(rename = "type")] pub overwrite_type: Option, diff --git a/src/types/entities/auto_moderation.rs b/src/types/entities/auto_moderation.rs index 3caa16c..2ee65b6 100644 --- a/src/types/entities/auto_moderation.rs +++ b/src/types/entities/auto_moderation.rs @@ -5,6 +5,7 @@ #[cfg(feature = "client")] use crate::gateway::Updateable; use crate::types::Shared; +use crate::UInt8; #[cfg(feature = "client")] use chorus_macros::Updateable; @@ -32,7 +33,8 @@ pub struct AutoModerationRule { } #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum AutoModerationRuleEventType { @@ -43,7 +45,8 @@ pub enum AutoModerationRuleEventType { #[derive( Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum AutoModerationRuleTriggerType { @@ -80,18 +83,20 @@ pub struct AutoModerationRuleTriggerMetadataForKeywordPreset { pub allow_list: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy)] +#[allow(missing_copy_implementations)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] /// See pub struct AutoModerationRuleTriggerMetadataForMentionSpam { /// Max 50 - pub mention_total_limit: u8, + pub mention_total_limit: UInt8, pub mention_raid_protection_enabled: bool, } #[derive( Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum AutoModerationRuleKeywordPresetType { @@ -110,9 +115,20 @@ pub struct AutoModerationAction { } #[derive( - Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, Hash + Serialize_repr, + Deserialize_repr, + Debug, + Clone, + Default, + PartialEq, + Eq, + PartialOrd, + Ord, + Copy, + Hash, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum AutoModerationActionType { diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 3d6cd3a..df30153 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -22,6 +22,7 @@ use crate::gateway::GatewayHandle; #[cfg(feature = "client")] use crate::gateway::Updateable; +use crate::UInt64; #[cfg(feature = "client")] use chorus_macros::{observe_option_vec, Composite, Updateable}; @@ -41,13 +42,7 @@ use super::{option_arc_rwlock_ptr_eq, option_vec_arc_rwlock_ptr_eq}; /// See pub struct Channel { pub application_id: Option, - #[cfg(feature = "sqlx")] - pub applied_tags: Option>>, - #[cfg(not(feature = "sqlx"))] pub applied_tags: Option>, - #[cfg(feature = "sqlx")] - pub available_tags: Option>>, - #[cfg(not(feature = "sqlx"))] pub available_tags: Option>, pub bitrate: Option, #[serde(rename = "type")] @@ -55,9 +50,7 @@ pub struct Channel { pub created_at: Option>, pub default_auto_archive_duration: Option, pub default_forum_layout: Option, - #[cfg(feature = "sqlx")] - pub default_reaction_emoji: Option>, - #[cfg(not(feature = "sqlx"))] + // DefaultReaction could be stored in a separate table. However, there are a lot of default emojis. How would we handle that? pub default_reaction_emoji: Option, pub default_sort_order: Option, pub default_thread_rate_limit_per_user: Option, @@ -179,6 +172,8 @@ fn compare_permission_overwrites( /// /// # Reference /// See +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] +#[cfg_attr(feature = "sqlx", sqlx(type_name = "interface_type"))] pub struct Tag { pub id: Snowflake, /// The name of the tag (max 20 characters) @@ -202,7 +197,8 @@ pub struct PermissionOverwrite { } #[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// # Reference /// /// See @@ -301,7 +297,7 @@ pub struct ThreadMember { pub id: Option, pub user_id: Option, pub join_timestamp: Option>, - pub flags: Option, + pub flags: Option, pub member: Option>, } @@ -321,6 +317,8 @@ impl PartialEq for ThreadMember { /// /// # Reference /// See +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] +#[cfg_attr(feature = "sqlx", sqlx(type_name = "interface_type"))] pub struct DefaultReaction { #[serde(default)] pub emoji_id: Option, @@ -342,7 +340,7 @@ pub struct DefaultReaction { )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u32)] +#[repr(i32)] /// # Reference /// See pub enum ChannelType { diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index 82f3e37..9a59ab0 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -32,9 +32,6 @@ use super::option_arc_rwlock_ptr_eq; pub struct Emoji { pub id: Snowflake, pub name: Option, - #[cfg(feature = "sqlx")] - pub roles: Option>>, - #[cfg(not(feature = "sqlx"))] pub roles: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 4de8569..91850ac 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -17,6 +17,7 @@ use crate::types::{ interfaces::WelcomeScreenObject, utils::Snowflake, }; +use crate::UInt64; use super::{option_arc_rwlock_ptr_eq, vec_arc_rwlock_ptr_eq, PublicUser}; @@ -273,7 +274,7 @@ pub struct GuildScheduledEvent { pub entity_id: Option, pub entity_metadata: Option, pub creator: Option>, - pub user_count: Option, + pub user_count: Option, pub image: Option, } @@ -300,7 +301,8 @@ impl PartialEq for GuildScheduledEvent { } #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Copy)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum GuildScheduledEventPrivacyLevel { #[default] @@ -308,7 +310,8 @@ pub enum GuildScheduledEventPrivacyLevel { } #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Copy)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum GuildScheduledEventStatus { #[default] @@ -331,7 +334,8 @@ pub enum GuildScheduledEventStatus { Copy, Hash, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum GuildScheduledEventEntityType { #[default] @@ -369,7 +373,8 @@ pub struct VoiceRegion { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum MessageNotificationLevel { @@ -392,7 +397,8 @@ pub enum MessageNotificationLevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum ExplicitContentFilterLevel { @@ -416,7 +422,8 @@ pub enum ExplicitContentFilterLevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum VerificationLevel { @@ -442,7 +449,8 @@ pub enum VerificationLevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum MFALevel { @@ -465,7 +473,8 @@ pub enum MFALevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum NSFWLevel { @@ -490,7 +499,8 @@ pub enum NSFWLevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] // Note: Maybe rename this to GuildPremiumTier? /// **Guild** premium (Boosting) tier diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 37aac42..8afec21 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -11,6 +11,7 @@ use crate::types::{ utils::Snowflake, Shared, }; +use crate::{UInt16, UInt8}; #[derive(Default, Debug, Deserialize, Serialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -25,7 +26,7 @@ pub struct Integration { pub role_id: Option, pub enabled_emoticons: Option, pub expire_behaviour: Option, - pub expire_grace_period: Option, + pub expire_grace_period: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 0160ac9..40f5e72 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -5,8 +5,12 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::{Snowflake, WelcomeScreenObject, Shared, InviteFlags, InviteType, InviteTargetType, Guild, VerificationLevel}; use crate::types::types::guild_configuration::GuildFeaturesList; +use crate::types::{ + Guild, InviteFlags, InviteTargetType, InviteType, Shared, Snowflake, VerificationLevel, + WelcomeScreenObject, +}; +use crate::{UInt32, UInt8}; use super::guild::GuildScheduledEvent; use super::{Application, Channel, GuildMember, NSFWLevel, User}; @@ -36,8 +40,8 @@ pub struct Invite { pub invite_type: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub inviter: Option, - pub max_age: Option, - pub max_uses: Option, + pub max_age: Option, + pub max_uses: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub stage_instance: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] @@ -47,7 +51,7 @@ pub struct Invite { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub target_user: Option, pub temporary: Option, - pub uses: Option, + pub uses: Option, } /// The guild an invite is for. diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index dbea3d5..b63eb3b 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -15,6 +15,7 @@ use crate::types::{ utils::Snowflake, Shared, }; +use crate::{UInt32, UInt8}; use super::option_arc_rwlock_ptr_eq; @@ -150,7 +151,7 @@ pub enum MessageReferenceType { pub struct MessageInteraction { pub id: Snowflake, #[serde(rename = "type")] - pub interaction_type: u8, + pub interaction_type: UInt8, pub name: String, pub user: User, pub member: Option>, @@ -282,8 +283,8 @@ pub struct EmbedField { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Reaction { - pub count: u32, - pub burst_count: u32, + pub count: UInt32, + pub burst_count: UInt32, #[serde(default)] pub me: bool, #[serde(default)] @@ -296,6 +297,8 @@ pub struct Reaction { } #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum Component { ActionRow = 1, Button = 2, @@ -320,7 +323,8 @@ pub struct MessageActivity { Debug, Default, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr, Eq, PartialOrd, Ord, )] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] /// # Reference /// See @@ -464,7 +468,8 @@ pub struct PartialEmoji { #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, PartialOrd, Ord, Eq, Hash)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum ReactionType { Normal = 0, Burst = 1, // The dreaded super reactions diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 6ac2629..969d731 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -132,10 +132,10 @@ pub trait Composite { pub trait IntoShared { /// Uses [`Shared`] to provide an ergonomic alternative to `Arc::new(RwLock::new(obj))`. /// - /// [`Shared`] can then be observed using the [`Gateway`], turning the underlying + /// [`Shared`] can then be observed using the gateway, turning the underlying /// `dyn Composite` into a self-updating struct, which is a tracked variant of a chorus /// entity struct, updating its' held information when new information concerning itself arrives - /// over the [`Gateway`] connection, reducing the need for expensive network-API calls. + /// over the gateway connection, reducing the need for expensive network-API calls. fn into_shared(self) -> Shared; } diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index e3276db..08cb41f 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -45,7 +45,8 @@ impl PartialEq for Relationship { Copy, Hash, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum RelationshipType { Suggestion = 6, diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 20d2fcf..8c2322c 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -8,6 +8,7 @@ use serde_aux::prelude::deserialize_option_number_from_string; use std::fmt::Debug; use crate::types::utils::Snowflake; +use crate::{UInt16, UInt32}; #[cfg(feature = "client")] use chorus_macros::{Composite, Updateable}; @@ -32,7 +33,7 @@ pub struct RoleObject { pub hoist: bool, pub icon: Option, pub unicode_emoji: Option, - pub position: u16, + pub position: UInt16, #[serde(default)] pub permissions: PermissionFlags, pub managed: bool, @@ -47,11 +48,13 @@ pub struct RoleObject { pub struct RoleSubscriptionData { pub role_subscription_listing_id: Snowflake, pub tier_name: String, - pub total_months_subscribed: u32, + pub total_months_subscribed: UInt32, pub is_renewal: bool, } -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] +#[derive( + Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord, +)] /// See pub struct RoleTags { #[serde(default)] diff --git a/src/types/entities/security_key.rs b/src/types/entities/security_key.rs index 7e0bb6b..ac6be8c 100644 --- a/src/types/entities/security_key.rs +++ b/src/types/entities/security_key.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::types::utils::Snowflake; +use crate::UInt64; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -13,7 +14,7 @@ pub struct SecurityKey { pub user_id: String, pub key_id: String, pub public_key: String, - pub counter: u64, + pub counter: UInt64, pub name: String, } @@ -24,7 +25,8 @@ impl Default for SecurityKey { user_id: String::new(), key_id: String::new(), public_key: String::new(), - counter: 0, + #[allow(clippy::useless_conversion)] + counter: 0u64.into(), name: String::new(), } } diff --git a/src/types/entities/stage_instance.rs b/src/types/entities/stage_instance.rs index 38e2817..cf473fa 100644 --- a/src/types/entities/stage_instance.rs +++ b/src/types/entities/stage_instance.rs @@ -21,8 +21,11 @@ pub struct StageInstance { pub guild_scheduled_event_id: Option, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u8)] +#[derive( + Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy, PartialEq, Eq, PartialOrd, Ord, +)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum StageInstancePrivacyLevel { diff --git a/src/types/entities/sticker.rs b/src/types/entities/sticker.rs index 6fcc708..73505a7 100644 --- a/src/types/entities/sticker.rs +++ b/src/types/entities/sticker.rs @@ -77,7 +77,8 @@ pub struct StickerItem { #[derive( Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename = "SCREAMING_SNAKE_CASE")] /// # Reference @@ -93,7 +94,8 @@ pub enum StickerType { #[derive( Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] /// # Reference /// See diff --git a/src/types/entities/team.rs b/src/types/entities/team.rs index 4748fad..8c36e0e 100644 --- a/src/types/entities/team.rs +++ b/src/types/entities/team.rs @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::User; use crate::types::Shared; use crate::types::Snowflake; +use crate::UInt8; use super::arc_rwlock_ptr_eq; @@ -34,7 +35,7 @@ impl PartialEq for Team { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct TeamMember { - pub membership_state: u8, + pub membership_state: UInt8, pub permissions: Vec, pub team_id: Snowflake, pub user: Shared, diff --git a/src/types/entities/template.rs b/src/types/entities/template.rs index e82ec17..29e5368 100644 --- a/src/types/entities/template.rs +++ b/src/types/entities/template.rs @@ -6,10 +6,11 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::{ - Shared, entities::{Guild, User}, utils::Snowflake, + Shared, }; +use crate::UInt64; /// See #[derive(Serialize, Deserialize, Debug, Default, Clone)] @@ -18,7 +19,7 @@ pub struct GuildTemplate { pub code: String, pub name: String, pub description: Option, - pub usage_count: Option, + pub usage_count: Option, pub creator_id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub creator: Shared, diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 9646cc1..9c7c3b9 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -4,6 +4,7 @@ use crate::errors::ChorusError; use crate::types::utils::Snowflake; +use crate::{UInt32, UInt8}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_aux::prelude::{deserialize_option_number_from_string, deserialize_default_from_null}; @@ -50,7 +51,7 @@ pub struct User { pub bot: Option, pub system: Option, pub mfa_enabled: Option, - pub accent_color: Option, + pub accent_color: Option, #[cfg_attr(feature = "sqlx", sqlx(default))] pub locale: Option, pub verified: Option, @@ -116,32 +117,32 @@ impl TryFrom> for ThemeColors { #[cfg(feature = "sqlx")] // TODO: Add tests for Encode and Decode. -impl<'q> sqlx::Encode<'q, sqlx::Any> for ThemeColors { +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for ThemeColors { fn encode_by_ref( &self, - buf: &mut ::ArgumentBuffer<'q>, + buf: &mut ::ArgumentBuffer<'q>, ) -> Result> { let mut vec_u8 = Vec::new(); vec_u8.extend_from_slice(&self.inner.0.to_be_bytes()); vec_u8.extend_from_slice(&self.inner.1.to_be_bytes()); - as sqlx::Encode>::encode_by_ref(&vec_u8, buf) + as sqlx::Encode>::encode_by_ref(&vec_u8, buf) } } #[cfg(feature = "sqlx")] -impl<'d> sqlx::Decode<'d, sqlx::Any> for ThemeColors { +impl<'d> sqlx::Decode<'d, sqlx::Postgres> for ThemeColors { fn decode( - value: ::ValueRef<'d>, + value: ::ValueRef<'d>, ) -> Result { - let value_vec = as sqlx::Decode<'d, sqlx::Any>>::decode(value)?; + let value_vec = as sqlx::Decode<'d, sqlx::Postgres>>::decode(value)?; value_vec.try_into().map_err(|e: ChorusError| e.into()) } } #[cfg(feature = "sqlx")] -impl sqlx::Type for ThemeColors { - fn type_info() -> ::TypeInfo { - >::type_info() +impl sqlx::Type for ThemeColors { + fn type_info() -> ::TypeInfo { + >::type_info() } } @@ -153,7 +154,7 @@ pub struct PublicUser { pub username: Option, pub discriminator: Option, pub avatar: Option, - pub accent_color: Option, + pub accent_color: Option, pub banner: Option, pub theme_colors: Option, pub pronouns: Option, diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index 395db2d..1f4c176 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -6,9 +6,12 @@ use chrono::{serde::ts_milliseconds_option, Utc}; use serde::{Deserialize, Serialize}; use crate::types::Shared; +use crate::{UInt16, UInt32, UInt8}; use serde_aux::field_attributes::deserialize_option_number_from_string; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash)] +#[derive( + Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "lowercase")] pub enum UserStatus { @@ -26,7 +29,9 @@ impl std::fmt::Display for UserStatus { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash)] +#[derive( + Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "lowercase")] pub enum UserTheme { @@ -38,36 +43,23 @@ pub enum UserTheme { #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct UserSettings { - pub afk_timeout: Option, + pub afk_timeout: Option, pub allow_accessibility_detection: bool, pub animate_emoji: bool, - pub animate_stickers: u8, + pub animate_stickers: UInt8, pub contact_sync_enabled: bool, pub convert_emoticons: bool, - #[cfg(feature = "sqlx")] - pub custom_status: Option>, - #[cfg(not(feature = "sqlx"))] pub custom_status: Option, pub default_guilds_restricted: bool, pub detect_platform_accounts: bool, pub developer_mode: bool, pub disable_games_tab: bool, pub enable_tts_command: bool, - pub explicit_content_filter: u8, - #[cfg(feature = "sqlx")] - pub friend_source_flags: sqlx::types::Json, - #[cfg(not(feature = "sqlx"))] + pub explicit_content_filter: UInt8, pub friend_source_flags: FriendSourceFlags, pub gateway_connected: Option, pub gif_auto_play: bool, - #[cfg(feature = "sqlx")] - pub guild_folders: sqlx::types::Json>, - #[cfg(not(feature = "sqlx"))] pub guild_folders: Vec, - #[cfg(feature = "sqlx")] - #[serde(default)] - pub guild_positions: sqlx::types::Json>, - #[cfg(not(feature = "sqlx"))] #[serde(default)] pub guild_positions: Vec, pub inline_attachment_media: bool, @@ -77,9 +69,6 @@ pub struct UserSettings { pub native_phone_integration_enabled: bool, pub render_embeds: bool, pub render_reactions: bool, - #[cfg(feature = "sqlx")] - pub restricted_guilds: sqlx::types::Json>, - #[cfg(not(feature = "sqlx"))] pub restricted_guilds: Vec, pub show_current_game: bool, pub status: Shared, @@ -91,10 +80,14 @@ pub struct UserSettings { impl Default for UserSettings { fn default() -> Self { Self { - afk_timeout: Some(3600), + #[allow(clippy::useless_conversion)] + afk_timeout: Some(3600u16.into()), allow_accessibility_detection: true, animate_emoji: true, + #[cfg(not(feature = "sqlx"))] animate_stickers: 0, + #[cfg(feature = "sqlx")] + animate_stickers: 0.into(), contact_sync_enabled: false, convert_emoticons: false, custom_status: None, @@ -103,7 +96,10 @@ impl Default for UserSettings { developer_mode: true, disable_games_tab: true, enable_tts_command: false, + #[cfg(not(feature = "sqlx"))] explicit_content_filter: 0, + #[cfg(feature = "sqlx")] + explicit_content_filter: 0.into(), friend_source_flags: Default::default(), gateway_connected: Some(false), gif_auto_play: false, @@ -127,7 +123,8 @@ impl Default for UserSettings { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] +#[cfg_attr(feature = "sqlx", sqlx(type_name = "interface_type"))] pub struct CustomStatus { pub emoji_id: Option, pub emoji_name: Option, @@ -137,6 +134,7 @@ pub struct CustomStatus { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] pub struct FriendSourceFlags { pub all: bool, } @@ -148,8 +146,10 @@ impl Default for FriendSourceFlags { } #[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] +#[cfg_attr(feature = "sqlx", sqlx(type_name = "interface_type"))] pub struct GuildFolder { - pub color: Option, + pub color: Option, pub guild_ids: Vec, // FIXME: What is this thing? // It's not a snowflake, and it's sometimes a string and sometimes an integer. diff --git a/src/types/entities/webhook.rs b/src/types/entities/webhook.rs index 19f6203..278ff0d 100644 --- a/src/types/entities/webhook.rs +++ b/src/types/entities/webhook.rs @@ -71,7 +71,8 @@ impl PartialEq for Webhook { #[derive( Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] pub enum WebhookType { #[default] diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 0a3d468..62b3b53 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -5,7 +5,7 @@ use bitflags::bitflags; use serde::{Deserialize, Serialize}; -use crate::types::{ChannelType, DefaultReaction, entities::PermissionOverwrite, Snowflake}; +use crate::types::{entities::PermissionOverwrite, ChannelType, DefaultReaction, Snowflake}; #[derive(Debug, Deserialize, Serialize, Default, PartialEq, PartialOrd)] #[serde(rename_all = "snake_case")] @@ -141,7 +141,8 @@ bitflags! { #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum InviteType { #[default] Guild = 0, @@ -152,7 +153,8 @@ pub enum InviteType { #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum InviteTargetType { #[default] Stream = 1, @@ -169,7 +171,9 @@ pub struct AddChannelRecipientSchema { } /// See -#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash)] +#[derive( + Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash, +)] pub struct ModifyChannelPositionsSchema { pub id: Snowflake, pub position: Option, @@ -178,7 +182,9 @@ pub struct ModifyChannelPositionsSchema { } /// See -#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash)] +#[derive( + Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash, +)] pub struct AddFollowingChannelSchema { pub webhook_channel_id: Snowflake, } diff --git a/src/types/schema/user.rs b/src/types/schema/user.rs index d6934d0..7a2543a 100644 --- a/src/types/schema/user.rs +++ b/src/types/schema/user.rs @@ -78,6 +78,11 @@ pub struct UserModifySchema { /// # Note /// /// This is not yet implemented on Spacebar + /// + /// [UserFlags]: crate::types::UserFlags + /// [UserFlags::PREMIUM_PROMO_DISMISSED]: crate::types::UserFlags::PREMIUM_PROMO_DISMISSED + /// [UserFlags::HAS_UNREAD_URGENT_MESSAGES]: + /// crate::types::UserFlags::HAS_UNREAD_URGENT_MESSAGES pub flags: Option, /// The user's date of birth, can only be set once /// diff --git a/src/types/utils/jwt.rs b/src/types/utils/jwt.rs index 0919a5a..0939723 100644 --- a/src/types/utils/jwt.rs +++ b/src/types/utils/jwt.rs @@ -3,11 +3,14 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::utils::Snowflake; -use jsonwebtoken::{encode, EncodingKey, Header}; +use jsonwebtoken::errors::Error; +use jsonwebtoken::{ + decode, encode, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation, +}; use serde::{Deserialize, Serialize}; -pub fn generate_token(id: &Snowflake, email: String, jwt_key: &str) -> String { - let claims = Claims::new(&email, id); +pub fn generate_token(id: &Snowflake, email: &str, jwt_key: &str) -> String { + let claims = Claims::new(email, id); build_token(&claims, jwt_key).unwrap() } @@ -42,8 +45,13 @@ pub fn build_token(claims: &Claims, jwt_key: &str) -> Result Result, Error> { +pub fn decode_token(token: &str, jwt_secret: &str) -> Result, Error> { let mut validation = Validation::new(Algorithm::HS256); - validation.sub = Some("quartzauth".to_string()); - decode(token, &DecodingKey::from_secret(JWT_SECRET), &validation) -}*/ + //TODO: What is this? + //validation.sub = Some("quartzauth".to_string()); + decode( + token, + &DecodingKey::from_secret(jwt_secret.as_bytes()), + &validation, + ) +} diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index 7caffc7..e19f766 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -26,7 +26,7 @@ impl Snowflake { const PROCESS_ID: u64 = 1; static INCREMENT: AtomicUsize = AtomicUsize::new(0); - let time = (Utc::now().naive_utc().timestamp_millis() - EPOCH) << 22; + let time = (Utc::now().naive_utc().and_utc().timestamp_millis() - EPOCH) << 22; let worker = WORKER_ID << 17; let process = PROCESS_ID << 12; let increment = INCREMENT.fetch_add(1, Ordering::Relaxed) as u64 % 32; @@ -53,12 +53,15 @@ impl Display for Snowflake { } } -impl From for Snowflake -where - T: Into, -{ - fn from(item: T) -> Self { - Self(item.into()) +impl From for Snowflake { + fn from(item: u64) -> Self { + Self(item) + } +} + +impl From for u64 { + fn from(item: Snowflake) -> Self { + item.0 } } @@ -99,29 +102,39 @@ impl<'de> serde::Deserialize<'de> for Snowflake { } #[cfg(feature = "sqlx")] -impl sqlx::Type for Snowflake { - fn type_info() -> ::TypeInfo { - >::type_info() +impl sqlx::Type for Snowflake { + fn type_info() -> ::TypeInfo { + >::type_info() } } #[cfg(feature = "sqlx")] -impl<'q> sqlx::Encode<'q, sqlx::Any> for Snowflake { +impl sqlx::postgres::PgHasArrayType for Snowflake { + fn array_type_info() -> sqlx::postgres::PgTypeInfo { + as sqlx::Type>::type_info() + } +} + +#[cfg(feature = "sqlx")] +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for Snowflake { fn encode_by_ref( &self, - buf: &mut ::ArgumentBuffer<'q>, + buf: &mut ::ArgumentBuffer<'q>, ) -> Result { - >::encode_by_ref(&self.0.to_string(), buf) + >::encode_by_ref( + &sqlx_pg_uint::PgU64::from(self.0), + buf, + ) } } #[cfg(feature = "sqlx")] -impl<'d> sqlx::Decode<'d, sqlx::Any> for Snowflake { +impl<'d> sqlx::Decode<'d, sqlx::Postgres> for Snowflake { fn decode( - value: ::ValueRef<'d>, + value: ::ValueRef<'d>, ) -> Result { - >::decode(value) - .map(|s| s.parse::().map(Snowflake).unwrap()) + >::decode(value) + .map(|s| s.to_uint().into()) } } diff --git a/src/voice/gateway/gateway.rs b/src/voice/gateway/gateway.rs index ba4df80..1b5981c 100644 --- a/src/voice/gateway/gateway.rs +++ b/src/voice/gateway/gateway.rs @@ -41,7 +41,7 @@ pub struct VoiceGateway { impl VoiceGateway { #[allow(clippy::new_ret_no_self)] - pub async fn spawn(websocket_url: String) -> Result { + pub async fn spawn(websocket_url: &str) -> Result { // Append the needed things to the websocket url let processed_url = format!("wss://{}/?v=7", websocket_url); trace!("VGW: Connecting to {}", processed_url.clone()); @@ -110,7 +110,7 @@ impl VoiceGateway { }); Ok(VoiceGatewayHandle { - url: websocket_url.clone(), + url: websocket_url.to_string(), events: shared_events, websocket_send: shared_websocket_send.clone(), kill_send: kill_send.clone(), diff --git a/src/voice/gateway/handle.rs b/src/voice/gateway/handle.rs index 8750f12..b265b71 100644 --- a/src/voice/gateway/handle.rs +++ b/src/voice/gateway/handle.rs @@ -72,7 +72,7 @@ impl VoiceGatewayHandle { /// Sends a speaking event to the gateway pub async fn send_speaking(&self, to_send: Speaking) { - let to_send_value = serde_json::to_value(&to_send).unwrap(); + let to_send_value = serde_json::to_value(to_send).unwrap(); trace!("VGW: Sending Speaking"); diff --git a/tests/auth.rs b/tests/auth.rs index 705328a..9f0cbfd 100644 --- a/tests/auth.rs +++ b/tests/auth.rs @@ -79,11 +79,7 @@ async fn test_login_with_token() { let mut bundle = common::setup().await; let token = &bundle.user.token; - let other_user = bundle - .instance - .login_with_token(token.clone()) - .await - .unwrap(); + let other_user = bundle.instance.login_with_token(token).await.unwrap(); assert_eq!( bundle.user.object.read().unwrap().id, other_user.object.read().unwrap().id @@ -98,8 +94,8 @@ async fn test_login_with_token() { async fn test_login_with_invalid_token() { let mut bundle = common::setup().await; - let token = "invalid token lalalalala".to_string(); - let other_user = bundle.instance.login_with_token(token.clone()).await; + let token = "invalid token lalalalala"; + let other_user = bundle.instance.login_with_token(token).await; assert!(other_user.is_err()); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 5bc0691..ac85b85 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -50,7 +50,7 @@ impl TestBundle { limits: self.user.limits.clone(), settings: self.user.settings.clone(), object: self.user.object.clone(), - gateway: Gateway::spawn(self.instance.urls.wss.clone(), GatewayOptions::default()) + gateway: Gateway::spawn(&self.instance.urls.wss, GatewayOptions::default()) .await .unwrap(), } @@ -66,7 +66,9 @@ pub(crate) async fn setup() -> TestBundle { ) .init(); - let instance = Instance::new("http://localhost:3001/api").await.unwrap(); + let instance = Instance::new("http://localhost:3001/api", None) + .await + .unwrap(); // Requires the existence of the below user. let reg = RegisterSchema { username: "integrationtestuser".into(), @@ -124,10 +126,10 @@ pub(crate) async fn setup() -> TestBundle { .unwrap(); let urls = UrlBundle::new( - "http://localhost:3001/api".to_string(), - "http://localhost:3001/api".to_string(), - "ws://localhost:3001/".to_string(), - "http://localhost:3001".to_string(), + "http://localhost:3001/api", + "http://localhost:3001/api", + "ws://localhost:3001/", + "http://localhost:3001", ); TestBundle { urls, diff --git a/tests/gateway.rs b/tests/gateway.rs index 1c8f56a..ccd96ef 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -31,7 +31,7 @@ use wasmtimer::tokio::sleep; async fn test_gateway_establish() { let bundle = common::setup().await; - let _: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()) + let _: GatewayHandle = Gateway::spawn(&bundle.urls.wss, GatewayOptions::default()) .await .unwrap(); common::teardown(bundle).await @@ -55,7 +55,7 @@ impl Subscriber for GatewayReadyObserver { async fn test_gateway_authenticate() { let bundle = common::setup().await; - let gateway: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()) + let gateway: GatewayHandle = Gateway::spawn(&bundle.urls.wss, GatewayOptions::default()) .await .unwrap();