From d18fb1b9c64597cda9f7ff85fd1d4e4b572fdab4 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 20 Feb 2022 20:04:59 +0300 Subject: [PATCH 01/62] chore(deps): update flake deps and rust toolchain --- flake.lock | 46 +++++++++++++++++++++++++++++++++------------ rust-toolchain.toml | 2 +- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index 1fee69e..3610b27 100644 --- a/flake.lock +++ b/flake.lock @@ -1,12 +1,19 @@ { "nodes": { "devshell": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixCargoIntegration", + "nixpkgs" + ] + }, "locked": { - "lastModified": 1642188268, - "narHash": "sha256-DNz4xScpXIn7rSDohdayBpPR9H9OWCMDOgTYegX081k=", + "lastModified": 1644227066, + "narHash": "sha256-FHcFZtpZEWnUh62xlyY3jfXAXHzJNEDLDzLsJxn+ve0=", "owner": "numtide", "repo": "devshell", - "rev": "696acc29668b644df1740b69e1601119bf6da83b", + "rev": "7033f64dd9ef8d9d8644c5030c73913351d2b660", "type": "github" }, "original": { @@ -15,6 +22,21 @@ "type": "github" } }, + "flake-utils": { + "locked": { + "lastModified": 1642700792, + "narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "846b2ae0fc4cc943637d3d1def4454213e203cba", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "flakeCompat": { "flake": false, "locked": { @@ -40,11 +62,11 @@ "rustOverlay": "rustOverlay" }, "locked": { - "lastModified": 1642745416, - "narHash": "sha256-i87+cNS0raIgHEhNdvBS9OhWm8Dam+PiWe7lKxPMZ9g=", + "lastModified": 1645337413, + "narHash": "sha256-H3hDB9EdU19JVfVMthPgrn3oKJSPxEimykw059CuQD0=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "20c4403b45b86f33a35b55569544e35cd7772927", + "rev": "8c882926b94ca60721d17216d60991fd4988d0c8", "type": "github" }, "original": { @@ -56,11 +78,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1642635915, - "narHash": "sha256-vabPA32j81xBO5m3+qXndWp5aqepe+vu96Wkd9UnngM=", + "lastModified": 1644613700, + "narHash": "sha256-wLRPJclMH8vsHuFtyI78aF09lw5mbi3lMB6uiK5S2wE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6d8215281b2f87a5af9ed7425a26ac575da0438f", + "rev": "23d785aa6f853e6cf3430119811c334025bbef55", "type": "github" }, "original": { @@ -80,11 +102,11 @@ "rustOverlay": { "flake": false, "locked": { - "lastModified": 1642646417, - "narHash": "sha256-1PN44kOjxk6fYeeE8qTo8k+oa4Fa4Mg5UVLPVzuhBpA=", + "lastModified": 1645323562, + "narHash": "sha256-Zv1s9KKgUmxAJqwnrQeanof5wJr9Hti+7odqXnNbPcY=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "85dcf1a4e4897db4420f2c0a3eaf7bb4693914bc", + "rev": "5893aa14811d0d982128e3730d1addb17754d436", "type": "github" }, "original": { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 6d7b8b5..32a4fa8 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-01-20" +channel = "nightly-2022-02-20" targets = ["x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl"] \ No newline at end of file From dde61dd6299c98ab7cb0c607d76bacf953a04dee Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 21 Feb 2022 13:55:57 +0300 Subject: [PATCH 02/62] feat: port to new protocol --- Cargo.lock | 522 +++++++----------- Cargo.toml | 16 +- build.rs | 2 +- protocols/before_proto_v2 | 1 + src/db/migration/add_account_kind.rs | 25 +- src/db/mod.rs | 7 + src/impls/auth/delete_user.rs | 1 - src/impls/auth/login_federated.rs | 1 - src/impls/auth/mod.rs | 3 +- src/impls/auth/next_step.rs | 4 +- src/impls/batch/batch.rs | 29 - src/impls/batch/batch_same.rs | 17 - src/impls/batch/mod.rs | 192 ------- src/impls/chat/guilds/create_guild.rs | 2 +- src/impls/chat/guilds/get_guild.rs | 17 +- src/impls/chat/messages/send_message.rs | 47 +- .../chat/messages/update_message_text.rs | 27 +- src/impls/chat/mod.rs | 487 ++++++++-------- src/impls/chat/permissions/get_permissions.rs | 67 ++- src/impls/chat/permissions/get_user_roles.rs | 35 +- ...ry_has_permission.rs => has_permission.rs} | 6 +- src/impls/chat/permissions/mod.rs | 2 +- src/impls/emote/add_emote_to_pack.rs | 62 ++- src/impls/emote/get_emote_pack_emotes.rs | 47 +- src/impls/mediaproxy/can_instant_view.rs | 28 +- src/impls/mediaproxy/fetch_link_metadata.rs | 11 +- src/impls/mediaproxy/mod.rs | 25 +- src/impls/mod.rs | 24 +- src/impls/profile/get_profile.rs | 16 +- src/impls/profile/mod.rs | 4 - src/impls/profile/update_profile.rs | 3 - src/main.rs | 10 +- 32 files changed, 693 insertions(+), 1047 deletions(-) create mode 160000 protocols/before_proto_v2 delete mode 100644 src/impls/batch/batch.rs delete mode 100644 src/impls/batch/batch_same.rs delete mode 100644 src/impls/batch/mod.rs rename src/impls/chat/permissions/{query_has_permission.rs => has_permission.rs} (60%) diff --git a/Cargo.lock b/Cargo.lock index 59b5fb2..0fd8385 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,9 +45,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.53" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" +checksum = "7a99269dff3bc004caa411f38845c20303f1e393ca2bd6581576fa3a7f59577d" [[package]] name = "arc-swap" @@ -106,9 +106,9 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" +checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" dependencies = [ "event-listener", ] @@ -177,9 +177,9 @@ checksum = "f9f65e4fb35ff6a80b3298d1f028649f3a23da141fa3951e9b24dde1d515b67e" [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum-server" @@ -194,7 +194,7 @@ dependencies = [ "http-body", "hyper", "pin-project-lite", - "rustls 0.20.2", + "rustls 0.20.4", "rustls-pemfile", "tokio", "tokio-rustls 0.23.2", @@ -238,9 +238,9 @@ dependencies = [ [[package]] name = "blake2" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f08f9f6871a8eacbb960d18db3d077ae6db1f0bc0df3272a78ca09eef8c5a931" +checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" dependencies = [ "digest 0.10.3", ] @@ -256,9 +256,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ "generic-array", ] @@ -316,9 +316,9 @@ checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" [[package]] name = "cc" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] @@ -356,8 +356,8 @@ dependencies = [ [[package]] name = "console-api" -version = "0.1.1" -source = "git+https://github.com/tokio-rs/console.git?branch=main#884f4ecac8cba7eee7f895024da4c6e28de75289" +version = "0.1.2" +source = "git+https://github.com/tokio-rs/console.git?branch=main#900a5c2bd5b610e9b939a5f824af1ac1a11267d0" dependencies = [ "prost", "prost-types", @@ -368,14 +368,16 @@ dependencies = [ [[package]] name = "console-subscriber" -version = "0.1.1" -source = "git+https://github.com/tokio-rs/console.git?branch=main#884f4ecac8cba7eee7f895024da4c6e28de75289" +version = "0.1.3" +source = "git+https://github.com/tokio-rs/console.git?branch=main#900a5c2bd5b610e9b939a5f824af1ac1a11267d0" dependencies = [ "console-api", "crossbeam-channel", + "crossbeam-utils", "futures", "hdrhistogram", "humantime", + "prost-types", "serde", "serde_json", "thread_local", @@ -387,17 +389,11 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "core-foundation" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -420,9 +416,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ "cfg-if", ] @@ -450,9 +446,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762" +checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" dependencies = [ "cfg-if", "crossbeam-utils", @@ -463,9 +459,9 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b979d76c9fcb84dffc80a73f7290da0f83e4c95773494674cb44b76d13a7a110" +checksum = "4dd435b205a4842da59efd07628f921c096bc1cc0a156835b4fa0bcb9a19bcce" dependencies = [ "cfg-if", "crossbeam-utils", @@ -473,9 +469,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" +checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" dependencies = [ "cfg-if", "lazy_static", @@ -501,15 +497,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "deflate" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f95bf05dffba6e6cce8dfbb30def788154949ccd9aed761b472119c21e01c70" -dependencies = [ - "adler32", -] - [[package]] name = "deflate" version = "1.0.0" @@ -519,30 +506,6 @@ dependencies = [ "adler32", ] -[[package]] -name = "derive-new" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", -] - [[package]] name = "digest" version = "0.9.0" @@ -558,7 +521,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ - "block-buffer 0.10.0", + "block-buffer 0.10.2", "crypto-common", "subtle", ] @@ -571,9 +534,9 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] name = "ed25519-compact" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302ea73924517e9952bf08b505536f757e28dca8372cbf8b20723a0e2bab6c01" +checksum = "24e1f30f0312ac83726c1197abeacd91c9557f8a623e904a009ae6bc529ae8d8" dependencies = [ "getrandom", ] @@ -584,70 +547,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "encoding" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" -dependencies = [ - "encoding-index-japanese", - "encoding-index-korean", - "encoding-index-simpchinese", - "encoding-index-singlebyte", - "encoding-index-tradchinese", -] - -[[package]] -name = "encoding-index-japanese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-korean" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-simpchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-singlebyte" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-tradchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding_index_tests" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" - [[package]] name = "encoding_rs" version = "0.8.30" @@ -681,7 +580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4badb9489a465cb2c555af1f00f0bfd8cecd6fc12ac11da9d5b40c5dd5f0200" dependencies = [ "bit_field", - "deflate 1.0.0", + "deflate", "flume", "half", "inflate", @@ -714,14 +613,14 @@ dependencies = [ "cfg-if", "crc32fast", "libc", - "miniz_oxide", + "miniz_oxide 0.4.4", ] [[package]] name = "flume" -version = "0.10.10" +version = "0.10.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d04dafd11240188e146b6f6476a898004cace3be31d4ec5e08e216bf4947ac0" +checksum = "0b279436a715a9de95dcd26b151db590a71961cc06e54918b24fe0dd5b7d3fc4" dependencies = [ "futures-core", "futures-sink", @@ -764,9 +663,9 @@ checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" [[package]] name = "futf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" dependencies = [ "mac", "new_debug_unreachable", @@ -774,9 +673,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -788,9 +687,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -798,15 +697,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -826,9 +725,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-lite" @@ -847,9 +746,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2", "quote", @@ -867,21 +766,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-util" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures-core", "futures-io", @@ -973,7 +872,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.6.9", "tracing", ] @@ -998,7 +897,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=master#3a7f65af8aefcfb3e808fce7d60b0defd6772f45" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#645c9136689eb920483ad9a33996b0185d5c7112" dependencies = [ "hrpc-build", "prost-build", @@ -1009,7 +908,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=master#3a7f65af8aefcfb3e808fce7d60b0defd6772f45" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#645c9136689eb920483ad9a33996b0185d5c7112" dependencies = [ "proc-macro2", "quote", @@ -1019,11 +918,9 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=master#3a7f65af8aefcfb3e808fce7d60b0defd6772f45" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#645c9136689eb920483ad9a33996b0185d5c7112" dependencies = [ "bytecheck", - "derive-new", - "derive_more", "harmony_build", "harmony_derive", "hrpc", @@ -1049,20 +946,29 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +dependencies = [ + "ahash", +] + [[package]] name = "hashlink" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" dependencies = [ - "hashbrown", + "hashbrown 0.11.2", ] [[package]] name = "hdrhistogram" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6490be71f07a5f62b564bc58e36953f675833df11c7e4a0647bee7a07ca1ec5e" +checksum = "31672b7011be2c4f7456c4ddbcb40e7e9a4a9fad8efe49a6ebaf5f307d0109c0" dependencies = [ "base64", "byteorder", @@ -1174,7 +1080,7 @@ checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" dependencies = [ "bytes", "fnv", - "itoa 1.0.1", + "itoa", ] [[package]] @@ -1196,9 +1102,9 @@ checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" [[package]] name = "httparse" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" [[package]] name = "httpdate" @@ -1214,9 +1120,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.16" +version = "0.14.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" +checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" dependencies = [ "bytes", "futures-channel", @@ -1227,7 +1133,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 0.4.8", + "itoa", "pin-project-lite", "socket2", "tokio", @@ -1244,7 +1150,7 @@ checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" dependencies = [ "http", "hyper", - "rustls 0.20.2", + "rustls 0.20.4", "rustls-native-certs", "tokio", "tokio-rustls 0.23.2", @@ -1275,15 +1181,15 @@ dependencies = [ [[package]] name = "image" -version = "0.24.0-alpha" -source = "git+https://github.com/image-rs/image.git?branch=master#9d70ecf5b41cde89b7c724f9a76f7827acfad57e" +version = "0.24.1" +source = "git+https://github.com/image-rs/image.git?branch=master#060a41c491a7b9cb7d1ebb3be5a100c8c3c73972" dependencies = [ "bytemuck", "byteorder", "color_quant", "exr", "gif", - "jpeg-decoder 0.2.1", + "jpeg-decoder 0.2.2", "num-iter", "num-rational", "num-traits", @@ -1299,7 +1205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.11.2", ] [[package]] @@ -1331,9 +1237,9 @@ dependencies = [ [[package]] name = "integer-encoding" -version = "1.1.7" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dc51180a9b377fd75814d0cc02199c20f8e99433d6762f650d39cdbbd3b56f" +checksum = "90c11140ffea82edce8dcd74137ce9324ec24b3cf0175fc9d7e29164da9915b8" [[package]] name = "ipnet" @@ -1350,12 +1256,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.1" @@ -1379,9 +1279,9 @@ checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" [[package]] name = "jpeg-decoder" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcf0244f6597be39ab8d9203f574cafb529ae8c698afa2182f7b3c3205a4a9c" +checksum = "105fb082d64e2100074587f59a74231f771750c664af903f1f9f76c9dedfc6f1" dependencies = [ "rayon", ] @@ -1432,7 +1332,7 @@ dependencies = [ "once_cell", "quoted_printable", "regex", - "rustls 0.20.2", + "rustls 0.20.4", "rustls-pemfile", "tokio", "tokio-rustls 0.23.2", @@ -1441,9 +1341,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.116" +version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" [[package]] name = "libsqlite3-sys" @@ -1535,9 +1435,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "matchit" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b6f41fdfbec185dd3dff58b51e323f5bc61692c0de38419a957b0dcfccca3c" +checksum = "9376a4f0340565ad675d11fc1419227faf5f60cd7ac9cb2e7185a471f30af833" [[package]] name = "mediasoup" @@ -1613,11 +1513,20 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +dependencies = [ + "adler", +] + [[package]] name = "mio" -version = "0.7.14" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" dependencies = [ "libc", "log", @@ -1651,7 +1560,7 @@ dependencies = [ "mime", "spin 0.9.2", "tokio", - "tokio-util", + "tokio-util 0.6.9", "version_check", ] @@ -1695,9 +1604,9 @@ dependencies = [ [[package]] name = "ntapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" dependencies = [ "winapi", ] @@ -1773,8 +1682,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "opentelemetry" -version = "0.16.0" -source = "git+https://github.com/open-telemetry/opentelemetry-rust.git?rev=482772f2317e242e6b98bfe04ed42e4dac8cf77b#482772f2317e242e6b98bfe04ed42e4dac8cf77b" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" dependencies = [ "async-trait", "crossbeam-channel", @@ -1793,8 +1703,9 @@ dependencies = [ [[package]] name = "opentelemetry-jaeger" -version = "0.15.0" -source = "git+https://github.com/open-telemetry/opentelemetry-rust.git?rev=482772f2317e242e6b98bfe04ed42e4dac8cf77b#482772f2317e242e6b98bfe04ed42e4dac8cf77b" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c0b12cd9e3f9b35b52f6e0dac66866c519b26f424f4bbf96e3fe8bfbdc5229" dependencies = [ "async-trait", "lazy_static", @@ -1807,8 +1718,9 @@ dependencies = [ [[package]] name = "opentelemetry-semantic-conventions" -version = "0.8.0" -source = "git+https://github.com/open-telemetry/opentelemetry-rust.git?rev=482772f2317e242e6b98bfe04ed42e4dac8cf77b#482772f2317e242e6b98bfe04ed42e4dac8cf77b" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985cc35d832d412224b2cffe2f9194b1b89b6aa5d0bef76d080dce09d90e62bd" dependencies = [ "opentelemetry", ] @@ -1846,7 +1758,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ "lock_api", - "parking_lot_core 0.9.0", + "parking_lot_core 0.9.1", ] [[package]] @@ -1865,9 +1777,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2f4f894f3865f6c0e02810fc597300f34dc2510f66400da262d8ae10e75767d" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" dependencies = [ "cfg-if", "libc", @@ -2006,15 +1918,14 @@ checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "png" -version = "0.17.2" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c845088517daa61e8a57eee40309347cea13f273694d1385c553e7a57127763b" +checksum = "8e8f1882177b17c98ec33a51f5910ecbf4db92ca0def706781a1f8d0c661f393" dependencies = [ "bitflags", "crc32fast", - "deflate 0.9.1", - "encoding", - "miniz_oxide", + "deflate", + "miniz_oxide 0.5.1", ] [[package]] @@ -2134,14 +2045,13 @@ checksum = "3fee2dce59f7a43418e3382c766554c614e06a552d53a8f07ef499ea4b332c0f" [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -2163,15 +2073,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - [[package]] name = "rayon" version = "1.5.1" @@ -2265,7 +2166,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustls 0.20.2", + "rustls 0.20.4", "rustls-native-certs", "rustls-pemfile", "serde", @@ -2273,7 +2174,7 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-rustls 0.23.2", - "tokio-util", + "tokio-util 0.6.9", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -2298,12 +2199,12 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.31" +version = "0.7.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439655b8d657bcb28264da8e5380d55549e34ffc4149bea9e3521890a122a7bd" +checksum = "bf98e3e6c7ed44e474b454b1ebded3193ee5aba3428e29c55d59b1d65e49945e" dependencies = [ "bytecheck", - "hashbrown", + "hashbrown 0.12.0", "ptr_meta", "rend", "rkyv_derive", @@ -2312,24 +2213,15 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.31" +version = "0.7.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cded413ad606a80291ca84bedba137093807cf4f5b36be8c60f57a7e790d48f6" +checksum = "cc9940ec6a7c62b1d1f476f607c6caf0d7fbf74e43f77bc022143b878fcd3266" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "rustls" version = "0.19.1" @@ -2345,9 +2237,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.2" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" +checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" dependencies = [ "log", "ring", @@ -2444,7 +2336,7 @@ dependencies = [ "swimmer", "tikv-jemallocator", "tokio", - "tokio-util", + "tokio-util 0.7.0", "toml", "tower", "tower-http", @@ -2506,9 +2398,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fed7948b6c68acbb6e20c334f55ad635dc0f75506963de4464289fbd3b051ac" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" dependencies = [ "bitflags", "core-foundation", @@ -2519,20 +2411,14 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57321bf8bc2362081b2599912d2961fe899c0efadf1b4b2f8d48b3e253bb96c" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ "core-foundation-sys", "libc", ] -[[package]] -name = "semver" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" - [[package]] name = "serde" version = "1.0.136" @@ -2555,11 +2441,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ - "itoa 1.0.1", + "itoa", "ryu", "serde", ] @@ -2582,7 +2468,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.1", + "itoa", "ryu", "serde", ] @@ -2613,9 +2499,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" +checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86" dependencies = [ "digest 0.10.3", "keccak", @@ -2721,9 +2607,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692749de69603d81e016212199d73a2e14ee20e2def7d7914919e8db5d4d48b9" +checksum = "fc15591eb44ffb5816a4a70a7efd5dd87bfd3aa84c4c200401c4396140525826" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2731,18 +2617,16 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518be6f6fff5ca76f985d434f9c37f3662af279642acf730388f271dff7b9016" +checksum = "195183bf6ff8328bb82c0511a83faf60aacf75840103388851db61d7a9854ae3" dependencies = [ "ahash", "atoi", "bitflags", "byteorder", "bytes", - "crossbeam-channel", "crossbeam-queue", - "crossbeam-utils", "either", "flume", "futures-channel", @@ -2753,13 +2637,13 @@ dependencies = [ "hashlink", "hex", "indexmap", - "itoa 1.0.1", + "itoa", "libc", "libsqlite3-sys", "log", "memchr", "once_cell", - "parking_lot 0.11.2", + "paste 1.0.6", "percent-encoding", "rustls 0.19.1", "smallvec", @@ -2775,9 +2659,9 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e45140529cf1f90a5e1c2e561500ca345821a1c513652c8f486bbf07407cc8" +checksum = "eee35713129561f5e55c554bba1c378e2a7e67f81257b7311183de98c50e6f94" dependencies = [ "dotenv", "either", @@ -2793,9 +2677,9 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8061cbaa91ee75041514f67a09398c65a64efed72c90151ecd47593bad53da99" +checksum = "b555e70fbbf84e269ec3858b7a6515bcfe7a166a7cc9c636dd6efd20431678b6" dependencies = [ "once_cell", "tokio", @@ -2925,9 +2809,9 @@ dependencies = [ [[package]] name = "thrift" -version = "0.13.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6d965454947cc7266d22716ebfd07b18d84ebaf35eec558586bbb2a8cb6b5b" +checksum = "b82ca8f46f95b3ce96081fe3dd89160fdea970c254bb72925255d1b62aae692e" dependencies = [ "byteorder", "integer-encoding", @@ -2993,9 +2877,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.16.1" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" dependencies = [ "bytes", "libc", @@ -3005,6 +2889,7 @@ dependencies = [ "once_cell", "pin-project-lite", "signal-hook-registry", + "socket2", "tokio-macros", "tracing", "winapi", @@ -3048,7 +2933,7 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" dependencies = [ - "rustls 0.20.2", + "rustls 0.20.4", "tokio", "webpki 0.22.0", ] @@ -3072,7 +2957,7 @@ checksum = "e80b39df6afcc12cdf752398ade96a6b9e99c903dfdc36e53ad10b9c366bca72" dependencies = [ "futures-util", "log", - "rustls 0.20.2", + "rustls 0.20.4", "rustls-native-certs", "tokio", "tokio-rustls 0.23.2", @@ -3094,6 +2979,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.5.8" @@ -3126,7 +3025,7 @@ dependencies = [ "prost-derive", "tokio", "tokio-stream", - "tokio-util", + "tokio-util 0.6.9", "tower", "tower-layer", "tower-service", @@ -3148,9 +3047,9 @@ dependencies = [ [[package]] name = "tower" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5651b5f6860a99bd1adb59dbfe1db8beb433e73709d9032b413a77e2fb7c066a" +checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" dependencies = [ "futures-core", "futures-util", @@ -3160,8 +3059,7 @@ dependencies = [ "rand", "slab", "tokio", - "tokio-stream", - "tokio-util", + "tokio-util 0.7.0", "tower-layer", "tower-service", "tracing", @@ -3169,9 +3067,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03650267ad175b51c47d02ed9547fc7d4ba2c7e5cb76df0bed67edd1825ae297" +checksum = "2bb284cac1883d54083a0edbdc9cabf931dfed87455f8c7266c01ece6394a43a" dependencies = [ "bitflags", "bytes", @@ -3200,9 +3098,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" dependencies = [ "cfg-if", "log", @@ -3213,9 +3111,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" dependencies = [ "proc-macro2", "quote", @@ -3224,11 +3122,12 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" dependencies = [ "lazy_static", + "valuable", ] [[package]] @@ -3254,21 +3153,22 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.16.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ffbf13a0f8b054a4e59df3a173b818e9c6177c02789871f2073977fd0062076" +checksum = "a73d0f08e0d227c4c63e6d003804946767f4c4f01f52098b56821ae22e336bfc" dependencies = [ "opentelemetry", "tracing", "tracing-core", + "tracing-log", "tracing-subscriber", ] [[package]] name = "tracing-subscriber" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5312f325fe3588e277415f5a6cca1f4ccad0f248c4cd5a4bd33032d7286abc22" +checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce" dependencies = [ "ansi_term", "sharded-slab", @@ -3306,7 +3206,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls 0.20.2", + "rustls 0.20.4", "sha-1 0.9.8", "thiserror", "url", @@ -3337,9 +3237,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "unicode-xid" @@ -3393,6 +3293,12 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -3621,9 +3527,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceb069ac8b2117d36924190469735767f0990833935ab430155e71a44bafe148" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -3634,33 +3540,33 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" [[package]] name = "windows_i686_gnu" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" [[package]] name = "windows_i686_msvc" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" [[package]] name = "windows_x86_64_gnu" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" [[package]] name = "windows_x86_64_msvc" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" [[package]] name = "winreg" diff --git a/Cargo.toml b/Cargo.toml index ecde11d..e8d2174 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ sqlite = ["sqlx", "itertools"] [dependencies] scherzo_derive = { path = "./scherzo_derive" } -harmony_rust_sdk = { git = "https://github.com/harmony-development/harmony_rust_sdk.git", branch = "master", features = [ +harmony_rust_sdk = { git = "https://github.com/harmony-development/harmony_rust_sdk.git", branch = "refactored", features = [ "gen_all_protocols", "gen_client", "gen_server", @@ -85,7 +85,7 @@ rand = "0.8" argon2 = "0.3" ed25519-compact = "1" sha3 = "0.10" -ahash = { version = "0.7", default-features = false } +ahash = "0.7" tokio = { version = "1.16", features = [ "macros", @@ -94,7 +94,7 @@ tokio = { version = "1.16", features = [ "tracing", "signal", ] } -tokio-util = "0.6.7" +tokio-util = { version = "0.7", features = ["io"] } swimmer = "0.3" tracing = "0.1" @@ -106,9 +106,9 @@ tracing-subscriber = { version = "0.3", default-features = false, features = [ "std", ] } console-subscriber = { git = "https://github.com/tokio-rs/console.git", branch = "main" } -opentelemetry = { version = "0.16", features = ["rt-tokio"] } -opentelemetry-jaeger = { version = "0.15", features = ["rt-tokio"] } -tracing-opentelemetry = { version = "0.16", default-features = false } +opentelemetry = { version = "0.17", features = ["rt-tokio"] } +opentelemetry-jaeger = { version = "0.16", features = ["rt-tokio"] } +tracing-opentelemetry = { version = "0.17" } pin-project = "1" @@ -138,7 +138,7 @@ mediasoup = { version = "0.9", optional = true } tikv-jemallocator = { git = "https://github.com/tikv/jemallocator.git", branch = "master", optional = true } [build-dependencies] -harmony_build = { git = "https://github.com/harmony-development/harmony_rust_sdk.git", branch = "master", features = [ +harmony_build = { git = "https://github.com/harmony-development/harmony_rust_sdk.git", branch = "refactored", features = [ "client", "server", "all_permissions", @@ -179,6 +179,4 @@ key = "harmony.cachix.org-1:yv78QZHgS0UHkrMW56rccNghWHRz18fFRl8mWQ63M6E=" markup5ever = { git = "https://github.com/servo/html5ever.git", rev = "0e03e1c2b1f63e81f831fd95b9eb8bbde18b7815" } string_cache = { git = "https://github.com/yusdacra/string-cache.git", branch = "chore/deps" } string_cache_codegen = { git = "https://github.com/yusdacra/string-cache.git", branch = "chore/deps" } -opentelemetry-jaeger = { git = "https://github.com/open-telemetry/opentelemetry-rust.git", rev = "482772f2317e242e6b98bfe04ed42e4dac8cf77b" } -opentelemetry = { git = "https://github.com/open-telemetry/opentelemetry-rust.git", rev = "482772f2317e242e6b98bfe04ed42e4dac8cf77b" } swimmer = { git = "https://github.com/yusdacra/swimmer-rs.git", branch = "master" } \ No newline at end of file diff --git a/build.rs b/build.rs index e805109..bb4e221 100644 --- a/build.rs +++ b/build.rs @@ -42,7 +42,7 @@ fn build_protocol( cfg }); - for service in all_services.filter(|a| "batch.v1".ne(**a)) { + for service in all_services { builder = builder.modify_hrpc_config(|cfg| { cfg.type_attribute( format!(".protocol.{}", service), diff --git a/protocols/before_proto_v2 b/protocols/before_proto_v2 new file mode 160000 index 0000000..2aef2cc --- /dev/null +++ b/protocols/before_proto_v2 @@ -0,0 +1 @@ +Subproject commit 2aef2cca047c6f3db76af543b06133ee4bd15028 diff --git a/src/db/migration/add_account_kind.rs b/src/db/migration/add_account_kind.rs index a587c8a..5db99b9 100644 --- a/src/db/migration/add_account_kind.rs +++ b/src/db/migration/add_account_kind.rs @@ -7,7 +7,6 @@ use db::{ rkyv_ser, Batch, DbError, }; use harmony_rust_sdk::api::profile::AccountKind; -use hrpc::box_error; use crate::api::profile::Profile as NewProfile; use profile::Profile as OldProfile; @@ -24,7 +23,6 @@ pub(super) fn migrate(db: &Db) -> BoxFuture<'_, DbResult<()>> { let new_val = rkyv_ser(&NewProfile { user_avatar: old_profile.user_avatar, account_kind: AccountKind::FullUnspecified.into(), - is_bot: old_profile.is_bot, user_name: old_profile.user_name, user_status: old_profile.user_status, }); @@ -33,12 +31,12 @@ pub(super) fn migrate(db: &Db) -> BoxFuture<'_, DbResult<()>> { // if it's new, then its already fine continue; } else { - old_profile.map_err(|err| DbError { - inner: box_error(AnyhowError(anyhow::anyhow!( - "profile with key {} has invalid state: {}", - String::from_utf8_lossy(key.as_ref()), - err - ))), + old_profile.map_err(|err| { + DbError::from( + anyhow::anyhow!("profile has invalid state") + .context(format!("rkyv error: {}", err)) + .context(format!("key: {}", String::from_utf8_lossy(key.as_ref()))), + ) })?; } } @@ -52,14 +50,3 @@ pub(super) fn migrate(db: &Db) -> BoxFuture<'_, DbResult<()>> { scherzo_derive::define_proto_mod!(before_account_kind, profile); scherzo_derive::define_proto_mod!(before_account_kind, harmonytypes); - -#[derive(Debug)] -struct AnyhowError(anyhow::Error); - -impl Display for AnyhowError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Display::fmt(&self.0, f) - } -} - -impl std::error::Error for AnyhowError {} diff --git a/src/db/mod.rs b/src/db/mod.rs index f5ab4e7..f383a84 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -31,6 +31,7 @@ use std::{ error::Error as StdError, fmt::{self, Display, Formatter}, mem::size_of, + pin::Pin, }; use crate::{config::DbConfig, utils::evec::EVec, ServerError, ServerResult}; @@ -99,6 +100,12 @@ pub struct DbError { pub inner: Box, } +impl From for DbError { + fn from(err: anyhow::Error) -> Self { + Self { inner: err.into() } + } +} + impl Display for DbError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("a database error occured") diff --git a/src/impls/auth/delete_user.rs b/src/impls/auth/delete_user.rs index c2f3961..9f97901 100644 --- a/src/impls/auth/delete_user.rs +++ b/src/impls/auth/delete_user.rs @@ -16,7 +16,6 @@ pub async fn logic(deps: &Dependencies, user_id: u64) -> ServerResult<()> { Some("Deleted User".to_string()), Some("".to_string()), Some(UserStatus::OfflineUnspecified.into()), - Some(false), ) .await?; diff --git a/src/impls/auth/login_federated.rs b/src/impls/auth/login_federated.rs index ce215cc..e8435b7 100644 --- a/src/impls/auth/login_federated.rs +++ b/src/impls/auth/login_federated.rs @@ -47,7 +47,6 @@ pub async fn handler( ); // Add the profile entry let profile = Profile { - is_bot: false, user_status: UserStatus::OfflineUnspecified.into(), user_avatar: avatar, user_name: username, diff --git a/src/impls/auth/mod.rs b/src/impls/auth/mod.rs index a785918..29018e9 100644 --- a/src/impls/auth/mod.rs +++ b/src/impls/auth/mod.rs @@ -6,6 +6,7 @@ use crate::api::{ }; use ahash::RandomState; use dashmap::DashMap; +use harmony_rust_sdk::api::profile::AccountKind; use hrpc::server::gen_prelude::BoxFuture; use hyper::{http, HeaderMap}; use rand::{Rng, SeedableRng}; @@ -142,7 +143,7 @@ impl AuthServer { atime_key(id), get_time_secs().to_be_bytes(), ); - } else if !profile.is_bot + } else if profile.account_kind() != AccountKind::Bot && auth_how_old >= SESSION_EXPIRE { tracing::debug!("user {} session has expired", id); diff --git a/src/impls/auth/next_step.rs b/src/impls/auth/next_step.rs index 21f8bcd..ad49ee7 100644 --- a/src/impls/auth/next_step.rs +++ b/src/impls/auth/next_step.rs @@ -159,7 +159,7 @@ fn form<'a>( .map(|(name, r#type)| { auth_step::form::FormField::new(name.to_string(), r#type.to_string()) }) - .collect(), + .collect::>(), ))) } @@ -180,7 +180,7 @@ pub fn handle_choice(svc: &AuthServer, choice: &str) -> ServerResult { AuthStep { can_go_back: true, fallback_url: String::default(), - step: Some(auth_step::Step::new_choice(auth_step::Choice::new( + step: Some(auth_step::Step::Choice(auth_step::Choice::new( "other-options".to_string(), options, ))), diff --git a/src/impls/batch/batch.rs b/src/impls/batch/batch.rs deleted file mode 100644 index e987af9..0000000 --- a/src/impls/batch/batch.rs +++ /dev/null @@ -1,29 +0,0 @@ -use super::*; - -pub async fn handler( - svc: &BatchServer, - mut request: Request, -) -> ServerResult> { - let auth_header = request - .header_map_mut() - .and_then(|h| h.remove(header::AUTHORIZATION)); - let BatchRequest { requests } = request.into_message().await?; - - let request_len = requests.len(); - let (bodies, endpoints) = requests.into_iter().fold( - ( - Vec::with_capacity(request_len), - Vec::with_capacity(request_len), - ), - |(mut bodies, mut endpoints), request| { - bodies.push(request.request); - endpoints.push(request.endpoint); - (bodies, endpoints) - }, - ); - let responses = svc - .make_req(bodies, Endpoint::Different(endpoints), auth_header) - .await?; - - Ok((BatchResponse { responses }).into_response()) -} diff --git a/src/impls/batch/batch_same.rs b/src/impls/batch/batch_same.rs deleted file mode 100644 index 6863412..0000000 --- a/src/impls/batch/batch_same.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::*; - -pub async fn handler( - svc: &BatchServer, - mut request: Request, -) -> ServerResult> { - let auth_header = request - .header_map_mut() - .and_then(|h| h.remove(header::AUTHORIZATION)); - let BatchSameRequest { endpoint, requests } = request.into_message().await?; - - let responses = svc - .make_req(requests, Endpoint::Same(endpoint), auth_header) - .await?; - - Ok((BatchSameResponse { responses }).into_response()) -} diff --git a/src/impls/batch/mod.rs b/src/impls/batch/mod.rs deleted file mode 100644 index cb312f6..0000000 --- a/src/impls/batch/mod.rs +++ /dev/null @@ -1,192 +0,0 @@ -use std::{future::Future, ops::Not}; - -use crate::api::{ - batch::{batch_service_server::BatchService, *}, - exports::{ - hrpc::{ - response, - server::{router::RoutesFinalized, MakeRoutes}, - }, - prost::bytes::Bytes, - }, -}; -use hrpc::{body::Body, exports::futures_util::StreamExt}; -use hyper::{header, http::HeaderValue}; -use swimmer::{Pool, PoolBuilder, Recyclable}; -use tower::Service as _; - -use super::prelude::*; - -#[allow(clippy::module_inception)] -pub mod batch; -pub mod batch_same; - -struct BatchReq { - bodies: Vec, - endpoint: Endpoint, - auth_header: Option, -} - -impl BatchReq { - async fn process_req( - self, - service: &mut RoutesFinalized, - ) -> Result, HrpcServerError> { - fn process_request( - body: Bytes, - endpoint: &str, - auth_header: &Option, - service: &mut RoutesFinalized, - ) -> impl Future> + Send + 'static { - let mut req = Request::new_with_body(Body::full(body)); - *req.endpoint_mut() = endpoint.to_string().into(); - - if let Some(auth) = auth_header { - req.get_or_insert_header_map() - .insert(header::AUTHORIZATION, auth.clone()); - } - - let fut = service.call(req); - - async move { - let mut reply = fut.await.unwrap(); - if let Some(err) = reply.extensions_mut().remove::() { - bail!(err); - } - - // This should be safe since we know we insert a message into responses - // as whole chunks - Ok(response::Parts::from(reply).body.next().await.unwrap()?) - } - } - - if self.bodies.len() > 64 { - return Err(ServerError::TooManyBatchedRequests.into()); - } - - let mut responses = Vec::with_capacity(self.bodies.len()); - - let auth_header = &self.auth_header; - match &self.endpoint { - Endpoint::Same(endpoint) => { - tracing::debug!( - "batching {} requests for endpoint {}", - self.bodies.len(), - endpoint - ); - if is_valid_endpoint(endpoint).not() { - bail!(ServerError::InvalidBatchEndpoint(endpoint.to_string())); - } - let mut handles = Vec::with_capacity(self.bodies.len()); - for body in self.bodies { - let handle = - tokio::spawn(process_request(body, endpoint, auth_header, service)); - handles.push(handle); - } - for handle in handles { - responses.push(handle.await.expect("task panicked")?); - } - } - Endpoint::Different(a) => { - for endpoint in a { - if is_valid_endpoint(endpoint).not() { - bail!(ServerError::InvalidBatchEndpoint(endpoint.to_string())); - } - } - let mut handles = Vec::with_capacity(self.bodies.len()); - for (body, endpoint) in self.bodies.into_iter().zip(a) { - tracing::debug!("batching request for endpoint {}", endpoint); - let handle = - tokio::spawn(process_request(body, endpoint, auth_header, service)); - handles.push(handle); - } - for handle in handles { - responses.push(handle.await.expect("task panicked")?); - } - } - } - - Ok(responses) - } -} - -struct RecyclableService(RoutesFinalized); - -impl Recyclable for RecyclableService { - fn new() -> Self - where - Self: Sized, - { - unreachable!("won't panic because we use the supplier function") - } - - fn recycle(&mut self) {} -} - -enum Endpoint { - Same(String), - Different(Vec), -} - -fn is_valid_endpoint(endpoint: &str) -> bool { - const ACCEPTED_ENDPOINTS: [&str; 9] = [ - "/protocol.profile.v1.ProfileService/GetProfile", - "/protocol.chat.v1.ChatService/QueryHasPermission", - "/protocol.chat.v1.ChatService/GetUserRoles", - "/protocol.chat.v1.ChatService/GetGuildRoles", - "/protocol.chat.v1.ChatService/GetGuild", - "/protocol.chat.v1.ChatService/GetGuildChannels", - "/protocol.mediaproxy.v1.MediaProxyService/FetchLinkMetadata", - "/protocol.mediaproxy.v1.MediaProxyService/InstantView", - "/protocol.mediaproxy.v1.MediaProxyService/CanInstantView", - ]; - - let endpoint = endpoint.trim_end_matches('/'); - ACCEPTED_ENDPOINTS.contains(&endpoint) -} - -#[derive(Clone)] -pub struct BatchServer { - deps: Arc, - disable_ratelimits: bool, - svc_pool: Arc>, -} - -impl BatchServer { - pub fn new(deps: Arc, svc: Svc) -> Self { - Self { - disable_ratelimits: deps.config.policy.ratelimit.disable, - svc_pool: Arc::new( - PoolBuilder::default() - .with_supplier(move || RecyclableService(svc.make_routes().build())) - .build(), - ), - deps, - } - } - - async fn make_req( - &self, - bodies: Vec, - endpoint: Endpoint, - auth_header: Option, - ) -> ServerResult> { - let mut service = self.svc_pool.get(); - (BatchReq { - bodies, - endpoint, - auth_header, - }) - .process_req(&mut service.0) - .await - } -} - -impl BatchService for BatchServer { - impl_unary_handlers! { - #[rate(10, 4)] - batch, BatchRequest, BatchResponse; - #[rate(10, 4)] - batch_same, BatchSameRequest, BatchSameResponse; - } -} diff --git a/src/impls/chat/guilds/create_guild.rs b/src/impls/chat/guilds/create_guild.rs index 21a4a61..817ecfc 100644 --- a/src/impls/chat/guilds/create_guild.rs +++ b/src/impls/chat/guilds/create_guild.rs @@ -28,7 +28,7 @@ pub async fn handler( name, picture, metadata, - guild_kind::Kind::new_normal(guild_kind::Normal::new()), + guild_kind::Kind::Normal(guild_kind::Normal::new()), ) .await?; diff --git a/src/impls/chat/guilds/get_guild.rs b/src/impls/chat/guilds/get_guild.rs index 57e61da..1ef33ad 100644 --- a/src/impls/chat/guilds/get_guild.rs +++ b/src/impls/chat/guilds/get_guild.rs @@ -6,14 +6,19 @@ pub async fn handler( ) -> ServerResult> { let user_id = svc.deps.auth(&request).await?; - let GetGuildRequest { guild_id } = request.into_message().await?; + let GetGuildRequest { guild_ids } = request.into_message().await?; let chat_tree = &svc.deps.chat_tree; - chat_tree.check_guild_user(guild_id, user_id).await?; + for guild_id in guild_ids.iter().copied() { + chat_tree.check_guild_user(guild_id, user_id).await?; + } - chat_tree - .get_guild_logic(guild_id) - .await - .map(|g| (GetGuildResponse { guild: Some(g) }).into_response()) + let mut guilds = HashMap::with_capacity(guild_ids.len()); + for guild_id in guild_ids { + let guild = chat_tree.get_guild_logic(guild_id).await?; + guilds.insert(guild_id, guild); + } + + Ok(GetGuildResponse::new(guilds).into_response()) } diff --git a/src/impls/chat/messages/send_message.rs b/src/impls/chat/messages/send_message.rs index 9e11182..5a0583c 100644 --- a/src/impls/chat/messages/send_message.rs +++ b/src/impls/chat/messages/send_message.rs @@ -24,32 +24,33 @@ pub async fn handler( chat_tree.process_message_overrides(request.overrides.as_ref())?; let content = chat_tree - .process_message_content( - request.content.take(), - svc.deps.config.media.media_root.as_path(), - &svc.deps.config.host, - ) + .process_message_content(svc.deps.as_ref(), request.content.take()) .await?; - request.content = Some(content); - let (message_id, message) = chat_tree.send_message_logic(user_id, request).await?; - let is_cmd_channel = chat_tree + let admin_action = chat_tree .admin_guild_keys .get() - .map_or(false, |keys| keys.check_if_cmd(guild_id, channel_id)); + .map_or(false, |keys| keys.check_if_cmd(guild_id, channel_id)) + .then(|| content.text.parse::().ok()) + .flatten(); + + let (message_id, message) = chat_tree + .send_message_logic( + guild_id, + channel_id, + user_id, + content, + request.overrides, + request.in_reply_to, + request.metadata, + ) + .await?; - let action_content = if is_cmd_channel { - if let Some(content::Content::TextMessage(content::TextContent { - content: Some(FormattedText { text, .. }), - })) = message.content.as_ref().and_then(|c| c.content.as_ref()) - { - let msg = admin_action::run_str(svc.deps.as_ref(), text) - .await - .unwrap_or_else(|err| format!("error: {}", err)); - Some(msg) - } else { - None - } + let action_content = if let Some(action) = admin_action { + let msg = admin_action::run(svc.deps.as_ref(), action) + .await + .unwrap_or_else(|err| format!("error: {}", err)); + Some(msg) } else { None }; @@ -73,9 +74,7 @@ pub async fn handler( ); if let Some(msg) = action_content { - let content = content::Content::TextMessage(content::TextContent { - content: Some(FormattedText::new(msg, Vec::new())), - }); + let content = Content::default().with_text(msg); let (message_id, message) = chat_tree .send_with_system(guild_id, channel_id, content) .await?; diff --git a/src/impls/chat/messages/update_message_text.rs b/src/impls/chat/messages/update_message_text.rs index 84ac07d..57a0c3c 100644 --- a/src/impls/chat/messages/update_message_text.rs +++ b/src/impls/chat/messages/update_message_text.rs @@ -26,8 +26,11 @@ pub async fn handler( .check_perms(guild_id, Some(channel_id), user_id, "messages.send", false) .await?; - if new_content.as_ref().map_or(true, |f| f.text.is_empty()) { - return Err(ServerError::MessageContentCantBeEmpty.into()); + let Some(new_content) = new_content else { + bail!(ServerError::MessageContentCantBeEmpty); + }; + if new_content.text.is_empty() { + bail!(ServerError::MessageContentCantBeEmpty); } let key = make_msg_key(guild_id, channel_id, message_id); @@ -47,17 +50,15 @@ pub async fn handler( .deserialize(&mut SharedDeserializeMap::default()) .unwrap(); - let msg_content = if let Some(content) = &mut message.content { - content - } else { - message.content = Some(Content::default()); - message.content.as_mut().unwrap() - }; - msg_content.content = Some(content::Content::TextMessage(content::TextContent { - content: new_content.clone(), - })); - let edited_at = get_time_secs(); + if let Some(content) = &mut message.content { + content.text.clear(); + content.text.push_str(&new_content.text); + content.text_formats.clear(); + content + .text_formats + .extend(new_content.format.iter().cloned()); + } message.edited_at = Some(edited_at); let buf = rkyv_ser(&message); @@ -70,7 +71,7 @@ pub async fn handler( channel_id, message_id, edited_at, - new_content, + new_content: Some(new_content), }), Some(PermCheck::new( guild_id, diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 21b5c84..37fb904 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -26,6 +26,7 @@ use rand::{Rng, SeedableRng}; use scherzo_derive::*; use smol_str::SmolStr; use tokio::{ + io::AsyncReadExt, sync::{broadcast::Sender as BroadcastSend, mpsc::UnboundedSender}, task::JoinHandle, }; @@ -478,7 +479,7 @@ impl chat_service_server::ChatService for ChatServer { #[rate(15, 8)] send_message, SendMessageRequest, SendMessageResponse; #[rate(5, 7)] - query_has_permission, QueryHasPermissionRequest, QueryHasPermissionResponse; + has_permission, HasPermissionRequest, HasPermissionResponse; #[rate(5, 7)] set_permissions, SetPermissionsRequest, SetPermissionsResponse; #[rate(7, 5)] @@ -1011,7 +1012,7 @@ impl ChatTree { })) } - pub async fn query_has_permission_logic( + pub async fn has_permission_logic( &self, guild_id: u64, channel_id: Option, @@ -1046,6 +1047,8 @@ impl ChatTree { Ok(false) } + // TODO: make this return bool so we can differ db errors + // from actual permission error pub async fn check_perms( &self, guild_id: u64, @@ -1061,7 +1064,7 @@ impl ChatTree { } } else if is_owner || self - .query_has_permission_logic(guild_id, channel_id, user_id, check_for) + .has_permission_logic(guild_id, channel_id, user_id, check_for) .await? { return Ok(()); @@ -1425,12 +1428,12 @@ impl ChatTree { } } - pub async fn query_has_permission_request( + pub async fn has_permission_request( &self, user_id: u64, - request: QueryHasPermissionRequest, - ) -> ServerResult { - let QueryHasPermissionRequest { + request: HasPermissionRequest, + ) -> ServerResult { + let HasPermissionRequest { guild_id, channel_id, check_for, @@ -1450,12 +1453,16 @@ impl ChatTree { return Err(ServerError::EmptyPermissionQuery.into()); } - Ok(QueryHasPermissionResponse { - ok: self + let mut perms = Vec::with_capacity(check_for.len()); + for check_for in check_for { + let ok = self .check_perms(guild_id, channel_id, check_as, &check_for, false) .await - .is_ok(), - }) + .is_ok(); + perms.push(Permission::new(check_for, ok)); + } + + Ok(HasPermissionResponse::new(perms)) } pub async fn get_next_message_id( @@ -1489,19 +1496,14 @@ impl ChatTree { pub async fn send_message_logic( &self, + guild_id: u64, + channel_id: u64, user_id: u64, - request: SendMessageRequest, + content: Content, + overrides: Option, + in_reply_to: Option, + metadata: Option, ) -> ServerResult<(u64, HarmonyMessage)> { - let SendMessageRequest { - guild_id, - channel_id, - content, - echo_id: _, - overrides, - in_reply_to, - metadata, - } = request; - let message_id = self.get_next_message_id(guild_id, channel_id).await?; let key = make_msg_key(guild_id, channel_id, message_id); // [tag:msg_key_u64] @@ -1513,7 +1515,7 @@ impl ChatTree { author_id: user_id, created_at, edited_at, - content, + content: Some(content), in_reply_to, overrides, reactions: Vec::new(), @@ -1546,249 +1548,191 @@ impl ChatTree { Ok(()) } - pub async fn process_message_content( + pub async fn process_attachment_info( &self, - content: Option, - media_root: &Path, - host: &str, - ) -> ServerResult { - use content::Content as MsgContent; - - let inner_content = content.and_then(|c| c.content); - let content = if let Some(content) = inner_content { - let content = match content { - content::Content::TextMessage(text) => { - if text.content.as_ref().map_or(true, |f| f.text.is_empty()) { - bail!(ServerError::MessageContentCantBeEmpty); - } - content::Content::TextMessage(text) - } - content::Content::PhotoMessage(mut photos) => { - if photos.photos.is_empty() { - bail!(ServerError::MessageContentCantBeEmpty); - } - for photo in photos.photos.drain(..).collect::>() { - // TODO: return error for invalid hmc - if let Ok(file_id) = FileId::from_str(&photo.hmc) { - // TODO: check if the hmc host matches ours, if not fetch the image from the other host - let id = match &file_id { - FileId::External(_) => bail!(( - "h.photo-cant-have-external-url", - "message photo contents cant use external URL" - )), - FileId::Hmc(hmc) => hmc.id(), - FileId::Id(id) => id.as_str(), - }; + deps: &Dependencies, + info: Option, + id: String, + size: u64, + mimetype: &str, + mut filebuf: tokio::io::BufReader<&mut tokio::fs::File>, + ) -> Result<(String, Option), ServerError> { + use send_message_request::{attachment::Info, ImageInfo as RequestImageInfo}; + + let media_root = &deps.config.media.media_root; + + let Some(info) = info else { + return Ok((id, None)); + }; - let image_id = format!("{}_{}", id, "jpeg"); - let image_path = media_root.join(&image_id); - let minithumbnail_id = format!("{}_{}", id, "jpegthumb"); - let minithumbnail_path = media_root.join(&minithumbnail_id); - - let ((file_size, isize), minithumbnail) = - if image_path.exists() && minithumbnail_path.exists() { - let minithumbnail = tokio::fs::read(&minithumbnail_path) - .await - .map_err(ServerError::from)?; - - let ifile = tokio::fs::File::open(&image_path) - .await - .map_err(ServerError::from)?; - - let file_size = - ifile.metadata().await.map_err(ServerError::from)?.len(); - let ifile = BufReader::new(ifile.into_std().await); - let ireader = image::io::Reader::new(ifile) - .with_guessed_format() - .map_err(ServerError::from)?; - // this should be cheap and shouldnt block... - let isize = ireader - .into_dimensions() - .map_err(|_| ServerError::InternalServerError)?; - - let mut minithumbnail = std::io::Cursor::new(minithumbnail); - let minireader = image::io::Reader::new(&mut minithumbnail) - .with_guessed_format() - .map_err(ServerError::from)?; - let minisize = minireader - .into_dimensions() - .map_err(|_| ServerError::InternalServerError)?; - - ( - (file_size as u32, isize), - Minithumbnail { - width: minisize.0, - height: minisize.1, - data: minithumbnail.into_inner(), - }, - ) - } else { - let (_, mime, data, _) = get_file_full(media_root, id).await?; - - let is_animated = mime == "image/gif"; - - let (minithumbnail, image_size, image_raw, data) = - tokio::task::spawn_blocking(move || { - let image = (mime == "image/webp") - .then(|| { - let decoder = webp::Decoder::new(&data); - decoder.decode().map(|i| i.to_image()) - }) - .flatten() - .or_else(|| image::load_from_memory(&data).ok()) - .ok_or(ServerError::InternalServerError)?; - - let image_size = image.dimensions(); - let minithumbnail = image.thumbnail(64, 64); - let encoded = is_animated.not().then(|| { - let rgba = image.into_rgba8(); - let encoder = webp::Encoder::from_rgba( - rgba.as_ref(), - rgba.width(), - rgba.height(), - ); - encoder.encode(100.0) - }); - ServerResult::Ok(( - minithumbnail, - image_size, - encoded.map(|m| m.to_vec()), - data, - )) - }) - .await - .map_err(|_| ServerError::InternalServerError)??; - - let image_raw = image_raw.unwrap_or(data); - - tokio::fs::write(&image_path, &image_raw) - .await - .map_err(ServerError::from)?; - - let (minithumb_size, minithumbnail_raw) = - tokio::task::spawn_blocking(move || { - let rgba = minithumbnail.into_rgba8(); - let encoder = webp::Encoder::from_rgba( - rgba.as_ref(), - rgba.width(), - rgba.height(), - ); - let encoded = encoder.encode(100.0); - - ServerResult::Ok(((64, 64), encoded.to_vec())) - }) - .await - .map_err(|_| ServerError::InternalServerError)??; - - tokio::fs::write(&minithumbnail_path, &minithumbnail_raw) - .await - .map_err(ServerError::from)?; - - ( - (image_raw.len() as u32, image_size), - Minithumbnail { - width: minithumb_size.0, - height: minithumb_size.1, - data: minithumbnail_raw, - }, - ) - }; - - photos.photos.push(Photo { - hmc: Hmc::new(host, image_id).unwrap().into(), - minithumbnail: Some(minithumbnail), - width: isize.0, - height: isize.1, - file_size, - ..photo - }); - } else { - photos.photos.push(photo); - } - } - content::Content::PhotoMessage(photos) - } - content::Content::AttachmentMessage(mut files) => { - if files.files.is_empty() { - bail!(ServerError::MessageContentCantBeEmpty); - } - for attachment in files.files.drain(..).collect::>() { - if let Ok(id) = FileId::from_str(&attachment.id) { - let fill_file_local = move |attachment: Attachment, id: String| async move { - let is_jpeg = is_id_jpeg(&id); - let (mut file, metadata, path) = - get_file_handle(media_root, &id).await?; - let (filename_raw, mimetype_raw, _) = - read_bufs(&path, &mut file, is_jpeg).await?; - let (start, end) = calculate_range( - &filename_raw, - &mimetype_raw, - &metadata, - is_jpeg, + let (id, info) = match info { + Info::Image(RequestImageInfo { + caption, + use_original, + }) => { + let mut raw = Vec::with_capacity(size as usize); + filebuf.read_to_end(&mut raw).await?; + + let is_animated = mimetype == "image/gif"; + let is_webp = mimetype == "image/webp"; + + // TODO: improve this code + let minithumbnail_id = format!("{}_jpegthumb", id); + let minithumbnail_path = media_root.join(&minithumbnail_id); + let id = use_original + .not() + .then(|| format!("{}_jpeg", id)) + .unwrap_or(id); + let image_path = media_root.join(&id); + + let task_fn = move || -> Result<_, ServerError> { + if image_path.exists() && minithumbnail_path.exists() { + let ifile = std::fs::File::open(&image_path)?; + let ifile = BufReader::new(ifile); + let ireader = image::io::Reader::new(ifile).with_guessed_format()?; + let idimensions = ireader + .into_dimensions() + .map_err(|_| ServerError::InternalServerError)?; + + let minithumbnail = std::fs::read(&minithumbnail_path)?; + let mut minithumbnail = std::io::Cursor::new(minithumbnail); + let minireader = + image::io::Reader::new(&mut minithumbnail).with_guessed_format()?; + let minisize = minireader + .into_dimensions() + .map_err(|_| ServerError::InternalServerError)?; + + let minithumbnail = Minithumbnail { + width: minisize.0, + height: minisize.1, + data: minithumbnail.into_inner(), + }; + + Ok((idimensions, minithumbnail)) + } else { + let image = is_webp + .then(|| { + let decoder = webp::Decoder::new(&raw); + decoder.decode().map(|i| i.to_image()) + }) + .flatten() + .or_else(|| image::load_from_memory(&raw).ok()) + .ok_or(ServerError::InternalServerError)?; + + let image_size = image.dimensions(); + let minithumbnail = image.thumbnail(64, 64); + if use_original.not() { + let encoded = is_animated.not().then(|| { + let rgba = image.into_rgba8(); + let encoder = webp::Encoder::from_rgba( + rgba.as_ref(), + rgba.width(), + rgba.height(), ); - let size = end - start; - - Result::<_, ServerError>::Ok(Attachment { - name: attachment - .name - .is_empty() - .then(|| unsafe { - String::from_utf8_unchecked(filename_raw) - }) - .unwrap_or(attachment.name), - size: attachment - .size - .eq(&0) - .then(|| size as u32) - .unwrap_or(attachment.size), - mimetype: attachment - .mimetype - .is_empty() - .then(|| unsafe { - String::from_utf8_unchecked(mimetype_raw) - }) - .unwrap_or(attachment.mimetype), - ..attachment - }) - }; - match id { - FileId::Hmc(hmc) => { - // TODO: fetch file from remote host if its not local - let id = hmc.id(); - files - .files - .push(fill_file_local(attachment, id.to_string()).await?); - } - FileId::Id(id) => { - files.files.push(fill_file_local(attachment, id).await?) - } - _ => files.files.push(attachment), - } - } else { - files.files.push(attachment); + encoder.encode(100.0) + }); + let image_raw = encoded.map(|m| m.to_vec()).unwrap_or(raw); + std::fs::write(&image_path, &image_raw)?; } + + let rgba = minithumbnail.into_rgba8(); + let encoder = + webp::Encoder::from_rgba(rgba.as_ref(), rgba.width(), rgba.height()); + let encoded = encoder.encode(100.0).to_vec(); + + std::fs::write(&minithumbnail_path, &encoded)?; + + Ok(( + image_size, + Minithumbnail { + width: rgba.width(), + height: rgba.height(), + data: encoded, + }, + )) } - content::Content::AttachmentMessage(files) - } - content::Content::EmbedMessage(embed) => { - if embed.embeds.is_empty() { - bail!(ServerError::MessageContentCantBeEmpty); - } - content::Content::EmbedMessage(embed) - } - MsgContent::InviteAccepted(_) - | MsgContent::InviteRejected(_) - | MsgContent::RoomUpgradedToGuild(_) => { - bail!(ServerError::ContentCantBeSentByUser); - } - }; - Content { - content: Some(content), + }; + + let ((width, height), minithumbnail) = tokio::task::spawn_blocking(task_fn) + .await + .map_err(|_| ServerError::InternalServerError)??; + + let info = attachment::Info::Image(ImageInfo { + width, + height, + minithumbnail: Some(minithumbnail), + caption, + }); + (id, info) } - } else { + }; + + Ok((id, Some(info))) + } + + pub async fn process_attachment( + &self, + deps: &Dependencies, + send_message_request::Attachment { id, name, info }: send_message_request::Attachment, + ) -> ServerResult { + let media_root = deps.config.media.media_root.as_path(); + + let is_jpeg = is_id_jpeg(&id); + let (mut file, metadata, path) = get_file_handle(media_root, &id).await?; + let (filename_raw, mimetype_raw, file_buf) = read_bufs(&path, &mut file, is_jpeg).await?; + let (start, end) = calculate_range(&filename_raw, &mimetype_raw, &metadata, is_jpeg); + + let size = end - start; + let filename = name + .is_empty() + .then(|| unsafe { String::from_utf8_unchecked(filename_raw) }) + .unwrap_or(name); + let mimetype = unsafe { String::from_utf8_unchecked(mimetype_raw) }; + + let (id, info) = self + .process_attachment_info(deps, info, id, size, &mimetype, file_buf) + .await?; + + Ok(Attachment { + id, + name: filename, + mimetype, + size: size as u32, + info, + }) + } + + pub async fn process_message_content( + &self, + deps: &Dependencies, + content: Option, + ) -> ServerResult { + let Some(content) = content else { bail!(ServerError::MessageContentCantBeEmpty); }; + let is_text_empty = content.text.is_empty(); + let is_embeds_empty = content.embeds.is_empty(); + let is_attachments_empty = content.attachments.is_empty(); + + // check if message content is empty + if is_attachments_empty && is_embeds_empty && is_text_empty { + bail!(ServerError::MessageContentCantBeEmpty); + } + + let mut attachments = Vec::with_capacity(content.attachments.len()); + for attachment in content.attachments { + attachments.push(self.process_attachment(deps, attachment).await?); + } + + let content = Content { + text: content.text, + text_formats: content.text_formats, + embeds: content.embeds, + attachments, + extra: None, + }; + Ok(content) } @@ -1802,20 +1746,23 @@ impl ChatTree { &self, guild_id: u64, channel_id: u64, - content: content::Content, + content: Content, ) -> ServerResult<(u64, HarmonyMessage)> { - let request = SendMessageRequest::default() - .with_guild_id(guild_id) - .with_channel_id(channel_id) - .with_content(Content { - content: Some(content), - }) - .with_overrides(Overrides { - username: Some("System".to_string()), - reason: Some(overrides::Reason::SystemMessage(Empty {})), - avatar: None, - }); - self.send_message_logic(0, request).await + let overrides = Overrides { + username: Some("System".to_string()), + reason: Some(overrides::Reason::SystemMessage(Empty {})), + avatar: None, + }; + self.send_message_logic( + 0, + guild_id, + channel_id, + content, + Some(overrides), + None, + None, + ) + .await } pub async fn update_reaction( diff --git a/src/impls/chat/permissions/get_permissions.rs b/src/impls/chat/permissions/get_permissions.rs index 3e73419..81f33a6 100644 --- a/src/impls/chat/permissions/get_permissions.rs +++ b/src/impls/chat/permissions/get_permissions.rs @@ -1,3 +1,7 @@ +use std::collections::HashMap; + +use harmony_rust_sdk::api::chat::get_permissions_response::Permissions; + use super::*; pub async fn handler( @@ -8,32 +12,51 @@ pub async fn handler( let GetPermissionsRequest { guild_id, - channel_id, + channel_ids, role_id, } = request.into_message().await?; let chat_tree = &svc.deps.chat_tree; + let get_perms = move |channel_id| async move { + let perms = chat_tree + .get_permissions_logic(guild_id, channel_id, role_id) + .await? + .into_iter() + .map(|(m, ok)| Permission { + matches: m.into(), + ok, + }) + .collect::>(); + ServerResult::Ok(Permissions::new(perms)) + }; + let check_perms = move |channel_id| async move { + chat_tree + .check_perms( + guild_id, + channel_id, + user_id, + "permissions.manage.get", + false, + ) + .await + }; chat_tree.check_guild_user(guild_id, user_id).await?; - chat_tree - .check_perms( - guild_id, - channel_id, - user_id, - "permissions.manage.get", - false, - ) - .await?; - - let perms = chat_tree - .get_permissions_logic(guild_id, channel_id, role_id) - .await? - .into_iter() - .map(|(m, ok)| Permission { - matches: m.into(), - ok, - }) - .collect(); - - Ok((GetPermissionsResponse { perms }).into_response()) + check_perms(None).await?; + for channel_id in channel_ids.iter().copied() { + check_perms(Some(channel_id)).await?; + } + + let guild_perms = get_perms(None).await?; + let mut channel_perms = HashMap::with_capacity(channel_ids.len()); + for channel_id in channel_ids { + let chan_perms = get_perms(Some(channel_id)).await?; + channel_perms.insert(channel_id, chan_perms); + } + + Ok((GetPermissionsResponse { + guild_perms: Some(guild_perms), + channel_perms, + }) + .into_response()) } diff --git a/src/impls/chat/permissions/get_user_roles.rs b/src/impls/chat/permissions/get_user_roles.rs index fcd1f6a..aad55a4 100644 --- a/src/impls/chat/permissions/get_user_roles.rs +++ b/src/impls/chat/permissions/get_user_roles.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use super::*; pub async fn handler( @@ -8,23 +10,40 @@ pub async fn handler( let GetUserRolesRequest { guild_id, - user_id: user_to_fetch, + user_ids: users_to_fetch, } = request.into_message().await?; let chat_tree = &svc.deps.chat_tree; + let users_to_fetch = users_to_fetch + .is_empty() + .then(|| vec![user_id]) + .unwrap_or(users_to_fetch); + chat_tree.check_guild_user(guild_id, user_id).await?; - chat_tree.is_user_in_guild(guild_id, user_to_fetch).await?; - let fetch_user = (user_to_fetch == 0) - .then(|| user_id) - .unwrap_or(user_to_fetch); - if fetch_user != user_id { + let mut fetch_other_user = false; + for user_to_fetch in users_to_fetch.iter().copied() { + if user_to_fetch == user_id { + fetch_other_user = true; + } + chat_tree.is_user_in_guild(guild_id, user_to_fetch).await?; + } + if fetch_other_user { chat_tree .check_perms(guild_id, None, user_id, "roles.user.get", false) .await?; } - let roles = chat_tree.get_user_roles_logic(guild_id, fetch_user).await?; + let mut user_roles = HashMap::with_capacity(users_to_fetch.len()); + for user_to_fetch in users_to_fetch { + let roles = chat_tree + .get_user_roles_logic(guild_id, user_to_fetch) + .await?; + user_roles.insert( + user_to_fetch, + get_user_roles_response::UserRoles::new(roles), + ); + } - Ok((GetUserRolesResponse { roles }).into_response()) + Ok((GetUserRolesResponse::new(user_roles)).into_response()) } diff --git a/src/impls/chat/permissions/query_has_permission.rs b/src/impls/chat/permissions/has_permission.rs similarity index 60% rename from src/impls/chat/permissions/query_has_permission.rs rename to src/impls/chat/permissions/has_permission.rs index 0d96917..78e8a25 100644 --- a/src/impls/chat/permissions/query_has_permission.rs +++ b/src/impls/chat/permissions/has_permission.rs @@ -2,14 +2,14 @@ use super::*; pub async fn handler( svc: &ChatServer, - request: Request, -) -> ServerResult> { + request: Request, +) -> ServerResult> { let user_id = svc.deps.auth(&request).await?; let request = request.into_message().await?; svc.deps .chat_tree - .query_has_permission_request(user_id, request) + .has_permission_request(user_id, request) .await .map(IntoResponse::into_response) } diff --git a/src/impls/chat/permissions/mod.rs b/src/impls/chat/permissions/mod.rs index 0b5c09f..c9866e5 100644 --- a/src/impls/chat/permissions/mod.rs +++ b/src/impls/chat/permissions/mod.rs @@ -7,8 +7,8 @@ pub mod get_permissions; pub mod get_user_roles; pub mod give_up_ownership; pub mod grant_ownership; +pub mod has_permission; pub mod manage_user_roles; pub mod modify_guild_role; pub mod move_role; -pub mod query_has_permission; pub mod set_permissions; diff --git a/src/impls/emote/add_emote_to_pack.rs b/src/impls/emote/add_emote_to_pack.rs index 4a0a122..e739c86 100644 --- a/src/impls/emote/add_emote_to_pack.rs +++ b/src/impls/emote/add_emote_to_pack.rs @@ -6,35 +6,39 @@ pub async fn handler( ) -> ServerResult> { let user_id = svc.deps.auth(&request).await?; - let AddEmoteToPackRequest { pack_id, emote } = request.into_message().await?; - - if let Some(emote) = emote { - svc.deps - .emote_tree - .check_if_emote_pack_owner(pack_id, user_id) - .await?; - - let emote_key = make_emote_pack_emote_key(pack_id, &emote.name); - let data = rkyv_ser(&emote); - - svc.deps.emote_tree.insert(emote_key, data).await?; - - let equipped_users = svc - .deps - .emote_tree - .calculate_users_pack_equipped(pack_id) - .await?; - svc.send_event_through_chan( - EventSub::Homeserver, - stream_event::Event::EmotePackEmotesUpdated(EmotePackEmotesUpdated { - pack_id, - added_emotes: vec![emote], - deleted_emotes: Vec::new(), - }), - None, - EventContext::new(equipped_users), - ); - } + let AddEmoteToPackRequest { + pack_id, + image_id, + name, + } = request.into_message().await?; + + svc.deps + .emote_tree + .check_if_emote_pack_owner(pack_id, user_id) + .await?; + + let emote = Emote::new(image_id, name); + + let emote_key = make_emote_pack_emote_key(pack_id, &emote.name); + let data = rkyv_ser(&emote); + + svc.deps.emote_tree.insert(emote_key, data).await?; + + let equipped_users = svc + .deps + .emote_tree + .calculate_users_pack_equipped(pack_id) + .await?; + svc.send_event_through_chan( + EventSub::Homeserver, + stream_event::Event::EmotePackEmotesUpdated(EmotePackEmotesUpdated { + pack_id, + added_emotes: vec![emote], + deleted_emotes: Vec::new(), + }), + None, + EventContext::new(equipped_users), + ); Ok((AddEmoteToPackResponse {}).into_response()) } diff --git a/src/impls/emote/get_emote_pack_emotes.rs b/src/impls/emote/get_emote_pack_emotes.rs index e3921f7..4977e21 100644 --- a/src/impls/emote/get_emote_pack_emotes.rs +++ b/src/impls/emote/get_emote_pack_emotes.rs @@ -1,3 +1,7 @@ +use std::ops::Not; + +use harmony_rust_sdk::api::emote::get_emote_pack_emotes_response::EmotePackEmotes; + use super::*; pub async fn handler( @@ -6,27 +10,32 @@ pub async fn handler( ) -> ServerResult> { svc.deps.auth(&request).await?; - let GetEmotePackEmotesRequest { pack_id } = request.into_message().await?; + let GetEmotePackEmotesRequest { pack_id: pack_ids } = request.into_message().await?; + + let mut pack_emotes = HashMap::with_capacity(pack_ids.len()); + for pack_id in pack_ids { + let pack_key = make_emote_pack_key(pack_id); + + if svc.deps.emote_tree.contains_key(pack_key).await?.not() { + bail!(ServerError::EmotePackNotFound); + } - let pack_key = make_emote_pack_key(pack_id); + let emotes = svc + .deps + .emote_tree + .inner + .scan_prefix(&pack_key) + .await + .try_fold(Vec::new(), |mut all, res| { + let (key, value) = res.map_err(ServerError::from)?; + if key.len() > pack_key.len() { + all.push(db::deser_emote(value)); + } + ServerResult::Ok(all) + })?; - if svc.deps.emote_tree.get(pack_key).await?.is_none() { - return Err(ServerError::EmotePackNotFound.into()); + pack_emotes.insert(pack_id, EmotePackEmotes::new(emotes)); } - let emotes = svc - .deps - .emote_tree - .inner - .scan_prefix(&pack_key) - .await - .try_fold(Vec::new(), |mut all, res| { - let (key, value) = res.map_err(ServerError::from)?; - if key.len() > pack_key.len() { - all.push(db::deser_emote(value)); - } - ServerResult::Ok(all) - })?; - - Ok((GetEmotePackEmotesResponse { emotes }).into_response()) + Ok((GetEmotePackEmotesResponse::new(pack_emotes)).into_response()) } diff --git a/src/impls/mediaproxy/can_instant_view.rs b/src/impls/mediaproxy/can_instant_view.rs index c08492a..d8695b0 100644 --- a/src/impls/mediaproxy/can_instant_view.rs +++ b/src/impls/mediaproxy/can_instant_view.rs @@ -6,28 +6,14 @@ pub async fn handler( ) -> ServerResult> { svc.deps.auth(&request).await?; - let CanInstantViewRequest { url } = request.into_message().await?; + let CanInstantViewRequest { url: urls } = request.into_message().await?; - if let Some(val) = get_from_cache(&url) { - return Ok((CanInstantViewResponse { - can_instant_view: matches!(val.value, Metadata::Site(_)), - }) - .into_response()); + let mut can_instant_view = HashMap::with_capacity(urls.len()); + for url in urls { + let metadata = svc.fetch_metadata(url.clone()).await?; + let ok = matches!(metadata, Metadata::Site(_)); + can_instant_view.insert(url, ok); } - let response = svc - .http - .get(url) - .send() - .await - .map_err(ServerError::FailedToFetchLink)? - .error_for_status() - .map_err(ServerError::FailedToFetchLink)?; - - let ok = get_mimetype(response.headers()).eq("text/html"); - - Ok((CanInstantViewResponse { - can_instant_view: ok, - }) - .into_response()) + Ok(CanInstantViewResponse::new(can_instant_view).into_response()) } diff --git a/src/impls/mediaproxy/fetch_link_metadata.rs b/src/impls/mediaproxy/fetch_link_metadata.rs index 3aa3715..14a7136 100644 --- a/src/impls/mediaproxy/fetch_link_metadata.rs +++ b/src/impls/mediaproxy/fetch_link_metadata.rs @@ -6,9 +6,14 @@ pub async fn handler( ) -> ServerResult> { svc.deps.auth(&request).await?; - let FetchLinkMetadataRequest { url } = request.into_message().await?; + let FetchLinkMetadataRequest { url: urls } = request.into_message().await?; - let data = svc.fetch_metadata(url).await?.into(); + let mut data = HashMap::with_capacity(urls.len()); + for url in urls { + let metadata = svc.fetch_metadata(url.clone()).await?.into(); + data.insert(url, metadata); + } - Ok((FetchLinkMetadataResponse { data: Some(data) }).into_response()) + // TODO: return fetch errors + Ok(FetchLinkMetadataResponse::new(data, HashMap::new()).into_response()) } diff --git a/src/impls/mediaproxy/mod.rs b/src/impls/mediaproxy/mod.rs index 73a177b..18a718b 100644 --- a/src/impls/mediaproxy/mod.rs +++ b/src/impls/mediaproxy/mod.rs @@ -1,4 +1,7 @@ -use crate::api::mediaproxy::{fetch_link_metadata_response::Data, *}; +use crate::api::mediaproxy::{ + fetch_link_metadata_response::{metadata::Data, Metadata as HarmonyMetadata}, + *, +}; use ahash::RandomState; use dashmap::{mapref::one::Ref, DashMap}; use reqwest::Client as HttpClient; @@ -17,12 +20,15 @@ fn site_metadata_from_html(html: &HTML) -> SiteMetadata { page_title: html.title.clone().unwrap_or_default(), description: html.description.clone().unwrap_or_default(), url: html.url.clone().unwrap_or_default(), - image: html + thumbnail: html .opengraph .images - .last() - .map(|og| og.url.clone()) - .unwrap_or_default(), + .iter() + .map(|img| site_metadata::ThumbnailImage { + url: img.url.clone(), + ..Default::default() + }) + .collect(), ..Default::default() } } @@ -47,13 +53,20 @@ impl From for Data { size, } => Data::IsMedia(MediaMetadata { mimetype: mimetype.into(), - filename: filename.into(), + name: filename.into(), size, + ..Default::default() }), } } } +impl From for HarmonyMetadata { + fn from(metadata: Metadata) -> Self { + HarmonyMetadata::new(Data::from(metadata)) + } +} + struct TimedCacheValue { value: T, since: Instant, diff --git a/src/impls/mod.rs b/src/impls/mod.rs index ac5ee3b..263077a 100644 --- a/src/impls/mod.rs +++ b/src/impls/mod.rs @@ -1,7 +1,6 @@ pub mod admin_action; pub mod against; pub mod auth; -pub mod batch; pub mod chat; pub mod emote; pub mod mediaproxy; @@ -34,7 +33,7 @@ use self::{ }; pub mod prelude { - pub use std::{convert::TryInto, mem::size_of}; + pub use std::{collections::HashMap, convert::TryInto, mem::size_of}; pub use crate::{ db::{self, deser_id, rkyv_arch, rkyv_ser, Batch, Db, DbResult, Tree}, @@ -156,13 +155,11 @@ pub fn setup_server( log_level: tracing::Level, ) -> (impl MakeRoutes, RestServiceLayer) { use self::{ - auth::AuthServer, batch::BatchServer, chat::ChatServer, emote::EmoteServer, - mediaproxy::MediaproxyServer, profile::ProfileServer, sync::SyncServer, + auth::AuthServer, chat::ChatServer, emote::EmoteServer, mediaproxy::MediaproxyServer, + profile::ProfileServer, sync::SyncServer, }; use crate::api::{ - auth::auth_service_server::AuthServiceServer, - batch::batch_service_server::BatchServiceServer, - chat::chat_service_server::ChatServiceServer, + auth::auth_service_server::AuthServiceServer, chat::chat_service_server::ChatServiceServer, emote::emote_service_server::EmoteServiceServer, mediaproxy::media_proxy_service_server::MediaProxyServiceServer, profile::profile_service_server::ProfileServiceServer, @@ -188,18 +185,8 @@ pub fn setup_server( #[cfg(feature = "voice")] let voice = crate::api::voice::voice_service_server::VoiceServiceServer::new(voice_server); - let batchable_services = { - let profile = ProfileServiceServer::new(profile_server.batch()); - let chat = ChatServiceServer::new(chat_server.batch()); - let mediaproxy = MediaProxyServiceServer::new(mediaproxy_server.batch()); - combine_services!(profile, chat, mediaproxy) - }; - let rest = RestServiceLayer::new(deps.clone()); - let batch_server = BatchServer::new(deps, batchable_services); - let batch = BatchServiceServer::new(batch_server); - let server = combine_services!( profile, emote, @@ -208,8 +195,7 @@ pub fn setup_server( mediaproxy, sync, #[cfg(feature = "voice")] - voice, - batch + voice ); (server, rest) diff --git a/src/impls/profile/get_profile.rs b/src/impls/profile/get_profile.rs index d43f187..706962f 100644 --- a/src/impls/profile/get_profile.rs +++ b/src/impls/profile/get_profile.rs @@ -6,13 +6,13 @@ pub async fn handler( ) -> ServerResult> { svc.deps.auth(&request).await?; - let GetProfileRequest { user_id } = request.into_message().await?; + let GetProfileRequest { user_id: user_ids } = request.into_message().await?; - svc.deps - .profile_tree - .get_profile_logic(user_id) - .await - .map(|p| GetProfileResponse { profile: Some(p) }) - .map(IntoResponse::into_response) - .map_err(Into::into) + let mut profiles = HashMap::with_capacity(user_ids.len()); + for user_id in user_ids { + let profile = svc.deps.profile_tree.get_profile_logic(user_id).await?; + profiles.insert(user_id, profile); + } + + Ok(GetProfileResponse::new(profiles).into_response()) } diff --git a/src/impls/profile/mod.rs b/src/impls/profile/mod.rs index ea2d08b..713cfde 100644 --- a/src/impls/profile/mod.rs +++ b/src/impls/profile/mod.rs @@ -79,7 +79,6 @@ impl ProfileTree { new_user_name: Option, new_user_avatar: Option, new_user_status: Option, - new_is_bot: Option, ) -> ServerResult<()> { let key = make_user_profile_key(user_id); @@ -101,9 +100,6 @@ impl ProfileTree { if let Some(new_status) = new_user_status { profile.user_status = new_status; } - if let Some(new_is_bot) = new_is_bot { - profile.is_bot = new_is_bot; - } let buf = rkyv_ser(&profile); self.insert(key, buf).await?; diff --git a/src/impls/profile/update_profile.rs b/src/impls/profile/update_profile.rs index 516aba4..53c9c5d 100644 --- a/src/impls/profile/update_profile.rs +++ b/src/impls/profile/update_profile.rs @@ -11,7 +11,6 @@ pub async fn handler( new_user_name, new_user_avatar, new_user_status, - new_is_bot, } = request.into_message().await?; if let Some(username) = new_user_name.as_deref() { @@ -27,7 +26,6 @@ pub async fn handler( new_user_name.clone(), new_user_avatar.clone(), new_user_status, - new_is_bot, ) .await?; @@ -38,7 +36,6 @@ pub async fn handler( new_username: new_user_name, new_avatar: new_user_avatar, new_status: new_user_status, - new_is_bot, new_account_kind: None, }), None, diff --git a/src/main.rs b/src/main.rs index 229a670..ea2dbfd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ use hrpc::{ }; use hyper::header; use scherzo::{ + api::chat::Content, config::Config, db::{ migration::{apply_migrations, get_db_version}, @@ -329,7 +330,7 @@ async fn setup_admin_guild(deps: &Dependencies) { "Admin".to_string(), None, None, - guild_kind::Kind::new_normal(guild_kind::Normal::new()), + guild_kind::Kind::Normal(guild_kind::Normal::new()), ) .await .unwrap(); @@ -366,12 +367,7 @@ async fn setup_admin_guild(deps: &Dependencies) { .send_with_system( guild_id, cmd_id, - content::Content::TextMessage(content::TextContent { - content: Some(FormattedText::new( - admin_action::HELP_TEXT.to_string(), - Vec::new(), - )), - }), + Content::default().with_text(admin_action::HELP_TEXT), ) .await .unwrap(); From 4c5795029e1ae50c549df955a68fbd4dab30aeb1 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 21 Feb 2022 21:10:05 +0300 Subject: [PATCH 03/62] refactor: fix some clippy lints --- src/db/migration/add_account_kind.rs | 2 -- src/db/mod.rs | 1 - src/impls/chat/mod.rs | 12 ++++-------- src/impls/mod.rs | 8 ++++---- src/impls/rest/mod.rs | 2 +- src/impls/voice/stream_message.rs | 5 +---- src/main.rs | 2 +- 7 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/db/migration/add_account_kind.rs b/src/db/migration/add_account_kind.rs index 5db99b9..943ab32 100644 --- a/src/db/migration/add_account_kind.rs +++ b/src/db/migration/add_account_kind.rs @@ -1,5 +1,3 @@ -use std::fmt::Display; - use super::*; use db::{ diff --git a/src/db/mod.rs b/src/db/mod.rs index f383a84..6360904 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -31,7 +31,6 @@ use std::{ error::Error as StdError, fmt::{self, Display, Formatter}, mem::size_of, - pin::Pin, }; use crate::{config::DbConfig, utils::evec::EVec, ServerError, ServerResult}; diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 37fb904..ad70395 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -1,17 +1,13 @@ -use std::{ - collections::HashSet, io::BufReader, iter, lazy::SyncOnceCell, mem::size_of, ops::Not, - path::Path, str::FromStr, -}; +use std::{collections::HashSet, io::BufReader, iter, lazy::SyncOnceCell, mem::size_of, ops::Not}; use crate::api::{ chat::{ get_channel_messages_request::Direction, overrides::Reason, permission::has_permission, - stream_event, FormattedText, Message as HarmonyMessage, *, + stream_event, Message as HarmonyMessage, *, }, emote::Emote, exports::hrpc::{server::socket::Socket, Request}, harmonytypes::{item_position, Empty, ItemPosition, Metadata}, - rest::FileId, sync::{ event::{ Kind as DispatchKind, UserAddedToGuild as SyncUserAddedToGuild, @@ -19,7 +15,6 @@ use crate::api::{ }, Event as DispatchEvent, }, - Hmc, }; use image::GenericImageView; use rand::{Rng, SeedableRng}; @@ -37,7 +32,7 @@ use crate::{ impls::{ get_time_millisecs, prelude::*, - rest::download::{calculate_range, get_file_full, get_file_handle, is_id_jpeg, read_bufs}, + rest::download::{calculate_range, get_file_handle, is_id_jpeg, read_bufs}, sync::EventDispatch, }, }; @@ -1494,6 +1489,7 @@ impl ChatTree { Ok(id) } + #[allow(clippy::too_many_arguments)] pub async fn send_message_logic( &self, guild_id: u64, diff --git a/src/impls/mod.rs b/src/impls/mod.rs index 263077a..37850b0 100644 --- a/src/impls/mod.rs +++ b/src/impls/mod.rs @@ -176,16 +176,16 @@ pub fn setup_server( #[cfg(feature = "voice")] let voice_server = self::voice::VoiceServer::new(deps.clone(), log_level); - let profile = ProfileServiceServer::new(profile_server.clone()); + let profile = ProfileServiceServer::new(profile_server); let emote = EmoteServiceServer::new(emote_server); let auth = AuthServiceServer::new(auth_server); - let chat = ChatServiceServer::new(chat_server.clone()); - let mediaproxy = MediaProxyServiceServer::new(mediaproxy_server.clone()); + let chat = ChatServiceServer::new(chat_server); + let mediaproxy = MediaProxyServiceServer::new(mediaproxy_server); let sync = PostboxServiceServer::new(sync_server); #[cfg(feature = "voice")] let voice = crate::api::voice::voice_service_server::VoiceServiceServer::new(voice_server); - let rest = RestServiceLayer::new(deps.clone()); + let rest = RestServiceLayer::new(deps); let server = combine_services!( profile, diff --git a/src/impls/rest/mod.rs b/src/impls/rest/mod.rs index faf9e58..122f01b 100644 --- a/src/impls/rest/mod.rs +++ b/src/impls/rest/mod.rs @@ -31,7 +31,7 @@ use crate::api::{ rest::{extract_file_info_from_download_response, FileId}, }; use hrpc::common::future::Ready; -use http::{header, HeaderValue, Method, StatusCode, Uri}; +use http::{header, HeaderValue, Method, StatusCode}; use hyper::Body; use pin_project::pin_project; use tokio::{ diff --git a/src/impls/voice/stream_message.rs b/src/impls/voice/stream_message.rs index 7921403..6ab1e7a 100644 --- a/src/impls/voice/stream_message.rs +++ b/src/impls/voice/stream_message.rs @@ -242,10 +242,7 @@ pub async fn handler( Event::UserLeft(user_left) => ResponseMessage::UserLeft(user_left), }; - bail_result!( - tx.send_message(StreamMessageResponse::new(Some(message))) - .await - ); + bail_result!(tx.send_message(StreamMessageResponse::new(message)).await); } ServerResult::Ok(()) }; diff --git a/src/main.rs b/src/main.rs index ea2dbfd..6bd7df6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use std::{ }; use harmony_rust_sdk::api::{ - chat::{content, guild_kind, ChannelKind, FormattedText, Permission}, + chat::{guild_kind, ChannelKind, Permission}, exports::hrpc::server::transport::{http::Hyper, Transport}, }; use hrpc::{ From 2f3d9f0d35ca11469bb73e7676dbccbb12d3250c Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 21 Feb 2022 22:52:32 +0300 Subject: [PATCH 04/62] refactor: introduce MediaStore, fix subtle Cursor usage bug in image process code --- src/impls/chat/mod.rs | 235 ++++++++++++++++++------------------- src/impls/media.rs | 166 ++++++++++++++++++++++++++ src/impls/mod.rs | 7 +- src/impls/rest/download.rs | 165 ++++++-------------------- src/impls/rest/mod.rs | 19 +-- src/impls/rest/upload.rs | 73 +++--------- 6 files changed, 341 insertions(+), 324 deletions(-) create mode 100644 src/impls/media.rs diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index ad70395..901490f 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -21,7 +21,6 @@ use rand::{Rng, SeedableRng}; use scherzo_derive::*; use smol_str::SmolStr; use tokio::{ - io::AsyncReadExt, sync::{broadcast::Sender as BroadcastSend, mpsc::UnboundedSender}, task::JoinHandle, }; @@ -29,12 +28,7 @@ use triomphe::Arc; use crate::{ db::{self, chat::*, rkyv_ser, Batch, Db, DbResult}, - impls::{ - get_time_millisecs, - prelude::*, - rest::download::{calculate_range, get_file_handle, is_id_jpeg, read_bufs}, - sync::EventDispatch, - }, + impls::{get_time_secs, prelude::*, sync::EventDispatch}, }; use channels::*; @@ -44,6 +38,8 @@ use messages::*; use moderation::*; use permissions::*; +use super::media::FileHandle; + pub mod channels; pub mod guilds; pub mod invites; @@ -1544,122 +1540,128 @@ impl ChatTree { Ok(()) } - pub async fn process_attachment_info( + pub async fn process_image_info( &self, deps: &Dependencies, - info: Option, + info: send_message_request::ImageInfo, id: String, - size: u64, - mimetype: &str, - mut filebuf: tokio::io::BufReader<&mut tokio::fs::File>, - ) -> Result<(String, Option), ServerError> { - use send_message_request::{attachment::Info, ImageInfo as RequestImageInfo}; + file_handle: FileHandle, + ) -> Result<(String, ImageInfo), ServerError> { + let send_message_request::ImageInfo { + caption, + use_original, + } = info; let media_root = &deps.config.media.media_root; - let Some(info) = info else { - return Ok((id, None)); + let is_animated = file_handle.mime == "image/gif"; + let is_webp = file_handle.mime == "image/webp"; + + let raw = file_handle.read().await?; + + // TODO: improve this code + let minithumbnail_id = format!("{}_jpegthumb", id); + let minithumbnail_path = media_root.join(&minithumbnail_id); + let id = use_original + .not() + .then(|| format!("{}_jpeg", id)) + .unwrap_or(id); + let image_path = media_root.join(&id); + + let task_fn = move || -> Result<_, ServerError> { + if image_path.exists() && minithumbnail_path.exists() { + let ifile = std::fs::File::open(&image_path)?; + let ifile = BufReader::new(ifile); + let ireader = image::io::Reader::new(ifile).with_guessed_format()?; + let idimensions = ireader + .into_dimensions() + .map_err(|_| ServerError::InternalServerError)?; + + let minireader = + image::io::Reader::open(&minithumbnail_path)?.with_guessed_format()?; + let minisize = minireader + .into_dimensions() + .map_err(|_| ServerError::InternalServerError)?; + + let minithumbnail = Minithumbnail { + width: minisize.0, + height: minisize.1, + data: std::fs::read(&minithumbnail_path)?, + }; + + Ok((idimensions, minithumbnail)) + } else { + let image = is_webp + .then(|| { + let decoder = webp::Decoder::new(&raw); + decoder.decode().map(|i| i.to_image()) + }) + .flatten() + .or_else(|| image::load_from_memory(&raw).ok()) + .ok_or(ServerError::InternalServerError)?; + + let image_size = image.dimensions(); + let minithumbnail = image.thumbnail(64, 64); + if use_original.not() { + let encoded = is_animated.not().then(|| { + let rgba = image.into_rgba8(); + let encoder = + webp::Encoder::from_rgba(rgba.as_ref(), rgba.width(), rgba.height()); + encoder.encode(100.0) + }); + let image_raw = encoded.map(|m| m.to_vec()).unwrap_or(raw); + std::fs::write(&image_path, &image_raw)?; + } + + let rgba = minithumbnail.into_rgba8(); + let encoder = webp::Encoder::from_rgba(rgba.as_ref(), rgba.width(), rgba.height()); + let encoded = encoder.encode(100.0).to_vec(); + + std::fs::write(&minithumbnail_path, &encoded)?; + + Ok(( + image_size, + Minithumbnail { + width: rgba.width(), + height: rgba.height(), + data: encoded, + }, + )) + } }; - let (id, info) = match info { - Info::Image(RequestImageInfo { - caption, - use_original, - }) => { - let mut raw = Vec::with_capacity(size as usize); - filebuf.read_to_end(&mut raw).await?; - - let is_animated = mimetype == "image/gif"; - let is_webp = mimetype == "image/webp"; - - // TODO: improve this code - let minithumbnail_id = format!("{}_jpegthumb", id); - let minithumbnail_path = media_root.join(&minithumbnail_id); - let id = use_original - .not() - .then(|| format!("{}_jpeg", id)) - .unwrap_or(id); - let image_path = media_root.join(&id); - - let task_fn = move || -> Result<_, ServerError> { - if image_path.exists() && minithumbnail_path.exists() { - let ifile = std::fs::File::open(&image_path)?; - let ifile = BufReader::new(ifile); - let ireader = image::io::Reader::new(ifile).with_guessed_format()?; - let idimensions = ireader - .into_dimensions() - .map_err(|_| ServerError::InternalServerError)?; - - let minithumbnail = std::fs::read(&minithumbnail_path)?; - let mut minithumbnail = std::io::Cursor::new(minithumbnail); - let minireader = - image::io::Reader::new(&mut minithumbnail).with_guessed_format()?; - let minisize = minireader - .into_dimensions() - .map_err(|_| ServerError::InternalServerError)?; - - let minithumbnail = Minithumbnail { - width: minisize.0, - height: minisize.1, - data: minithumbnail.into_inner(), - }; + let ((width, height), minithumbnail) = tokio::task::spawn_blocking(task_fn) + .await + .map_err(|_| ServerError::InternalServerError)??; - Ok((idimensions, minithumbnail)) - } else { - let image = is_webp - .then(|| { - let decoder = webp::Decoder::new(&raw); - decoder.decode().map(|i| i.to_image()) - }) - .flatten() - .or_else(|| image::load_from_memory(&raw).ok()) - .ok_or(ServerError::InternalServerError)?; - - let image_size = image.dimensions(); - let minithumbnail = image.thumbnail(64, 64); - if use_original.not() { - let encoded = is_animated.not().then(|| { - let rgba = image.into_rgba8(); - let encoder = webp::Encoder::from_rgba( - rgba.as_ref(), - rgba.width(), - rgba.height(), - ); - encoder.encode(100.0) - }); - let image_raw = encoded.map(|m| m.to_vec()).unwrap_or(raw); - std::fs::write(&image_path, &image_raw)?; - } + let info = ImageInfo { + width, + height, + minithumbnail: Some(minithumbnail), + caption, + }; - let rgba = minithumbnail.into_rgba8(); - let encoder = - webp::Encoder::from_rgba(rgba.as_ref(), rgba.width(), rgba.height()); - let encoded = encoder.encode(100.0).to_vec(); + Ok((id, info)) + } - std::fs::write(&minithumbnail_path, &encoded)?; + pub async fn process_attachment_info( + &self, + deps: &Dependencies, + info: Option, + id: String, + file_handle: FileHandle, + ) -> Result<(String, Option), ServerError> { + use send_message_request::attachment::Info; - Ok(( - image_size, - Minithumbnail { - width: rgba.width(), - height: rgba.height(), - data: encoded, - }, - )) - } - }; + let Some(info) = info else { + return Ok((id, None)); + }; - let ((width, height), minithumbnail) = tokio::task::spawn_blocking(task_fn) - .await - .map_err(|_| ServerError::InternalServerError)??; + let (id, info) = match info { + Info::Image(info) => { + let (id, info) = self.process_image_info(deps, info, id, file_handle).await?; - let info = attachment::Info::Image(ImageInfo { - width, - height, - minithumbnail: Some(minithumbnail), - caption, - }); - (id, info) + (id, attachment::Info::Image(info)) } }; @@ -1671,22 +1673,17 @@ impl ChatTree { deps: &Dependencies, send_message_request::Attachment { id, name, info }: send_message_request::Attachment, ) -> ServerResult { - let media_root = deps.config.media.media_root.as_path(); - - let is_jpeg = is_id_jpeg(&id); - let (mut file, metadata, path) = get_file_handle(media_root, &id).await?; - let (filename_raw, mimetype_raw, file_buf) = read_bufs(&path, &mut file, is_jpeg).await?; - let (start, end) = calculate_range(&filename_raw, &mimetype_raw, &metadata, is_jpeg); + let file_handle = deps.media.get_file(&id).await?; - let size = end - start; + let size = file_handle.size; let filename = name .is_empty() - .then(|| unsafe { String::from_utf8_unchecked(filename_raw) }) + .then(|| file_handle.name.clone()) .unwrap_or(name); - let mimetype = unsafe { String::from_utf8_unchecked(mimetype_raw) }; + let mimetype = file_handle.mime.clone(); let (id, info) = self - .process_attachment_info(deps, info, id, size, &mimetype, file_buf) + .process_attachment_info(deps, info, id, file_handle) .await?; Ok(Attachment { diff --git a/src/impls/media.rs b/src/impls/media.rs new file mode 100644 index 0000000..f3ac768 --- /dev/null +++ b/src/impls/media.rs @@ -0,0 +1,166 @@ +use std::{ + fs::Metadata, + path::{Path, PathBuf}, +}; + +use hrpc::exports::futures_util::{Stream, StreamExt}; +use prost::bytes::Bytes; +use smol_str::SmolStr; +use tokio::{ + fs::File, + io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}, +}; + +use crate::{config::MediaConfig, utils::gen_rand_inline_str, ServerError}; + +const SEPERATOR: u8 = b'\n'; + +pub struct FileHandle { + pub file: File, + pub metadata: Metadata, + pub name: String, + pub mime: String, + pub size: u64, + pub range: (u64, u64), +} + +impl FileHandle { + pub async fn read(mut self) -> Result, ServerError> { + let mut raw = Vec::with_capacity(self.size as usize); + self.file.read_to_end(&mut raw).await?; + Ok(raw) + } +} + +pub struct MediaStore { + root: PathBuf, +} + +impl MediaStore { + pub fn new(config: &MediaConfig) -> Self { + Self { + root: config.media_root.clone(), + } + } + + pub async fn write_file( + &self, + mut chunks: impl Stream> + Unpin, + name: &str, + mime: &str, + write_to: Option, + ) -> Result { + let id = gen_rand_inline_str(); + let path = write_to.unwrap_or_else(|| self.root.join(id.as_str())); + if path.exists() { + return Ok(id); + } + let first_chunk = chunks.next().await.ok_or(ServerError::MissingFiles)??; + + let file = tokio::fs::OpenOptions::default() + .append(true) + .create(true) + .open(path) + .await?; + let mut buf_writer = BufWriter::new(file); + + // Write prefix + buf_writer.write_all(name.as_bytes()).await?; + buf_writer.write_all(&[SEPERATOR]).await?; + buf_writer.write_all(mime.as_bytes()).await?; + buf_writer.write_all(&[SEPERATOR]).await?; + + // Write our first chunk + buf_writer.write_all(&first_chunk).await?; + + // flush before starting to write other chunks + buf_writer.flush().await?; + + while let Some(chunk) = chunks.next().await.transpose()? { + buf_writer.write_all(&chunk).await?; + } + + // flush everything else + buf_writer.flush().await?; + + Ok(id) + } + + pub async fn get_file(&self, id: &str) -> Result { + let is_jpeg = is_id_jpeg(id); + let (mut file, metadata, file_path) = self.get_file_handle(id).await?; + let (filename_raw, mimetype_raw, _) = read_bufs(&file_path, &mut file, is_jpeg).await?; + + let (start, end) = calculate_range(&filename_raw, &mimetype_raw, &metadata, is_jpeg); + + let mime = String::from_utf8_lossy(&mimetype_raw).into_owned(); + let name = String::from_utf8_lossy(&filename_raw).into_owned(); + + Ok(FileHandle { + file, + metadata, + mime, + name, + size: end - start, + range: (start, end), + }) + } + + async fn get_file_handle(&self, id: &str) -> Result<(File, Metadata, PathBuf), ServerError> { + let file_path = self.root.join(id); + let file = tokio::fs::File::open(&file_path).await.map_err(|err| { + if let std::io::ErrorKind::NotFound = err.kind() { + ServerError::MediaNotFound + } else { + err.into() + } + })?; + let metadata = file.metadata().await?; + Ok((file, metadata, file_path)) + } +} + +pub async fn read_bufs<'file>( + path: &Path, + file: &'file mut File, + is_jpeg: bool, +) -> Result<(Vec, Vec, BufReader<&'file mut File>), ServerError> { + if is_jpeg { + let mimetype = infer::get_from_path(path).ok().flatten().map_or_else( + || b"image/jpeg".to_vec(), + |t| t.mime_type().as_bytes().to_vec(), + ); + Ok((b"unknown".to_vec(), mimetype, BufReader::new(file))) + } else { + let mut buf_reader = BufReader::new(file); + + let mut filename_raw = Vec::with_capacity(20); + buf_reader.read_until(SEPERATOR, &mut filename_raw).await?; + filename_raw.pop(); + + let mut mimetype_raw = Vec::with_capacity(20); + buf_reader.read_until(SEPERATOR, &mut mimetype_raw).await?; + mimetype_raw.pop(); + + Ok((filename_raw, mimetype_raw, buf_reader)) + } +} + +pub fn calculate_range( + filename_raw: &[u8], + mimetype_raw: &[u8], + metadata: &Metadata, + is_jpeg: bool, +) -> (u64, u64) { + // + 2 is because we need to factor in the 2 b'\n' seperators + let start = is_jpeg + .then(|| 0) + .unwrap_or((filename_raw.len() + mimetype_raw.len()) as u64 + 2); + let end = metadata.len(); + + (start, end) +} + +pub fn is_id_jpeg(id: &str) -> bool { + id.ends_with("_jpeg") || id.ends_with("_jpegthumb") +} diff --git a/src/impls/mod.rs b/src/impls/mod.rs index 37850b0..7ba3e0c 100644 --- a/src/impls/mod.rs +++ b/src/impls/mod.rs @@ -3,6 +3,7 @@ pub mod against; pub mod auth; pub mod chat; pub mod emote; +pub mod media; pub mod mediaproxy; pub mod profile; pub mod rest; @@ -28,8 +29,8 @@ use tokio::sync::{broadcast, mpsc}; use crate::{config::Config, key, SharedConfig, SharedConfigData}; use self::{ - auth::AuthTree, chat::ChatTree, emote::EmoteTree, profile::ProfileTree, rest::RestServiceLayer, - sync::EventDispatch, + auth::AuthTree, chat::ChatTree, emote::EmoteTree, media::MediaStore, profile::ProfileTree, + rest::RestServiceLayer, sync::EventDispatch, }; pub mod prelude { @@ -78,6 +79,7 @@ pub struct Dependencies { pub key_manager: Option>, pub http: HttpClient, pub email: Option>, + pub media: MediaStore, pub config: Config, pub runtime_config: SharedConfig, @@ -138,6 +140,7 @@ impl Dependencies { } builder.build() }), + media: MediaStore::new(&config.media), runtime_config: Arc::new(Mutex::new(SharedConfigData { motd: config.motd.clone(), diff --git a/src/impls/rest/download.rs b/src/impls/rest/download.rs index c4a122a..6700cc5 100644 --- a/src/impls/rest/download.rs +++ b/src/impls/rest/download.rs @@ -1,10 +1,19 @@ -use std::{convert::Infallible, ops::Not}; - -use hrpc::{exports::futures_util::future::BoxFuture, server::transport::http::HttpResponse}; +use std::{cmp, convert::Infallible, fs::Metadata, ops::Not}; + +use hrpc::{ + exports::futures_util::{ + future::{self, BoxFuture, Either}, + ready, stream, FutureExt, Stream, StreamExt, + }, + server::transport::http::HttpResponse, +}; +use prost::bytes::BytesMut; use reqwest::Client as HttpClient; +use tokio::io::AsyncSeekExt; +use tokio_util::io::poll_read_buf; use tower::Service; -use crate::rest_error_response; +use crate::{impls::media::FileHandle, rest_error_response}; use super::*; @@ -63,7 +72,6 @@ impl Service for DownloadService { _ => return Ok(ServerError::InvalidFileId.into_rest_http_response()), }; - let media_root = deps.config.media.media_root.as_path(); let http_client = &deps.http; let host = &deps.config.host; @@ -107,8 +115,8 @@ impl Service for DownloadService { info!("Serving HMC from {}", hmc); if format!("{}:{}", hmc.server(), hmc.port()) == host.as_str() { info!("Serving local media with id {}", hmc.id()); - match get_file(media_root, hmc.id()).await { - Ok(data) => data, + match deps.media.get_file(hmc.id()).await { + Ok(handle) => file_handle_to_data(handle), Err(err) => return Ok(err.into_rest_http_response()), } } else { @@ -149,8 +157,8 @@ impl Service for DownloadService { } FileId::Id(id) => { info!("Serving local media with id {}", id); - match get_file(media_root, &id).await { - Ok(data) => data, + match deps.media.get_file(&id).await { + Ok(handle) => file_handle_to_data(handle), Err(err) => return Ok(err.into_rest_http_response()), } } @@ -180,128 +188,26 @@ pub fn handler(deps: Arc) -> RateLimit { ) } -// Safety: the `name` argument MUST ONLY contain ASCII characters. -unsafe fn disposition_header(name: &str) -> HeaderValue { - HeaderValue::from_maybe_shared_unchecked(Bytes::from( - format!("inline; filename={}", name).into_bytes(), - )) -} - -pub async fn get_file_handle( - media_root: &Path, - id: &str, -) -> Result<(File, Metadata, PathBuf), ServerError> { - let file_path = media_root.join(id); - let file = tokio::fs::File::open(&file_path).await.map_err(|err| { - if let std::io::ErrorKind::NotFound = err.kind() { - ServerError::MediaNotFound - } else { - err.into() - } - })?; - let metadata = file.metadata().await?; - Ok((file, metadata, file_path)) -} - -pub async fn read_bufs<'file>( - path: &Path, - file: &'file mut File, - is_jpeg: bool, -) -> Result<(Vec, Vec, BufReader<&'file mut File>), ServerError> { - if is_jpeg { - let mimetype = infer::get_from_path(path).ok().flatten().map_or_else( - || b"image/jpeg".to_vec(), - |t| t.mime_type().as_bytes().to_vec(), - ); - Ok((b"unknown".to_vec(), mimetype, BufReader::new(file))) - } else { - let mut buf_reader = BufReader::new(file); - - let mut filename_raw = Vec::with_capacity(20); - buf_reader.read_until(SEPERATOR, &mut filename_raw).await?; - filename_raw.pop(); - - let mut mimetype_raw = Vec::with_capacity(20); - buf_reader.read_until(SEPERATOR, &mut mimetype_raw).await?; - mimetype_raw.pop(); - - Ok((filename_raw, mimetype_raw, buf_reader)) - } +fn file_handle_to_data(handle: FileHandle) -> (HeaderValue, HeaderValue, Body, HeaderValue) { + let stream = Body::wrap_stream(file_stream( + handle.file, + optimal_buf_size(&handle.metadata), + handle.range, + )); + let disposition = unsafe { disposition_header(&handle.name) }; + let mime = unsafe { string_header(handle.mime) }; + let size = unsafe { string_header(handle.size.to_string()) }; + (disposition, mime, stream, size) } -pub async fn get_file_full( - media_root: &Path, - id: &str, -) -> Result<(String, String, Vec, u64), ServerError> { - let is_jpeg = is_id_jpeg(id); - let (mut file, metadata, file_path) = get_file_handle(media_root, id).await?; - let (filename_raw, mimetype_raw, mut buf_reader) = - read_bufs(&file_path, &mut file, is_jpeg).await?; - - let (start, end) = calculate_range(&filename_raw, &mimetype_raw, &metadata, is_jpeg); - let size = end - start; - let mut file_raw = Vec::with_capacity(size as usize); - buf_reader.read_to_end(&mut file_raw).await?; - - unsafe { - Ok(( - String::from_utf8_unchecked(filename_raw), - String::from_utf8_unchecked(mimetype_raw), - file_raw, - size, - )) - } -} - -pub fn calculate_range( - filename_raw: &[u8], - mimetype_raw: &[u8], - metadata: &Metadata, - is_jpeg: bool, -) -> (u64, u64) { - // + 2 is because we need to factor in the 2 b'\n' seperators - let start = is_jpeg - .then(|| 0) - .unwrap_or((filename_raw.len() + mimetype_raw.len()) as u64 + 2); - let end = metadata.len(); - - (start, end) -} - -pub fn is_id_jpeg(id: &str) -> bool { - id.ends_with("_jpeg") || id.ends_with("_jpegthumb") +// SAFETY: the `name` argument MUST ONLY contain ASCII characters. +unsafe fn disposition_header(name: &str) -> HeaderValue { + string_header(format!("inline; filename={}", name)) } -pub async fn get_file( - media_root: &Path, - id: &str, -) -> Result<(HeaderValue, HeaderValue, hyper::Body, HeaderValue), ServerError> { - let is_jpeg = is_id_jpeg(id); - let (mut file, metadata, file_path) = get_file_handle(media_root, id).await?; - let (filename_raw, mimetype_raw, _) = read_bufs(&file_path, &mut file, is_jpeg).await?; - - let (start, end) = calculate_range(&filename_raw, &mimetype_raw, &metadata, is_jpeg); - let mimetype: Bytes = mimetype_raw.into(); - - let disposition = unsafe { - let filename = std::str::from_utf8_unchecked(&filename_raw); - // Safety: filenames must be valid ASCII characters since we get them through only ASCII allowed structures [ref:ascii_filename_upload] - disposition_header(filename) - }; - // Safety: mimetypes must be valid ASCII chars since we get them through only ASCII allowed structures [ref:ascii_mimetype_upload] - let mimetype = unsafe { HeaderValue::from_maybe_shared_unchecked(mimetype) }; - - let buf_size = optimal_buf_size(&metadata); - Ok(( - disposition, - mimetype, - hyper::Body::wrap_stream(file_stream(file, buf_size, (start, end))), - unsafe { - HeaderValue::from_maybe_shared_unchecked(Bytes::from( - (end - start).to_string().into_bytes(), - )) - }, - )) +// SAFETY: the `string` argument MUST ONLY contain ASCII characters. +unsafe fn string_header(string: String) -> HeaderValue { + HeaderValue::from_maybe_shared_unchecked(Bytes::from(string.into_bytes())) } fn file_stream( @@ -312,8 +218,9 @@ fn file_stream( use std::io::SeekFrom; let seek = async move { - // We will always seek from a point that is non-zero - file.seek(SeekFrom::Start(start)).await?; + if start != 0 { + file.seek(SeekFrom::Start(start)).await?; + } Ok(file) }; diff --git a/src/impls/rest/mod.rs b/src/impls/rest/mod.rs index 122f01b..529dde7 100644 --- a/src/impls/rest/mod.rs +++ b/src/impls/rest/mod.rs @@ -2,15 +2,12 @@ use crate::{http, utils::http_ratelimit::RateLimit}; use self::{about::AboutService, download::DownloadService, upload::UploadService}; -use super::{gen_rand_inline_str, get_content_length, prelude::*}; +use super::{get_content_length, prelude::*}; use std::{ borrow::Cow, - cmp, convert::Infallible, - fs::Metadata, future::Future, - path::{Path, PathBuf}, pin::Pin, str::FromStr, task::{Context, Poll}, @@ -20,13 +17,10 @@ use std::{ use crate::api::{ exports::{ hrpc::{ - exports::futures_util::{ - future::{self, BoxFuture, Either}, - ready, stream, FutureExt, Stream, StreamExt, - }, + exports::futures_util::{future::BoxFuture, FutureExt}, server::transport::http::{box_body, HttpRequest, HttpResponse}, }, - prost::bytes::{Bytes, BytesMut}, + prost::bytes::Bytes, }, rest::{extract_file_info_from_download_response, FileId}, }; @@ -34,11 +28,6 @@ use hrpc::common::future::Ready; use http::{header, HeaderValue, Method, StatusCode}; use hyper::Body; use pin_project::pin_project; -use tokio::{ - fs::File, - io::{AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteExt, BufReader, BufWriter}, -}; -use tokio_util::io::poll_read_buf; use tower::{Layer, Service}; use tracing::info; @@ -46,8 +35,6 @@ pub mod about; pub mod download; pub mod upload; -const SEPERATOR: u8 = b'\n'; - type Out = Result; #[derive(Clone)] diff --git a/src/impls/rest/upload.rs b/src/impls/rest/upload.rs index 225a187..20133fa 100644 --- a/src/impls/rest/upload.rs +++ b/src/impls/rest/upload.rs @@ -1,6 +1,9 @@ use std::convert::Infallible; -use hrpc::{exports::futures_util::future::BoxFuture, server::transport::http::HttpResponse}; +use hrpc::{ + exports::futures_util::{future::BoxFuture, TryStreamExt}, + server::transport::http::HttpResponse, +}; use tower::Service; use crate::{impls::auth::get_token_from_header_map, rest_error_response}; @@ -72,13 +75,17 @@ impl Service for UploadService { match multipart.next_field().await { Ok(maybe_field) => match maybe_field { Some(field) => { - let id = - match write_file(deps.config.media.media_root.as_path(), field, None) - .await - { - Ok(id) => id, - Err(err) => return Ok(err.into_rest_http_response()), - }; + let name = field.file_name().unwrap_or("unknown").to_string(); + let mime = field + .content_type() + .map_or("application/octet-stream", |m| m.essence_str()) + .to_string(); + let chunks = field.map_err(ServerError::MultipartError); + + let id = match deps.media.write_file(chunks, &name, &mime, None).await { + Ok(id) => id, + Err(err) => return Ok(err.into_rest_http_response()), + }; Ok(http::Response::builder() .status(StatusCode::OK) @@ -96,53 +103,3 @@ impl Service for UploadService { Box::pin(fut) } } - -pub async fn write_file( - media_root: &Path, - mut part: multer::Field<'static>, - write_to: Option, -) -> Result { - let id = gen_rand_inline_str(); - let path = write_to.unwrap_or_else(|| media_root.join(id.as_str())); - if path.exists() { - return Ok(id); - } - let first_chunk = part.chunk().await?.ok_or(ServerError::MissingFiles)?; - - let file = tokio::fs::OpenOptions::default() - .append(true) - .create(true) - .open(path) - .await?; - let mut buf_writer = BufWriter::new(file); - - // [tag:ascii_filename_upload] - let name = part.file_name().unwrap_or("unknown"); - // [tag:ascii_mimetype_upload] - let content_type = part - .content_type() - .map(|m| m.essence_str()) - .or_else(|| infer::get(&first_chunk).map(|t| t.mime_type())) - .unwrap_or("application/octet-stream"); - - // Write prefix - buf_writer.write_all(name.as_bytes()).await?; - buf_writer.write_all(&[SEPERATOR]).await?; - buf_writer.write_all(content_type.as_bytes()).await?; - buf_writer.write_all(&[SEPERATOR]).await?; - - // Write our first chunk - buf_writer.write_all(&first_chunk).await?; - - // flush before starting to write other chunks - buf_writer.flush().await?; - - while let Some(chunk) = part.chunk().await? { - buf_writer.write_all(&chunk).await?; - } - - // flush everything else - buf_writer.flush().await?; - - Ok(id) -} From 0ce60ca9cd0c594e6157b629acbf982480acacd0 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 21 Feb 2022 22:57:00 +0300 Subject: [PATCH 05/62] refactor: remove unused write_to argument from write_file --- src/impls/media.rs | 3 +-- src/impls/rest/upload.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/impls/media.rs b/src/impls/media.rs index f3ac768..83019e1 100644 --- a/src/impls/media.rs +++ b/src/impls/media.rs @@ -48,10 +48,9 @@ impl MediaStore { mut chunks: impl Stream> + Unpin, name: &str, mime: &str, - write_to: Option, ) -> Result { let id = gen_rand_inline_str(); - let path = write_to.unwrap_or_else(|| self.root.join(id.as_str())); + let path = self.root.join(id.as_str()); if path.exists() { return Ok(id); } diff --git a/src/impls/rest/upload.rs b/src/impls/rest/upload.rs index 20133fa..376a803 100644 --- a/src/impls/rest/upload.rs +++ b/src/impls/rest/upload.rs @@ -82,7 +82,7 @@ impl Service for UploadService { .to_string(); let chunks = field.map_err(ServerError::MultipartError); - let id = match deps.media.write_file(chunks, &name, &mime, None).await { + let id = match deps.media.write_file(chunks, &name, &mime).await { Ok(id) => id, Err(err) => return Ok(err.into_rest_http_response()), }; From f8b606f577f8ff94f3a6bb1c32899a9ff2940eb0 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 21 Feb 2022 23:27:33 +0300 Subject: [PATCH 06/62] refactor: introduce migrate_type, improve migration error reporting --- src/db/migration/add_account_kind.rs | 41 ++++++---------------------- src/db/migration/mod.rs | 37 ++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/db/migration/add_account_kind.rs b/src/db/migration/add_account_kind.rs index 943ab32..9ab4e47 100644 --- a/src/db/migration/add_account_kind.rs +++ b/src/db/migration/add_account_kind.rs @@ -1,9 +1,6 @@ use super::*; -use db::{ - profile::{make_user_profile_key, USER_PREFIX}, - rkyv_ser, Batch, DbError, -}; +use db::profile::USER_PREFIX; use harmony_rust_sdk::api::profile::AccountKind; use crate::api::profile::Profile as NewProfile; @@ -12,35 +9,15 @@ use profile::Profile as OldProfile; pub(super) fn migrate(db: &Db) -> BoxFuture<'_, DbResult<()>> { let fut = async move { let profile_tree = db.open_tree(b"profile").await?; - let mut batch = Batch::default(); - for res in profile_tree.scan_prefix(USER_PREFIX).await { - let (key, val) = res?; - if key.len() == make_user_profile_key(0).len() { - let old_profile = rkyv::from_bytes::(&val); - if let Ok(old_profile) = old_profile { - let new_val = rkyv_ser(&NewProfile { - user_avatar: old_profile.user_avatar, - account_kind: AccountKind::FullUnspecified.into(), - user_name: old_profile.user_name, - user_status: old_profile.user_status, - }); - batch.insert(key, new_val); - } else if rkyv::check_archived_root::(&val).is_ok() { - // if it's new, then its already fine - continue; - } else { - old_profile.map_err(|err| { - DbError::from( - anyhow::anyhow!("profile has invalid state") - .context(format!("rkyv error: {}", err)) - .context(format!("key: {}", String::from_utf8_lossy(key.as_ref()))), - ) - })?; - } + migrate_type::(&profile_tree, USER_PREFIX, |old_profile| { + NewProfile { + user_avatar: old_profile.user_avatar, + account_kind: AccountKind::FullUnspecified.into(), + user_name: old_profile.user_name, + user_status: old_profile.user_status, } - } - profile_tree.apply_batch(batch).await?; - Ok(()) + }) + .await }; Box::pin(fut) diff --git a/src/db/migration/mod.rs b/src/db/migration/mod.rs index ef9c236..f54e682 100644 --- a/src/db/migration/mod.rs +++ b/src/db/migration/mod.rs @@ -1,11 +1,17 @@ use std::future::Future; +use anyhow::Context; +use bytecheck::CheckBytes; use hrpc::server::gen_prelude::BoxFuture; +use rkyv::{ + de::deserializers::SharedDeserializeMap, ser::serializers::AllocSerializer, + validation::validators::DefaultValidator, Archive, Deserialize, Serialize, +}; use tracing::Instrument; use crate::db; -use super::{Db, DbResult}; +use super::{rkyv_ser, Batch, Db, DbResult, Tree}; mod add_account_kind; mod add_next_msg_ids; @@ -77,3 +83,32 @@ async fn increment_db_version(db: &Db) -> DbResult<()> { } Ok(()) } + +async fn migrate_type(tree: &Tree, prefix: &[u8], mut migrate: F) -> DbResult<()> +where + From: Archive, + To: Archive + Serialize>, + From::Archived: + for<'a> CheckBytes> + Deserialize, + To::Archived: for<'a> CheckBytes>, + F: FnMut(From) -> To, +{ + let mut batch = Batch::default(); + for res in tree.scan_prefix(prefix).await { + let (key, val) = res?; + let old = rkyv::from_bytes::(&val); + if let Ok(old) = old { + let new_val = migrate(old); + let new_val = rkyv_ser(&new_val); + batch.insert(key, new_val); + } else if rkyv::check_archived_root::(&val).is_ok() { + // if it's new, then its already fine + continue; + } else { + old.map_err(|err| anyhow::anyhow!(err.to_string())) + .with_context(|| format!("invalid state on key: {:?}", key.as_ref()))?; + } + } + tree.apply_batch(batch).await?; + Ok(()) +} From 328b00492832275cbce458f2d11bd182841dd30d Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 21 Feb 2022 23:37:16 +0300 Subject: [PATCH 07/62] refactor: introduce define_migration to abstract away ugly BoxFuture --- src/db/migration/add_account_kind.rs | 28 +++---- src/db/migration/add_next_msg_ids.rs | 82 +++++++++---------- src/db/migration/initial_db_version.rs | 22 ++--- src/db/migration/mod.rs | 12 +++ .../remove_log_chan_id_from_admin_keys.rs | 28 +++---- 5 files changed, 84 insertions(+), 88 deletions(-) diff --git a/src/db/migration/add_account_kind.rs b/src/db/migration/add_account_kind.rs index 9ab4e47..54edc39 100644 --- a/src/db/migration/add_account_kind.rs +++ b/src/db/migration/add_account_kind.rs @@ -6,22 +6,18 @@ use harmony_rust_sdk::api::profile::AccountKind; use crate::api::profile::Profile as NewProfile; use profile::Profile as OldProfile; -pub(super) fn migrate(db: &Db) -> BoxFuture<'_, DbResult<()>> { - let fut = async move { - let profile_tree = db.open_tree(b"profile").await?; - migrate_type::(&profile_tree, USER_PREFIX, |old_profile| { - NewProfile { - user_avatar: old_profile.user_avatar, - account_kind: AccountKind::FullUnspecified.into(), - user_name: old_profile.user_name, - user_status: old_profile.user_status, - } - }) - .await - }; - - Box::pin(fut) -} +define_migration!(|db| { + let profile_tree = db.open_tree(b"profile").await?; + migrate_type::(&profile_tree, USER_PREFIX, |old_profile| { + NewProfile { + user_avatar: old_profile.user_avatar, + account_kind: AccountKind::FullUnspecified.into(), + user_name: old_profile.user_name, + user_status: old_profile.user_status, + } + }) + .await +}); scherzo_derive::define_proto_mod!(before_account_kind, profile); scherzo_derive::define_proto_mod!(before_account_kind, harmonytypes); diff --git a/src/db/migration/add_next_msg_ids.rs b/src/db/migration/add_next_msg_ids.rs index dcf65fb..9e27d12 100644 --- a/src/db/migration/add_next_msg_ids.rs +++ b/src/db/migration/add_next_msg_ids.rs @@ -2,47 +2,43 @@ use super::*; use db::{chat::make_chan_key, deser_chan, Batch}; -pub(super) fn migrate(db: &Db) -> BoxFuture<'_, DbResult<()>> { - const CHAN_KEY_LEN: usize = make_chan_key(0, 0).len(); - - let fut = async move { - let chat_tree = db.open_tree(b"chat").await?; - - let mut batch = Batch::default(); - for res in chat_tree.iter().await { - let (key, val) = res?; - let mut key: Vec = key.into(); - - if key.len() == CHAN_KEY_LEN && key[8] == 8 { - deser_chan(val); - key.push(9); - - let id = chat_tree - .scan_prefix(&key) - .await - .last() - // Ensure that the first message ID is always 1! - // otherwise get message id - .map_or(Ok(1), |res| { - res.map(|res| { - u64::from_be_bytes( - res.0 - .split_at(key.len()) - .1 - .try_into() - .expect("failed to convert to u64 id"), - ) - }) - })?; - - key.pop(); - key.push(7); - - batch.insert(key, id.to_be_bytes()); - } +const CHAN_KEY_LEN: usize = make_chan_key(0, 0).len(); + +define_migration!(|db| { + let chat_tree = db.open_tree(b"chat").await?; + + let mut batch = Batch::default(); + for res in chat_tree.iter().await { + let (key, val) = res?; + let mut key: Vec = key.into(); + + if key.len() == CHAN_KEY_LEN && key[8] == 8 { + deser_chan(val); + key.push(9); + + let id = chat_tree + .scan_prefix(&key) + .await + .last() + // Ensure that the first message ID is always 1! + // otherwise get message id + .map_or(Ok(1), |res| { + res.map(|res| { + u64::from_be_bytes( + res.0 + .split_at(key.len()) + .1 + .try_into() + .expect("failed to convert to u64 id"), + ) + }) + })?; + + key.pop(); + key.push(7); + + batch.insert(key, id.to_be_bytes()); } - chat_tree.apply_batch(batch).await - }; - - Box::pin(fut) -} + } + chat_tree.apply_batch(batch).await +}); diff --git a/src/db/migration/initial_db_version.rs b/src/db/migration/initial_db_version.rs index 9dd1692..b037106 100644 --- a/src/db/migration/initial_db_version.rs +++ b/src/db/migration/initial_db_version.rs @@ -1,15 +1,11 @@ use super::*; -pub(super) fn migrate(db: &Db) -> BoxFuture<'_, DbResult<()>> { - let fut = async move { - let version_tree = db.open_tree(b"version").await?; - if !version_tree.contains_key(b"version").await? { - version_tree - .insert(b"version", &MIGRATIONS.len().to_be_bytes()) - .await?; - } - Ok(()) - }; - - Box::pin(fut) -} +define_migration!(|db| { + let version_tree = db.open_tree(b"version").await?; + if !version_tree.contains_key(b"version").await? { + version_tree + .insert(b"version", &MIGRATIONS.len().to_be_bytes()) + .await?; + } + Ok(()) +}); diff --git a/src/db/migration/mod.rs b/src/db/migration/mod.rs index f54e682..b6d6f0d 100644 --- a/src/db/migration/mod.rs +++ b/src/db/migration/mod.rs @@ -112,3 +112,15 @@ where tree.apply_batch(batch).await?; Ok(()) } + +macro_rules! define_migration { + (|$db:ident| $e:tt) => { + pub(super) fn migrate($db: &Db) -> BoxFuture<'_, DbResult<()>> { + let fut = Box::pin(async move { $e }); + + Box::pin(fut) + } + }; +} + +pub(self) use define_migration; diff --git a/src/db/migration/remove_log_chan_id_from_admin_keys.rs b/src/db/migration/remove_log_chan_id_from_admin_keys.rs index ac0ce97..6518a7c 100644 --- a/src/db/migration/remove_log_chan_id_from_admin_keys.rs +++ b/src/db/migration/remove_log_chan_id_from_admin_keys.rs @@ -4,23 +4,19 @@ use crate::db::chat::ADMIN_GUILD_KEY; use super::*; -pub(super) fn migrate(db: &Db) -> BoxFuture<'_, DbResult<()>> { - let fut = Box::pin(async move { - let chat_tree = db.open_tree(b"chat").await?; +define_migration!(|db| { + let chat_tree = db.open_tree(b"chat").await?; - if let Some(raw) = chat_tree.get(ADMIN_GUILD_KEY).await? { - let (gid_raw, rest) = raw.split_at(size_of::()); - let guild_id = unsafe { u64::from_be_bytes(gid_raw.try_into().unwrap_unchecked()) }; - let (_, cmd_raw) = rest.split_at(size_of::()); - let cmd_id = unsafe { u64::from_be_bytes(cmd_raw.try_into().unwrap_unchecked()) }; + if let Some(raw) = chat_tree.get(ADMIN_GUILD_KEY).await? { + let (gid_raw, rest) = raw.split_at(size_of::()); + let guild_id = unsafe { u64::from_be_bytes(gid_raw.try_into().unwrap_unchecked()) }; + let (_, cmd_raw) = rest.split_at(size_of::()); + let cmd_id = unsafe { u64::from_be_bytes(cmd_raw.try_into().unwrap_unchecked()) }; - let new_raw = [guild_id.to_be_bytes(), cmd_id.to_be_bytes()].concat(); + let new_raw = [guild_id.to_be_bytes(), cmd_id.to_be_bytes()].concat(); - chat_tree.insert(ADMIN_GUILD_KEY, new_raw).await?; - } + chat_tree.insert(ADMIN_GUILD_KEY, new_raw).await?; + } - Ok(()) - }); - - Box::pin(fut) -} + Ok(()) +}); From 8a590489067e5070b2c536128baada9e44c6036c Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 21 Feb 2022 23:45:33 +0300 Subject: [PATCH 08/62] refactor: improve define_proto_mod macro --- scherzo_derive/src/lib.rs | 35 +++++++++++++++------------- src/db/migration/add_account_kind.rs | 3 +-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/scherzo_derive/src/lib.rs b/scherzo_derive/src/lib.rs index 5191132..4d3284f 100644 --- a/scherzo_derive/src/lib.rs +++ b/scherzo_derive/src/lib.rs @@ -6,27 +6,30 @@ use syn::{parse_macro_input, AttributeArgs, ItemFn}; #[proc_macro] pub fn define_proto_mod(input: TokenStream) -> TokenStream { let input = input.to_string(); - let mut split = input.split(',').collect::>(); - let (proto_name, svc) = if split.len() == 1 { - ("main", split.pop().unwrap()) + let mut split = input.split(',').map(str::trim).collect::>(); + let (proto_name, svcs) = if split.len() == 1 { + ("main", split) } else { - let svc = split.pop().unwrap().trim(); - let proto_name = split.pop().unwrap().trim(); - (proto_name, svc) + let proto_name = split.remove(0); + (proto_name, split) }; - let path = format!("/{}/protocol.{}.v1.rs", proto_name, svc); - let svc = Ident::new(svc, Span::call_site()); + let mut gen = TokenStream::new(); + for svc in svcs { + let path = format!("/{}/protocol.{}.v1.rs", proto_name, svc); + let svc = Ident::new(svc, Span::call_site()); - (quote! { - pub mod #svc { - pub mod v1 { - include!(concat!(env!("OUT_DIR"), #path)); + gen.extend(TokenStream::from(quote! { + pub mod #svc { + pub mod v1 { + include!(concat!(env!("OUT_DIR"), #path)); + } + pub use v1::*; } - pub use v1::*; - } - }) - .into() + })); + } + + gen } #[proc_macro] diff --git a/src/db/migration/add_account_kind.rs b/src/db/migration/add_account_kind.rs index 54edc39..e485b94 100644 --- a/src/db/migration/add_account_kind.rs +++ b/src/db/migration/add_account_kind.rs @@ -19,5 +19,4 @@ define_migration!(|db| { .await }); -scherzo_derive::define_proto_mod!(before_account_kind, profile); -scherzo_derive::define_proto_mod!(before_account_kind, harmonytypes); +scherzo_derive::define_proto_mod!(before_account_kind, harmonytypes, profile); From eacac0077967c25b8993459ca40e501ccdc19bfa Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 22 Feb 2022 00:42:17 +0300 Subject: [PATCH 09/62] feat: incomplete proto migration --- .gitmodules | 3 + build.rs | 26 ++--- src/db/migration/mod.rs | 2 + src/db/migration/proto_v2.rs | 191 +++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 16 deletions(-) create mode 100644 src/db/migration/proto_v2.rs diff --git a/.gitmodules b/.gitmodules index e3152d6..33411f7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "protocols/before_account_kind"] path = protocols/before_account_kind url = https://github.com/harmony-development/protocol.git +[submodule "protocols/before_proto_v2"] + path = protocols/before_proto_v2 + url = https://github.com/harmony-development/protocol.git diff --git a/build.rs b/build.rs index bb4e221..cdca5f9 100644 --- a/build.rs +++ b/build.rs @@ -5,24 +5,16 @@ fn main() -> Result<()> { "before_account_kind", &["profile.v1", "harmonytypes.v1"], &[], - |builder| { - builder.modify_hrpc_config(|cfg| { - cfg.type_attribute( - ".protocol.profile.v1.Profile", - "#[archive_attr(derive(::bytecheck::CheckBytes))]", - ) - }) - }, + )?; + build_protocol( + "before_proto_v2", + &["profile.v1", "emote.v1", "chat.v1", "harmonytypes.v1"], + &[], )?; Ok(()) } -fn build_protocol( - version: &str, - stable_svcs: &[&str], - staging_svcs: &[&str], - f: impl FnOnce(Builder) -> Builder, -) -> Result<()> { +fn build_protocol(version: &str, stable_svcs: &[&str], staging_svcs: &[&str]) -> Result<()> { let protocol_path = format!("protocols/{}", version); let out_dir = { let mut dir = std::env::var("OUT_DIR").expect("no out dir, how"); @@ -48,11 +40,13 @@ fn build_protocol( format!(".protocol.{}", service), "#[derive(::rkyv::Archive, ::rkyv::Serialize, ::rkyv::Deserialize)]", ) + .type_attribute( + format!(".protocol.{}", service), + "#[archive_attr(derive(::bytecheck::CheckBytes))]", + ) }); } - let builder = f(builder); - builder.generate(protocol, out_dir)?; Ok(()) diff --git a/src/db/migration/mod.rs b/src/db/migration/mod.rs index b6d6f0d..61f0206 100644 --- a/src/db/migration/mod.rs +++ b/src/db/migration/mod.rs @@ -16,6 +16,7 @@ use super::{rkyv_ser, Batch, Db, DbResult, Tree}; mod add_account_kind; mod add_next_msg_ids; mod initial_db_version; +mod proto_v2; mod remove_log_chan_id_from_admin_keys; mod timestamps_are_milliseconds; @@ -27,6 +28,7 @@ pub const MIGRATIONS: [Migration; 5] = [ remove_log_chan_id_from_admin_keys::migrate, add_account_kind::migrate, timestamps_are_milliseconds::migrate, + proto_v2::migrate, ]; pub async fn get_db_version(db: &Db) -> DbResult<(usize, bool)> { diff --git a/src/db/migration/proto_v2.rs b/src/db/migration/proto_v2.rs new file mode 100644 index 0000000..182c0fe --- /dev/null +++ b/src/db/migration/proto_v2.rs @@ -0,0 +1,191 @@ +use super::*; + +use crate::api::{ + chat::{ + attachment::Info, + content::{Extra, InviteAccepted, InviteRejected, RoomUpgradedToGuild}, + format::{Format as NewFormatData, *}, + overrides::Reason as NewReason, + Attachment, Content as NewContent, Format as NewFormat, ImageInfo, Message as NewMessage, + Minithumbnail, Overrides as NewOverrides, Reaction as NewReaction, + }, + emote::Emote as NewEmote, + harmonytypes::{Anything as NewAnything, Empty as NewEmpty, Metadata as NewMetadata}, +}; +use chat::Message as OldMessage; + +define_migration!(|db| { + let chat_tree = db.open_tree(b"chat").await?; + migrate_type::(&chat_tree, &[], |old| NewMessage { + author_id: old.author_id, + content: old.content.and_then(|c| c.content).map(|old| { + let mut content = NewContent::default(); + match old { + chat::content::Content::TextMessage(text) => { + if let Some(text) = text.content { + content = content.with_text(text.text).with_text_formats( + text.format.into_iter().map(From::from).collect::>(), + ); + } + } + // TODO: I HATE ONEOFS I HATE ONEOFS + chat::content::Content::EmbedMessage(_) => todo!(), + chat::content::Content::AttachmentMessage(old) => { + content.attachments = old + .files + .into_iter() + .map(|file| Attachment { + id: file.id, + name: file.name, + mimetype: file.mimetype, + size: file.size, + info: None, + }) + .collect(); + } + chat::content::Content::PhotoMessage(old) => { + content.attachments = old + .photos + .into_iter() + .map(|photo| Attachment { + id: photo.hmc, + name: photo.name, + // TODO: read the image for the actual mimetype + mimetype: "image/webp".to_string(), + size: photo.file_size, + info: Some(Info::Image(ImageInfo { + caption: photo.caption.map(|f| f.text), + height: photo.height, + width: photo.width, + minithumbnail: photo.minithumbnail.map(|old| Minithumbnail { + height: old.height, + width: old.width, + data: old.data, + }), + })), + }) + .collect(); + } + chat::content::Content::InviteRejected(old) => { + content.extra = Some(Extra::InviteRejected(InviteRejected { + inviter_id: old.inviter_id, + invitee_id: old.invitee_id, + })); + } + chat::content::Content::InviteAccepted(old) => { + content.extra = Some(Extra::InviteAccepted(InviteAccepted { + inviter_id: old.inviter_id, + invitee_id: old.invitee_id, + })); + } + chat::content::Content::RoomUpgradedToGuild(old) => { + content.extra = Some(Extra::RoomUpgradedToGuild(RoomUpgradedToGuild { + upgraded_by: old.upgraded_by, + })); + } + } + content + }), + created_at: old.created_at, + edited_at: old.edited_at, + in_reply_to: old.in_reply_to, + metadata: old.metadata.map(|old| NewMetadata { + kind: old.kind, + extension: old + .extension + .into_iter() + .map(|(key, val)| { + ( + key, + NewAnything { + body: val.body, + kind: val.kind, + }, + ) + }) + .collect(), + }), + overrides: old.overrides.map(|old| NewOverrides { + avatar: old.avatar, + username: old.username, + reason: old.reason.map(|old| match old { + chat::overrides::Reason::UserDefined(e) => NewReason::UserDefined(e), + chat::overrides::Reason::Webhook(e) => NewReason::Webhook(e.into()), + chat::overrides::Reason::SystemPlurality(e) => NewReason::SystemPlurality(e.into()), + chat::overrides::Reason::SystemMessage(e) => NewReason::SystemMessage(e.into()), + chat::overrides::Reason::Bridge(e) => NewReason::Bridge(e.into()), + }), + }), + reactions: old + .reactions + .into_iter() + .map(|old| NewReaction { + count: old.count, + emote: old.emote.map(|old| NewEmote { + name: old.name, + image_id: old.image_id, + }), + }) + .collect(), + }) + .await?; + Ok(()) +}); + +scherzo_derive::define_proto_mod!(before_proto_v2, harmonytypes, chat, emote, profile); + +impl From for NewEmpty { + fn from(_: harmonytypes::Empty) -> Self { + NewEmpty {} + } +} + +impl From for NewFormat { + fn from(old: chat::Format) -> Self { + NewFormat { + length: old.length, + start: old.start, + format: old.format.map(|old| match old { + chat::format::Format::Bold(_) => NewFormatData::Bold(Bold {}), + chat::format::Format::Italic(_) => NewFormatData::Italic(Italic {}), + chat::format::Format::Underline(_) => NewFormatData::Underline(Underline {}), + chat::format::Format::Monospace(_) => NewFormatData::Monospace(Monospace {}), + chat::format::Format::Superscript(_) => NewFormatData::Superscript(Superscript {}), + chat::format::Format::Subscript(_) => NewFormatData::Subscript(Subscript {}), + chat::format::Format::CodeBlock(old) => NewFormatData::CodeBlock(CodeBlock { + language: old.language, + }), + chat::format::Format::UserMention(old) => NewFormatData::UserMention(UserMention { + user_id: old.user_id, + }), + chat::format::Format::RoleMention(old) => NewFormatData::RoleMention(RoleMention { + role_id: old.role_id, + }), + chat::format::Format::ChannelMention(old) => { + NewFormatData::ChannelMention(ChannelMention { + channel_id: old.channel_id, + }) + } + chat::format::Format::GuildMention(old) => { + NewFormatData::GuildMention(GuildMention { + guild_id: old.guild_id, + homeserver: old.homeserver, + }) + } + chat::format::Format::Emoji(old) => NewFormatData::Emoji(Emoji { + emote: Some(NewEmote { + image_id: old.image_hmc, + // TODO: actually get the emote name using the pack_id from old + name: String::new(), + }), + }), + chat::format::Format::Color(old) => NewFormatData::Color(Color { kind: old.kind }), + chat::format::Format::Localization(old) => { + NewFormatData::Localization(Localization { + i18n_code: old.i18n_code, + }) + } + }), + } + } +} From 0b78147dce4cec7d94efc691ae38102c0ed090bc Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 22 Feb 2022 20:28:40 +0300 Subject: [PATCH 10/62] feat: finish proto v2 migration --- src/db/migration/proto_v2.rs | 426 ++++++++++++++++++++++++----------- 1 file changed, 296 insertions(+), 130 deletions(-) diff --git a/src/db/migration/proto_v2.rs b/src/db/migration/proto_v2.rs index 182c0fe..afbf60f 100644 --- a/src/db/migration/proto_v2.rs +++ b/src/db/migration/proto_v2.rs @@ -1,18 +1,30 @@ use super::*; -use crate::api::{ - chat::{ - attachment::Info, - content::{Extra, InviteAccepted, InviteRejected, RoomUpgradedToGuild}, - format::{Format as NewFormatData, *}, - overrides::Reason as NewReason, - Attachment, Content as NewContent, Format as NewFormat, ImageInfo, Message as NewMessage, - Minithumbnail, Overrides as NewOverrides, Reaction as NewReaction, +use crate::{ + api::{ + chat::{ + action::{ + dropdown::Entry as DropdownEntry, Button as ButtonAction, + Dropdown as DropdownAction, Input as InputAction, Kind as ActionKind, + }, + attachment::Info, + content::{Extra, InviteAccepted, InviteRejected, RoomUpgradedToGuild}, + embed::{embed_field::Image, EmbedField, EmbedHeading}, + format::{Format as NewFormatData, *}, + overrides::Reason as NewReason, + Action, Attachment, Content as NewContent, Embed, Format as NewFormat, FormattedText, + ImageInfo, Message as NewMessage, Minithumbnail, Overrides as NewOverrides, + Reaction as NewReaction, + }, + emote::Emote as NewEmote, + harmonytypes::{Anything as NewAnything, Empty as NewEmpty, Metadata as NewMetadata}, + profile::Profile as NewProfile, }, - emote::Emote as NewEmote, - harmonytypes::{Anything as NewAnything, Empty as NewEmpty, Metadata as NewMetadata}, + db::profile::USER_PREFIX, }; + use chat::Message as OldMessage; +use profile::Profile as OldProfile; define_migration!(|db| { let chat_tree = db.open_tree(b"chat").await?; @@ -28,60 +40,23 @@ define_migration!(|db| { ); } } - // TODO: I HATE ONEOFS I HATE ONEOFS - chat::content::Content::EmbedMessage(_) => todo!(), + chat::content::Content::EmbedMessage(old) => { + content.embeds = old.embeds.into_iter().map(Into::into).collect(); + } chat::content::Content::AttachmentMessage(old) => { - content.attachments = old - .files - .into_iter() - .map(|file| Attachment { - id: file.id, - name: file.name, - mimetype: file.mimetype, - size: file.size, - info: None, - }) - .collect(); + content.attachments = old.files.into_iter().map(Into::into).collect(); } chat::content::Content::PhotoMessage(old) => { - content.attachments = old - .photos - .into_iter() - .map(|photo| Attachment { - id: photo.hmc, - name: photo.name, - // TODO: read the image for the actual mimetype - mimetype: "image/webp".to_string(), - size: photo.file_size, - info: Some(Info::Image(ImageInfo { - caption: photo.caption.map(|f| f.text), - height: photo.height, - width: photo.width, - minithumbnail: photo.minithumbnail.map(|old| Minithumbnail { - height: old.height, - width: old.width, - data: old.data, - }), - })), - }) - .collect(); + content.attachments = old.photos.into_iter().map(Into::into).collect(); } chat::content::Content::InviteRejected(old) => { - content.extra = Some(Extra::InviteRejected(InviteRejected { - inviter_id: old.inviter_id, - invitee_id: old.invitee_id, - })); + content.extra = Some(Extra::InviteRejected(old.into())); } chat::content::Content::InviteAccepted(old) => { - content.extra = Some(Extra::InviteAccepted(InviteAccepted { - inviter_id: old.inviter_id, - invitee_id: old.invitee_id, - })); + content.extra = Some(Extra::InviteAccepted(old.into())); } chat::content::Content::RoomUpgradedToGuild(old) => { - content.extra = Some(Extra::RoomUpgradedToGuild(RoomUpgradedToGuild { - upgraded_by: old.upgraded_by, - })); + content.extra = Some(Extra::RoomUpgradedToGuild(old.into())); } } content @@ -89,50 +64,239 @@ define_migration!(|db| { created_at: old.created_at, edited_at: old.edited_at, in_reply_to: old.in_reply_to, - metadata: old.metadata.map(|old| NewMetadata { + metadata: old.metadata.map(Into::into), + overrides: old.overrides.map(Into::into), + reactions: old.reactions.into_iter().map(Into::into).collect(), + }) + .await?; + let profile_tree = db.open_tree(b"profile").await?; + migrate_type::(&profile_tree, USER_PREFIX, |old| NewProfile { + user_avatar: old.user_avatar, + account_kind: old.account_kind, + user_name: old.user_name, + user_status: old.user_status, + }) + .await?; + Ok(()) +}); + +scherzo_derive::define_proto_mod!(before_proto_v2, harmonytypes, chat, emote, profile); + +impl From for Embed { + fn from(embed: chat::Embed) -> Self { + Embed { + header: embed.header.map(Into::into), + title: embed.title, + body: embed.body.map(Into::into), + fields: embed.fields.into_iter().map(Into::into).collect(), + footer: embed.footer.map(Into::into), + color: embed.color, + } + } +} + +impl From for EmbedHeading { + fn from(old: chat::embed::EmbedHeading) -> Self { + EmbedHeading { + url: old.url, + icon: old.icon, + subtext: old.subtext, + text: old.text, + } + } +} + +impl From for EmbedField { + fn from(old: chat::embed::EmbedField) -> Self { + EmbedField { + presentation: old.presentation, + title: old.title, + subtitle: old.subtitle, + body: old.body.map(Into::into), + image: old.image_url.map(|id| Image { + id, + ..Default::default() + }), + actions: old.actions.into_iter().map(Into::into).collect(), + } + } +} + +impl From for Action { + fn from(old: chat::Action) -> Self { + Action { + action_type: old.action_type, + kind: old.kind.map(Into::into), + } + } +} + +impl From for ActionKind { + fn from(old: chat::action::Kind) -> Self { + match old { + chat::action::Kind::Button(old) => ActionKind::Button(ButtonAction { + data: old.data, + text: old.text, + url: old.url, + }), + chat::action::Kind::Dropdown(old) => ActionKind::Dropdown(DropdownAction { + entries: old.entries.into_iter().map(Into::into).collect(), + label: old.label, + }), + chat::action::Kind::Input(old) => ActionKind::Input(InputAction { + data: old.data, + label: old.label, + multiline: old.multiline, + }), + } + } +} + +impl From for DropdownEntry { + fn from(old: chat::action::dropdown::Entry) -> Self { + DropdownEntry { + data: old.data, + label: old.label, + } + } +} + +impl From for RoomUpgradedToGuild { + fn from(old: chat::content::RoomUpgradedToGuild) -> Self { + RoomUpgradedToGuild { + upgraded_by: old.upgraded_by, + } + } +} + +impl From for InviteAccepted { + fn from(old: chat::content::InviteAccepted) -> Self { + InviteAccepted { + inviter_id: old.inviter_id, + invitee_id: old.invitee_id, + } + } +} + +impl From for InviteRejected { + fn from(old: chat::content::InviteRejected) -> Self { + InviteRejected { + inviter_id: old.inviter_id, + invitee_id: old.invitee_id, + } + } +} + +impl From for Attachment { + fn from(old: chat::Photo) -> Self { + Attachment { + id: old.hmc, + name: old.name, + // TODO: read the image for the actual mimetype + mimetype: "image/webp".to_string(), + size: old.file_size, + info: Some(Info::Image(ImageInfo { + caption: old.caption.map(|f| f.text), + height: old.height, + width: old.width, + minithumbnail: old.minithumbnail.map(Into::into), + })), + } + } +} + +impl From for Minithumbnail { + fn from(old: chat::Minithumbnail) -> Self { + Minithumbnail { + height: old.height, + width: old.width, + data: old.data, + } + } +} + +impl From for Attachment { + fn from(old: chat::Attachment) -> Self { + Attachment { + id: old.id, + name: old.name, + mimetype: old.mimetype, + size: old.size, + info: None, + } + } +} + +impl From for NewMetadata { + fn from(old: harmonytypes::Metadata) -> Self { + NewMetadata { kind: old.kind, extension: old .extension .into_iter() - .map(|(key, val)| { - ( - key, - NewAnything { - body: val.body, - kind: val.kind, - }, - ) - }) + .map(|(key, val)| (key, NewAnything::from(val))) .collect(), - }), - overrides: old.overrides.map(|old| NewOverrides { + } + } +} + +impl From for NewAnything { + fn from(old: harmonytypes::Anything) -> Self { + NewAnything { + body: old.body, + kind: old.kind, + } + } +} + +impl From for NewEmote { + fn from(old: emote::Emote) -> Self { + NewEmote { + name: old.name, + image_id: old.image_id, + } + } +} + +impl From for NewReaction { + fn from(old: chat::Reaction) -> Self { + NewReaction { + count: old.count, + emote: old.emote.map(Into::into), + } + } +} + +impl From for NewOverrides { + fn from(old: chat::Overrides) -> Self { + Self { avatar: old.avatar, username: old.username, - reason: old.reason.map(|old| match old { - chat::overrides::Reason::UserDefined(e) => NewReason::UserDefined(e), - chat::overrides::Reason::Webhook(e) => NewReason::Webhook(e.into()), - chat::overrides::Reason::SystemPlurality(e) => NewReason::SystemPlurality(e.into()), - chat::overrides::Reason::SystemMessage(e) => NewReason::SystemMessage(e.into()), - chat::overrides::Reason::Bridge(e) => NewReason::Bridge(e.into()), - }), - }), - reactions: old - .reactions - .into_iter() - .map(|old| NewReaction { - count: old.count, - emote: old.emote.map(|old| NewEmote { - name: old.name, - image_id: old.image_id, - }), - }) - .collect(), - }) - .await?; - Ok(()) -}); + reason: old.reason.map(Into::into), + } + } +} -scherzo_derive::define_proto_mod!(before_proto_v2, harmonytypes, chat, emote, profile); +impl From for NewReason { + fn from(old: chat::overrides::Reason) -> Self { + match old { + chat::overrides::Reason::UserDefined(e) => NewReason::UserDefined(e), + chat::overrides::Reason::Webhook(e) => NewReason::Webhook(e.into()), + chat::overrides::Reason::SystemPlurality(e) => NewReason::SystemPlurality(e.into()), + chat::overrides::Reason::SystemMessage(e) => NewReason::SystemMessage(e.into()), + chat::overrides::Reason::Bridge(e) => NewReason::Bridge(e.into()), + } + } +} + +impl From for FormattedText { + fn from(old: chat::FormattedText) -> Self { + FormattedText { + text: old.text, + format: old.format.into_iter().map(Into::into).collect(), + } + } +} impl From for NewEmpty { fn from(_: harmonytypes::Empty) -> Self { @@ -145,46 +309,48 @@ impl From for NewFormat { NewFormat { length: old.length, start: old.start, - format: old.format.map(|old| match old { - chat::format::Format::Bold(_) => NewFormatData::Bold(Bold {}), - chat::format::Format::Italic(_) => NewFormatData::Italic(Italic {}), - chat::format::Format::Underline(_) => NewFormatData::Underline(Underline {}), - chat::format::Format::Monospace(_) => NewFormatData::Monospace(Monospace {}), - chat::format::Format::Superscript(_) => NewFormatData::Superscript(Superscript {}), - chat::format::Format::Subscript(_) => NewFormatData::Subscript(Subscript {}), - chat::format::Format::CodeBlock(old) => NewFormatData::CodeBlock(CodeBlock { - language: old.language, - }), - chat::format::Format::UserMention(old) => NewFormatData::UserMention(UserMention { - user_id: old.user_id, - }), - chat::format::Format::RoleMention(old) => NewFormatData::RoleMention(RoleMention { - role_id: old.role_id, - }), - chat::format::Format::ChannelMention(old) => { - NewFormatData::ChannelMention(ChannelMention { - channel_id: old.channel_id, - }) - } - chat::format::Format::GuildMention(old) => { - NewFormatData::GuildMention(GuildMention { - guild_id: old.guild_id, - homeserver: old.homeserver, - }) - } - chat::format::Format::Emoji(old) => NewFormatData::Emoji(Emoji { - emote: Some(NewEmote { - image_id: old.image_hmc, - // TODO: actually get the emote name using the pack_id from old - name: String::new(), - }), + format: old.format.map(Into::into), + } + } +} + +impl From for NewFormatData { + fn from(old: chat::format::Format) -> Self { + match old { + chat::format::Format::Bold(_) => NewFormatData::Bold(Bold {}), + chat::format::Format::Italic(_) => NewFormatData::Italic(Italic {}), + chat::format::Format::Underline(_) => NewFormatData::Underline(Underline {}), + chat::format::Format::Monospace(_) => NewFormatData::Monospace(Monospace {}), + chat::format::Format::Superscript(_) => NewFormatData::Superscript(Superscript {}), + chat::format::Format::Subscript(_) => NewFormatData::Subscript(Subscript {}), + chat::format::Format::CodeBlock(old) => NewFormatData::CodeBlock(CodeBlock { + language: old.language, + }), + chat::format::Format::UserMention(old) => NewFormatData::UserMention(UserMention { + user_id: old.user_id, + }), + chat::format::Format::RoleMention(old) => NewFormatData::RoleMention(RoleMention { + role_id: old.role_id, + }), + chat::format::Format::ChannelMention(old) => { + NewFormatData::ChannelMention(ChannelMention { + channel_id: old.channel_id, + }) + } + chat::format::Format::GuildMention(old) => NewFormatData::GuildMention(GuildMention { + guild_id: old.guild_id, + homeserver: old.homeserver, + }), + chat::format::Format::Emoji(old) => NewFormatData::Emoji(Emoji { + emote: Some(NewEmote { + image_id: old.image_hmc, + // TODO: actually get the emote name using the pack_id from old + name: String::new(), }), - chat::format::Format::Color(old) => NewFormatData::Color(Color { kind: old.kind }), - chat::format::Format::Localization(old) => { - NewFormatData::Localization(Localization { - i18n_code: old.i18n_code, - }) - } + }), + chat::format::Format::Color(old) => NewFormatData::Color(Color { kind: old.kind }), + chat::format::Format::Localization(old) => NewFormatData::Localization(Localization { + i18n_code: old.i18n_code, }), } } From f5879995f42463ec914207cd382070bd8e10251e Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 22 Feb 2022 21:47:54 +0300 Subject: [PATCH 11/62] chore(deps): update cargo deps --- Cargo.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0fd8385..c903c4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,9 +45,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.54" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a99269dff3bc004caa411f38845c20303f1e393ca2bd6581576fa3a7f59577d" +checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" [[package]] name = "arc-swap" @@ -814,9 +814,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" +checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ "cfg-if", "js-sys", @@ -1237,9 +1237,9 @@ dependencies = [ [[package]] name = "integer-encoding" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90c11140ffea82edce8dcd74137ce9324ec24b3cf0175fc9d7e29164da9915b8" +checksum = "0e85a1509a128c855368e135cffcde7eac17d8e1083f41e2b98c58bc1a5074be" [[package]] name = "ipnet" @@ -2833,8 +2833,8 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.4.2+5.2.1-patched.2" -source = "git+https://github.com/tikv/jemallocator.git?branch=master#52de4257fab3e770f73d5174c12a095b49572fba" +version = "0.4.3+5.2.1-patched.2" +source = "git+https://github.com/tikv/jemallocator.git?branch=master#2706fb3874e075eca51af7f672d228ce28d5c475" dependencies = [ "cc", "fs_extra", @@ -2843,8 +2843,8 @@ dependencies = [ [[package]] name = "tikv-jemallocator" -version = "0.4.1" -source = "git+https://github.com/tikv/jemallocator.git?branch=master#52de4257fab3e770f73d5174c12a095b49572fba" +version = "0.4.3" +source = "git+https://github.com/tikv/jemallocator.git?branch=master#2706fb3874e075eca51af7f672d228ce28d5c475" dependencies = [ "libc", "tikv-jemalloc-sys", @@ -3153,9 +3153,9 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.17.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a73d0f08e0d227c4c63e6d003804946767f4c4f01f52098b56821ae22e336bfc" +checksum = "1f9378e96a9361190ae297e7f3a8ff644aacd2897f244b1ff81f381669196fa6" dependencies = [ "opentelemetry", "tracing", From 4860c9f6adf82b5c993e699a25311024dc0804f6 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 22 Feb 2022 22:13:50 +0300 Subject: [PATCH 12/62] build: remove unused deps --- Cargo.lock | 26 -------------------------- Cargo.toml | 5 +---- deny.toml | 2 -- 3 files changed, 1 insertion(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c903c4c..6989b1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1295,12 +1295,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "keccak" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" - [[package]] name = "lazy_static" version = "1.4.0" @@ -2329,11 +2323,9 @@ dependencies = [ "scherzo_derive", "serde", "serde_json", - "sha3", "sled", "smol_str", "sqlx", - "swimmer", "tikv-jemallocator", "tokio", "tokio-util 0.7.0", @@ -2497,16 +2489,6 @@ dependencies = [ "digest 0.10.3", ] -[[package]] -name = "sha3" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86" -dependencies = [ - "digest 0.10.3", - "keccak", -] - [[package]] name = "sharded-slab" version = "0.1.4" @@ -2725,14 +2707,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" -[[package]] -name = "swimmer" -version = "0.3.0" -source = "git+https://github.com/yusdacra/swimmer-rs.git?branch=master#5f5735a6f8a6e3c61624ab7756943c8fa0cc2793" -dependencies = [ - "thread_local", -] - [[package]] name = "syn" version = "1.0.86" diff --git a/Cargo.toml b/Cargo.toml index e8d2174..d8a73c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,6 @@ itertools = { version = "0.10", default-features = false, features = [ rand = "0.8" argon2 = "0.3" ed25519-compact = "1" -sha3 = "0.10" ahash = "0.7" tokio = { version = "1.16", features = [ @@ -95,7 +94,6 @@ tokio = { version = "1.16", features = [ "signal", ] } tokio-util = { version = "0.7", features = ["io"] } -swimmer = "0.3" tracing = "0.1" tracing-subscriber = { version = "0.3", default-features = false, features = [ @@ -178,5 +176,4 @@ key = "harmony.cachix.org-1:yv78QZHgS0UHkrMW56rccNghWHRz18fFRl8mWQ63M6E=" [patch.crates-io] markup5ever = { git = "https://github.com/servo/html5ever.git", rev = "0e03e1c2b1f63e81f831fd95b9eb8bbde18b7815" } string_cache = { git = "https://github.com/yusdacra/string-cache.git", branch = "chore/deps" } -string_cache_codegen = { git = "https://github.com/yusdacra/string-cache.git", branch = "chore/deps" } -swimmer = { git = "https://github.com/yusdacra/swimmer-rs.git", branch = "master" } \ No newline at end of file +string_cache_codegen = { git = "https://github.com/yusdacra/string-cache.git", branch = "chore/deps" } \ No newline at end of file diff --git a/deny.toml b/deny.toml index 820b503..ad4e644 100644 --- a/deny.toml +++ b/deny.toml @@ -83,7 +83,6 @@ allow = [ "ISC", "OpenSSL", "Zlib", - "CC0-1.0", "BSL-1.0", "0BSD", ] @@ -210,7 +209,6 @@ allow-registry = ["https://github.com/rust-lang/crates.io-index"] # List of URLs for allowed Git repositories allow-git = [ "https://github.com/servo/html5ever.git", - "https://github.com/open-telemetry/opentelemetry-rust.git", "https://github.com/tokio-rs/console.git", "https://github.com/image-rs/image.git", ] From aed1bd68bcec17fd9f605824419b865383694762 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 6 Mar 2022 19:06:56 +0300 Subject: [PATCH 13/62] feat: update protocol --- Cargo.lock | 102 +++------ src/db/migration/add_account_kind.rs | 15 +- src/db/migration/mod.rs | 5 +- src/db/migration/proto_v2.rs | 79 ++++--- src/db/mod.rs | 4 +- src/db/sled.rs | 11 +- src/impls/auth/delete_user.rs | 2 +- src/impls/auth/login_federated.rs | 2 +- src/impls/chat/guilds/create_guild.rs | 2 +- src/impls/chat/messages/add_reaction.rs | 57 +++-- src/impls/chat/messages/mod.rs | 2 +- src/impls/chat/messages/remove_reaction.rs | 36 ++-- ...sage_text.rs => update_message_content.rs} | 26 +-- src/impls/chat/mod.rs | 198 +++++++++++++----- src/impls/mediaproxy/mod.rs | 17 +- src/impls/profile/mod.rs | 7 +- src/impls/profile/update_profile.rs | 5 +- src/impls/profile/update_status.rs | 33 +++ src/main.rs | 4 +- 19 files changed, 371 insertions(+), 236 deletions(-) rename src/impls/chat/messages/{update_message_text.rs => update_message_content.rs} (72%) create mode 100644 src/impls/profile/update_status.rs diff --git a/Cargo.lock b/Cargo.lock index 6989b1b..3348ad3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,9 +145,9 @@ dependencies = [ [[package]] name = "async-task" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d306121baf53310a3fd342d88dc0824f6bbeace68347593658525565abee8" +checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" [[package]] name = "async-trait" @@ -242,16 +242,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" dependencies = [ - "digest 0.10.3", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", + "digest", ] [[package]] @@ -292,9 +283,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.7.3" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" +checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead" [[package]] name = "byteorder" @@ -357,7 +348,7 @@ dependencies = [ [[package]] name = "console-api" version = "0.1.2" -source = "git+https://github.com/tokio-rs/console.git?branch=main#900a5c2bd5b610e9b939a5f824af1ac1a11267d0" +source = "git+https://github.com/tokio-rs/console.git?branch=main#b4e6b6a61eb8fc03a623c7d33a98830c2109fe0d" dependencies = [ "prost", "prost-types", @@ -369,7 +360,7 @@ dependencies = [ [[package]] name = "console-subscriber" version = "0.1.3" -source = "git+https://github.com/tokio-rs/console.git?branch=main#900a5c2bd5b610e9b939a5f824af1ac1a11267d0" +source = "git+https://github.com/tokio-rs/console.git?branch=main#b4e6b6a61eb8fc03a623c7d33a98830c2109fe0d" dependencies = [ "console-api", "crossbeam-channel", @@ -506,22 +497,13 @@ dependencies = [ "adler32", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ - "block-buffer 0.10.2", + "block-buffer", "crypto-common", "subtle", ] @@ -897,7 +879,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#645c9136689eb920483ad9a33996b0185d5c7112" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9d41463c376dabde7fc6b43d0ca2aba70132d5b6" dependencies = [ "hrpc-build", "prost-build", @@ -908,7 +890,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#645c9136689eb920483ad9a33996b0185d5c7112" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9d41463c376dabde7fc6b43d0ca2aba70132d5b6" dependencies = [ "proc-macro2", "quote", @@ -918,7 +900,7 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#645c9136689eb920483ad9a33996b0185d5c7112" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9d41463c376dabde7fc6b43d0ca2aba70132d5b6" dependencies = [ "bytecheck", "harmony_build", @@ -1014,16 +996,15 @@ dependencies = [ [[package]] name = "hrpc" -version = "0.33.22" +version = "0.33.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7808b92a1a40d44ed5ea66d2fca9dbabe5d9a694d95c5ca49b05b87886345135" +checksum = "1e13cd3bc199b303c4e226eb220fd5456982d2fb20d774bd0a0ff963c8c8e48a" dependencies = [ "axum-server", "base64", "bytes", "futures-channel", "futures-util", - "hrpc-build", "hrpc-proc-macro", "http", "http-body", @@ -1033,7 +1014,7 @@ dependencies = [ "pin-project-lite", "prost", "prost-build", - "sha-1 0.10.0", + "sha-1", "tokio", "tokio-tungstenite", "tower", @@ -1380,9 +1361,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "274353858935c992b13c0ca408752e2121da852d07dec7ce5f108c77dfa14d1f" +checksum = "fcb87f3080f6d1d69e8c564c0fcfde1d7aa8cc451ce40cae89479111f03bc0eb" [[package]] name = "mac" @@ -1658,15 +1639,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "openssl-probe" @@ -1912,9 +1887,9 @@ checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "png" -version = "0.17.3" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8f1882177b17c98ec33a51f5910ecbf4db92ca0def706781a1f8d0c661f393" +checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" dependencies = [ "bitflags", "crc32fast", @@ -2094,9 +2069,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" dependencies = [ "bitflags", ] @@ -2193,9 +2168,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.33" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf98e3e6c7ed44e474b454b1ebded3193ee5aba3428e29c55d59b1d65e49945e" +checksum = "2cdcf5caf69bcc87b1e3f5427b4f21a32fdd53c2847687bdf9861abb1cdaa0d8" dependencies = [ "bytecheck", "hashbrown 0.12.0", @@ -2207,9 +2182,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.33" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9940ec6a7c62b1d1f476f607c6caf0d7fbf74e43f77bc022143b878fcd3266" +checksum = "a6cf557da1f81b8c7e889c59c9c3abaf6978f7feb156b9579e4f8bf6d7a2bada" dependencies = [ "proc-macro2", "quote", @@ -2465,19 +2440,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha-1" version = "0.10.0" @@ -2486,7 +2448,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest", ] [[package]] @@ -2925,9 +2887,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.16.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e80b39df6afcc12cdf752398ade96a6b9e99c903dfdc36e53ad10b9c366bca72" +checksum = "06cda1232a49558c46f8a504d5b93101d42c0bf7f911f12a105ba48168f821ae" dependencies = [ "futures-util", "log", @@ -3169,9 +3131,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "tungstenite" -version = "0.16.0" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad3713a14ae247f22a728a0456a545df14acf3867f905adff84be99e23b3ad1" +checksum = "d96a2dea40e7570482f28eb57afbe42d97551905da6a9400acc5c328d24004f5" dependencies = [ "base64", "byteorder", @@ -3181,7 +3143,7 @@ dependencies = [ "log", "rand", "rustls 0.20.4", - "sha-1 0.9.8", + "sha-1", "thiserror", "url", "utf-8", diff --git a/src/db/migration/add_account_kind.rs b/src/db/migration/add_account_kind.rs index e485b94..8ab6212 100644 --- a/src/db/migration/add_account_kind.rs +++ b/src/db/migration/add_account_kind.rs @@ -1,10 +1,10 @@ use super::*; use db::profile::USER_PREFIX; -use harmony_rust_sdk::api::profile::AccountKind; +use harmony_rust_sdk::api::profile::{user_status, AccountKind, UserStatus}; use crate::api::profile::Profile as NewProfile; -use profile::Profile as OldProfile; +use profile::{Profile as OldProfile, UserStatus as OldUserStatus}; define_migration!(|db| { let profile_tree = db.open_tree(b"profile").await?; @@ -13,7 +13,16 @@ define_migration!(|db| { user_avatar: old_profile.user_avatar, account_kind: AccountKind::FullUnspecified.into(), user_name: old_profile.user_name, - user_status: old_profile.user_status, + user_status: Some(UserStatus { + kind: (match OldUserStatus::from_i32(old_profile.user_status).unwrap_or_default() { + OldUserStatus::Online => user_status::Kind::Online, + OldUserStatus::Idle => user_status::Kind::Idle, + OldUserStatus::DoNotDisturb => user_status::Kind::DoNotDisturb, + _ => user_status::Kind::OfflineUnspecified, + }) + .into(), + ..Default::default() + }), } }) .await diff --git a/src/db/migration/mod.rs b/src/db/migration/mod.rs index 61f0206..548d7f5 100644 --- a/src/db/migration/mod.rs +++ b/src/db/migration/mod.rs @@ -108,7 +108,10 @@ where continue; } else { old.map_err(|err| anyhow::anyhow!(err.to_string())) - .with_context(|| format!("invalid state on key: {:?}", key.as_ref()))?; + .with_context(|| format!("on tree: {}", tree.name())) + .with_context(|| { + format!("invalid state on key: {}", String::from_utf8_lossy(&key)) + })?; } } tree.apply_batch(batch).await?; diff --git a/src/db/migration/proto_v2.rs b/src/db/migration/proto_v2.rs index afbf60f..18fc7d8 100644 --- a/src/db/migration/proto_v2.rs +++ b/src/db/migration/proto_v2.rs @@ -7,13 +7,13 @@ use crate::{ dropdown::Entry as DropdownEntry, Button as ButtonAction, Dropdown as DropdownAction, Input as InputAction, Kind as ActionKind, }, - attachment::Info, + attachment::{ImageInfo, Info}, content::{Extra, InviteAccepted, InviteRejected, RoomUpgradedToGuild}, - embed::{embed_field::Image, EmbedField, EmbedHeading}, + embed::{Field as EmbedField, Heading as EmbedHeading}, format::{Format as NewFormatData, *}, overrides::Reason as NewReason, Action, Attachment, Content as NewContent, Embed, Format as NewFormat, FormattedText, - ImageInfo, Message as NewMessage, Minithumbnail, Overrides as NewOverrides, + Message as NewMessage, Minithumbnail, Overrides as NewOverrides, Reaction as NewReaction, }, emote::Emote as NewEmote, @@ -24,7 +24,8 @@ use crate::{ }; use chat::Message as OldMessage; -use profile::Profile as OldProfile; +use harmony_rust_sdk::api::profile::{user_status, UserStatus}; +use profile::{Profile as OldProfile, UserStatus as OldUserStatus}; define_migration!(|db| { let chat_tree = db.open_tree(b"chat").await?; @@ -61,8 +62,8 @@ define_migration!(|db| { } content }), - created_at: old.created_at, - edited_at: old.edited_at, + created_at: to_seconds(old.created_at), + edited_at: old.edited_at.map(to_seconds), in_reply_to: old.in_reply_to, metadata: old.metadata.map(Into::into), overrides: old.overrides.map(Into::into), @@ -74,7 +75,16 @@ define_migration!(|db| { user_avatar: old.user_avatar, account_kind: old.account_kind, user_name: old.user_name, - user_status: old.user_status, + user_status: Some(UserStatus { + kind: (match OldUserStatus::from_i32(old.user_status).unwrap_or_default() { + OldUserStatus::Online => user_status::Kind::Online, + OldUserStatus::Idle => user_status::Kind::Idle, + OldUserStatus::DoNotDisturb => user_status::Kind::DoNotDisturb, + _ => user_status::Kind::OfflineUnspecified, + }) + .into(), + ..Default::default() + }), }) .await?; Ok(()) @@ -82,15 +92,33 @@ define_migration!(|db| { scherzo_derive::define_proto_mod!(before_proto_v2, harmonytypes, chat, emote, profile); +fn to_seconds(millis: u64) -> u64 { + std::time::Duration::from_millis(millis).as_secs() +} + impl From for Embed { fn from(embed: chat::Embed) -> Self { + let (fields, actions) = embed.fields.into_iter().fold( + (Vec::new(), Vec::new()), + |(mut fields, mut actions), item| { + let field = EmbedField { + title: item.title, + body: item.body.map(|f| f.text).unwrap_or_default(), + }; + fields.push(field); + actions.extend(item.actions.into_iter().map(Into::into)); + (fields, actions) + }, + ); Embed { header: embed.header.map(Into::into), title: embed.title, body: embed.body.map(Into::into), - fields: embed.fields.into_iter().map(Into::into).collect(), + fields, footer: embed.footer.map(Into::into), color: embed.color, + image: None, + actions, } } } @@ -100,28 +128,11 @@ impl From for EmbedHeading { EmbedHeading { url: old.url, icon: old.icon, - subtext: old.subtext, text: old.text, } } } -impl From for EmbedField { - fn from(old: chat::embed::EmbedField) -> Self { - EmbedField { - presentation: old.presentation, - title: old.title, - subtitle: old.subtitle, - body: old.body.map(Into::into), - image: old.image_url.map(|id| Image { - id, - ..Default::default() - }), - actions: old.actions.into_iter().map(Into::into).collect(), - } - } -} - impl From for Action { fn from(old: chat::Action) -> Self { Action { @@ -260,9 +271,12 @@ impl From for NewEmote { impl From for NewReaction { fn from(old: chat::Reaction) -> Self { + let emote = old.emote.unwrap_or_default(); NewReaction { count: old.count, - emote: old.emote.map(Into::into), + name: emote.name, + data: emote.image_id, + ..Default::default() } } } @@ -309,14 +323,14 @@ impl From for NewFormat { NewFormat { length: old.length, start: old.start, - format: old.format.map(Into::into), + format: old.format.and_then(Into::into), } } } -impl From for NewFormatData { +impl From for Option { fn from(old: chat::format::Format) -> Self { - match old { + let new = match old { chat::format::Format::Bold(_) => NewFormatData::Bold(Bold {}), chat::format::Format::Italic(_) => NewFormatData::Italic(Italic {}), chat::format::Format::Underline(_) => NewFormatData::Underline(Underline {}), @@ -349,9 +363,8 @@ impl From for NewFormatData { }), }), chat::format::Format::Color(old) => NewFormatData::Color(Color { kind: old.kind }), - chat::format::Format::Localization(old) => NewFormatData::Localization(Localization { - i18n_code: old.i18n_code, - }), - } + _ => return None, + }; + Some(new) } } diff --git a/src/db/mod.rs b/src/db/mod.rs index 6360904..511b051 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -275,13 +275,13 @@ pub mod chat { channel_id: u64, message_id: u64, user_id: u64, - image_id: &str, + data: &str, ) -> Vec { [ make_msg_key(guild_id, channel_id, message_id).as_ref(), &[0], user_id.to_be_bytes().as_ref(), - image_id.as_bytes(), + data.as_bytes(), ] .concat() } diff --git a/src/db/sled.rs b/src/db/sled.rs index b86aad0..45f436a 100644 --- a/src/db/sled.rs +++ b/src/db/sled.rs @@ -10,6 +10,7 @@ type SledFut = Ready>; pub mod shared { use hrpc::common::future::ready; + use smol_str::SmolStr; use super::*; @@ -63,7 +64,10 @@ pub mod shared { self.inner .open_tree(name) .map_err(Into::into) - .map(|tree| Tree { inner: tree }), + .map(|tree| Tree { + inner: tree, + name: String::from_utf8_lossy(name).as_ref().into(), + }), ) } @@ -79,9 +83,14 @@ pub mod shared { #[derive(Debug, Clone)] pub struct Tree { inner: sled::Tree, + name: SmolStr, } impl Tree { + pub fn name(&self) -> &str { + self.name.as_str() + } + pub fn get(&self, key: &[u8]) -> SledFut> { ready( self.inner diff --git a/src/impls/auth/delete_user.rs b/src/impls/auth/delete_user.rs index 9f97901..333159e 100644 --- a/src/impls/auth/delete_user.rs +++ b/src/impls/auth/delete_user.rs @@ -15,7 +15,7 @@ pub async fn logic(deps: &Dependencies, user_id: u64) -> ServerResult<()> { user_id, Some("Deleted User".to_string()), Some("".to_string()), - Some(UserStatus::OfflineUnspecified.into()), + Some(UserStatus::default()), ) .await?; diff --git a/src/impls/auth/login_federated.rs b/src/impls/auth/login_federated.rs index e8435b7..04554a4 100644 --- a/src/impls/auth/login_federated.rs +++ b/src/impls/auth/login_federated.rs @@ -47,7 +47,7 @@ pub async fn handler( ); // Add the profile entry let profile = Profile { - user_status: UserStatus::OfflineUnspecified.into(), + user_status: Some(UserStatus::default()), user_avatar: avatar, user_name: username, account_kind: AccountKind::FullUnspecified.into(), diff --git a/src/impls/chat/guilds/create_guild.rs b/src/impls/chat/guilds/create_guild.rs index 817ecfc..717c8df 100644 --- a/src/impls/chat/guilds/create_guild.rs +++ b/src/impls/chat/guilds/create_guild.rs @@ -28,7 +28,7 @@ pub async fn handler( name, picture, metadata, - guild_kind::Kind::Normal(guild_kind::Normal::new()), + guild::Kind::NormalUnspecified, ) .await?; diff --git a/src/impls/chat/messages/add_reaction.rs b/src/impls/chat/messages/add_reaction.rs index 411994f..06b4bd8 100644 --- a/src/impls/chat/messages/add_reaction.rs +++ b/src/impls/chat/messages/add_reaction.rs @@ -10,27 +10,50 @@ pub async fn handler( guild_id, channel_id, message_id, - emote, + reaction_data, + reaction_kind, + reaction_name, } = request.into_message().await?; + let reaction_kind = ReactionKind::from_i32(reaction_kind).unwrap_or_default(); - if let Some(emote) = emote { - let chat_tree = &svc.deps.chat_tree; + let chat_tree = &svc.deps.chat_tree; - chat_tree - .check_perms( - guild_id, - Some(channel_id), - user_id, - all_permissions::MESSAGES_REACTIONS_ADD, - false, - ) - .await?; + chat_tree + .check_perms( + guild_id, + Some(channel_id), + user_id, + all_permissions::MESSAGES_REACTIONS_ADD, + false, + ) + .await?; - let reaction = chat_tree - .update_reaction(user_id, guild_id, channel_id, message_id, emote, true) - .await?; - svc.send_reaction_event(guild_id, channel_id, message_id, reaction); + let did_add = chat_tree + .add_reaction( + user_id, + guild_id, + channel_id, + message_id, + reaction_data.clone(), + reaction_name.clone(), + reaction_kind, + ) + .await?; + if did_add { + svc.send_new_reaction_event( + guild_id, + channel_id, + message_id, + Reaction { + count: 1, + data: reaction_data, + kind: reaction_kind.into(), + name: reaction_name, + }, + ); + } else { + svc.send_added_reaction_event(guild_id, channel_id, message_id, reaction_data); } - Ok((AddReactionResponse {}).into_response()) + Ok(AddReactionResponse::new().into_response()) } diff --git a/src/impls/chat/messages/mod.rs b/src/impls/chat/messages/mod.rs index 11766b4..38f3e0b 100644 --- a/src/impls/chat/messages/mod.rs +++ b/src/impls/chat/messages/mod.rs @@ -9,4 +9,4 @@ pub mod pin_message; pub mod remove_reaction; pub mod send_message; pub mod unpin_message; -pub mod update_message_text; +pub mod update_message_content; diff --git a/src/impls/chat/messages/remove_reaction.rs b/src/impls/chat/messages/remove_reaction.rs index 8b1053b..dedebef 100644 --- a/src/impls/chat/messages/remove_reaction.rs +++ b/src/impls/chat/messages/remove_reaction.rs @@ -10,29 +10,25 @@ pub async fn handler( guild_id, channel_id, message_id, - emote, + reaction_data, } = request.into_message().await?; - if let Some(emote) = emote { - let chat_tree = &svc.deps.chat_tree; + let chat_tree = &svc.deps.chat_tree; - chat_tree - .check_perms( - guild_id, - Some(channel_id), - user_id, - all_permissions::MESSAGES_REACTIONS_REMOVE, - false, - ) - .await?; + chat_tree + .check_perms( + guild_id, + Some(channel_id), + user_id, + all_permissions::MESSAGES_REACTIONS_REMOVE, + false, + ) + .await?; - let reaction = chat_tree - .update_reaction(user_id, guild_id, channel_id, message_id, emote, false) - .await?; - if reaction.is_some() { - svc.send_reaction_event(guild_id, channel_id, message_id, reaction); - } - } + chat_tree + .remove_reaction(user_id, guild_id, channel_id, message_id, &reaction_data) + .await?; + svc.send_removed_reaction_event(guild_id, channel_id, message_id, reaction_data); - Ok((RemoveReactionResponse {}).into_response()) + Ok(RemoveReactionResponse::new().into_response()) } diff --git a/src/impls/chat/messages/update_message_text.rs b/src/impls/chat/messages/update_message_content.rs similarity index 72% rename from src/impls/chat/messages/update_message_text.rs rename to src/impls/chat/messages/update_message_content.rs index 57a0c3c..927e088 100644 --- a/src/impls/chat/messages/update_message_text.rs +++ b/src/impls/chat/messages/update_message_content.rs @@ -4,13 +4,13 @@ use super::*; pub async fn handler( svc: &ChatServer, - request: Request, -) -> ServerResult> { + request: Request, +) -> ServerResult> { let user_id = svc.deps.auth(&request).await?; let request = request.into_message().await?; - let UpdateMessageTextRequest { + let UpdateMessageContentRequest { guild_id, channel_id, message_id, @@ -26,12 +26,9 @@ pub async fn handler( .check_perms(guild_id, Some(channel_id), user_id, "messages.send", false) .await?; - let Some(new_content) = new_content else { - bail!(ServerError::MessageContentCantBeEmpty); - }; - if new_content.text.is_empty() { - bail!(ServerError::MessageContentCantBeEmpty); - } + let new_content = chat_tree + .process_message_content(&svc.deps, new_content) + .await?; let key = make_msg_key(guild_id, channel_id, message_id); let Some(message_raw) = chat_tree.get(key).await? else { @@ -51,14 +48,7 @@ pub async fn handler( .unwrap(); let edited_at = get_time_secs(); - if let Some(content) = &mut message.content { - content.text.clear(); - content.text.push_str(&new_content.text); - content.text_formats.clear(); - content - .text_formats - .extend(new_content.format.iter().cloned()); - } + message.content = Some(new_content.clone()); message.edited_at = Some(edited_at); let buf = rkyv_ser(&message); @@ -82,5 +72,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((UpdateMessageTextResponse {}).into_response()) + Ok(UpdateMessageContentResponse::new().into_response()) } diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 901490f..70969e3 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -2,10 +2,10 @@ use std::{collections::HashSet, io::BufReader, iter, lazy::SyncOnceCell, mem::si use crate::api::{ chat::{ - get_channel_messages_request::Direction, overrides::Reason, permission::has_permission, + attachment::ImageInfo, get_channel_messages_request::Direction, overrides::Reason, + permission::has_permission, send_message_request::attachment::ImageInfo as SendImageInfo, stream_event, Message as HarmonyMessage, *, }, - emote::Emote, exports::hrpc::{server::socket::Socket, Request}, harmonytypes::{item_position, Empty, ItemPosition, Metadata}, sync::{ @@ -169,9 +169,7 @@ impl ChatServer { let initial_subs = initial_subs .chain(iter::once(EventSub::Actions)) .chain(iter::once(EventSub::Homeserver)); - for sub in initial_subs { - subs.insert(sub); - } + subs.extend(initial_subs); // keep track of failed writes and reads to decide if closing the socket is worth it let mut failed_writes: u8 = 0; @@ -395,20 +393,70 @@ impl ChatServer { Ok(()) } - fn send_reaction_event( + fn send_new_reaction_event( &self, guild_id: u64, channel_id: u64, message_id: u64, - reaction: Option, + reaction: Reaction, ) { self.send_event_through_chan( EventSub::Guild(guild_id), - stream_event::Event::ReactionUpdated(stream_event::ReactionUpdated { + stream_event::Event::NewReactionAdded(stream_event::NewReactionAdded { guild_id, channel_id, message_id, - reaction, + reaction: Some(reaction), + }), + Some(PermCheck { + guild_id, + channel_id: Some(channel_id), + check_for: all_permissions::MESSAGES_VIEW, + must_be_guild_owner: false, + }), + EventContext::empty(), + ); + } + + fn send_added_reaction_event( + &self, + guild_id: u64, + channel_id: u64, + message_id: u64, + data: String, + ) { + self.send_event_through_chan( + EventSub::Guild(guild_id), + stream_event::Event::ReactionAdded(stream_event::ReactionAdded { + guild_id, + channel_id, + message_id, + reaction_data: data, + }), + Some(PermCheck { + guild_id, + channel_id: Some(channel_id), + check_for: all_permissions::MESSAGES_VIEW, + must_be_guild_owner: false, + }), + EventContext::empty(), + ); + } + + fn send_removed_reaction_event( + &self, + guild_id: u64, + channel_id: u64, + message_id: u64, + data: String, + ) { + self.send_event_through_chan( + EventSub::Guild(guild_id), + stream_event::Event::ReactionRemoved(stream_event::ReactionRemoved { + guild_id, + channel_id, + message_id, + reaction_data: data, }), Some(PermCheck { guild_id, @@ -452,7 +500,7 @@ impl chat_service_server::ChatService for ChatServer { #[rate(1, 5)] update_all_channel_order, UpdateAllChannelOrderRequest, UpdateAllChannelOrderResponse; #[rate(5, 5)] - update_message_text, UpdateMessageTextRequest, UpdateMessageTextResponse; + update_message_content, UpdateMessageContentRequest, UpdateMessageContentResponse; #[rate(1, 15)] delete_guild, DeleteGuildRequest, DeleteGuildResponse; #[rate(4, 5)] @@ -1207,7 +1255,7 @@ impl ChatTree { name: String, picture: Option, metadata: Option, - kind: guild_kind::Kind, + kind: guild::Kind, ) -> ServerResult { let guild_id = { let mut rng = rand::rngs::SmallRng::from_entropy(); @@ -1223,7 +1271,7 @@ impl ChatTree { picture, owner_ids: vec![user_id], metadata, - kind: Some(GuildKind { kind: Some(kind) }), + kind: kind.into(), }; let buf = rkyv_ser(&guild); @@ -1476,7 +1524,6 @@ impl ChatTree { ) -> Result { let next_id_key = make_next_msg_id_key(guild_id, channel_id); let raw = self - .chat_tree .get(&next_id_key) .await? .expect("no next message id for channel - this is a bug"); @@ -1543,11 +1590,11 @@ impl ChatTree { pub async fn process_image_info( &self, deps: &Dependencies, - info: send_message_request::ImageInfo, + info: SendImageInfo, id: String, file_handle: FileHandle, ) -> Result<(String, ImageInfo), ServerError> { - let send_message_request::ImageInfo { + let SendImageInfo { caption, use_original, } = info; @@ -1747,9 +1794,9 @@ impl ChatTree { avatar: None, }; self.send_message_logic( - 0, guild_id, channel_id, + 0, content, Some(overrides), None, @@ -1758,67 +1805,114 @@ impl ChatTree { .await } - pub async fn update_reaction( + /// Removes a reaction by decrementing the count, if count is zero + /// deletes the reaction from message reactions. + /// + /// Returns `true` if the message was deleted from message reactions. + pub async fn remove_reaction( &self, user_id: u64, guild_id: u64, channel_id: u64, message_id: u64, - emote: Emote, - add: bool, - ) -> ServerResult> { - let react_key = - make_user_reacted_msg_key(guild_id, channel_id, message_id, user_id, &emote.image_id); + data: &str, + ) -> ServerResult { + self.check_guild_user_channel(guild_id, user_id, channel_id) + .await?; + + let react_key = make_user_reacted_msg_key(guild_id, channel_id, message_id, user_id, data); + let reacted = self .chat_tree .contains_key(&react_key) .await .map_err(ServerError::from)?; - if matches!((add, reacted), (true, true) | (false, false)) { - return Ok(None); + if reacted.not() { + bail!(("h.cant-remove-react", "cant remove react if didnt react")); } // TODO: validate the emote image_id is below a certain size + let (mut message, message_key) = self + .get_message_logic(guild_id, channel_id, message_id) + .await?; + + let remove_index = message + .reactions + .iter_mut() + .enumerate() + .find(|(_, r)| r.data == data) + .and_then(|(index, reaction)| { + reaction.count = reaction.count.saturating_sub(1); + (reaction.count == 0).then(|| index) + }); + + if let Some(index) = remove_index { + message.reactions.remove(index); + } + + self.insert(message_key, rkyv_ser(&message)).await?; + self.remove(react_key).await?; + + Ok(remove_index.is_some()) + } + + /// Adds a new reaction by incrementing the count, if the reaction + /// doesn't already exist adds it to the message reactions. + /// + /// Returns `true` if the reaction was new. + #[allow(clippy::too_many_arguments)] + pub async fn add_reaction( + &self, + user_id: u64, + guild_id: u64, + channel_id: u64, + message_id: u64, + data: String, + name: String, + kind: ReactionKind, + ) -> ServerResult { self.check_guild_user_channel(guild_id, user_id, channel_id) .await?; + let react_key = make_user_reacted_msg_key(guild_id, channel_id, message_id, user_id, &data); + + let reacted = self + .chat_tree + .contains_key(&react_key) + .await + .map_err(ServerError::from)?; + if reacted { + bail!(("h.cant-react-multiple", "cant react multiple times")); + } + + // TODO: validate the emote image_id is below a certain size let (mut message, message_key) = self .get_message_logic(guild_id, channel_id, message_id) .await?; - let mut batch = Batch::default(); - let reaction = if let Some(reaction) = message.reactions.iter_mut().find(|r| { - r.emote - .as_ref() - .map_or(false, |e| e.image_id == emote.image_id) - }) { - reaction.count = add - .then(|| reaction.count.saturating_add(1)) - .unwrap_or_else(|| reaction.count.saturating_sub(1)); - if reaction.count == 0 { - batch.remove(react_key); - } - Some(reaction.clone()) - } else if add { + let did_increment = message + .reactions + .iter_mut() + .find(|r| r.data == data) + .map(|reaction| { + reaction.count = reaction.count.saturating_add(1); + }) + .is_some(); + + if did_increment.not() { let reaction = Reaction { count: 1, - emote: Some(emote), + data, + kind: kind.into(), + name, }; - batch.insert(react_key, Vec::new()); - message.reactions.push(reaction.clone()); - Some(reaction) - } else { - None - }; - - batch.insert(message_key, rkyv_ser(&message)); + message.reactions.push(reaction); + } - self.chat_tree - .apply_batch(batch) - .await - .map_err(ServerError::from)?; + self.insert(message_key, rkyv_ser(&message)).await?; + self.insert(react_key, []).await?; - Ok(reaction) + Ok(did_increment.not()) } pub async fn get_pinned_messages_logic( diff --git a/src/impls/mediaproxy/mod.rs b/src/impls/mediaproxy/mod.rs index 18a718b..7f9db49 100644 --- a/src/impls/mediaproxy/mod.rs +++ b/src/impls/mediaproxy/mod.rs @@ -72,6 +72,15 @@ struct TimedCacheValue { since: Instant, } +impl TimedCacheValue { + fn new(value: T) -> Self { + Self { + value, + since: Instant::now(), + } + } +} + // TODO: investigate possible optimization since the key will always be an URL? lazy_static::lazy_static! { static ref CACHE: DashMap, RandomState> = DashMap::with_capacity_and_hasher(512, RandomState::new()); @@ -171,13 +180,7 @@ impl MediaproxyServer { }; // Insert to cache since successful - CACHE.insert( - raw_url, - TimedCacheValue { - value: metadata.clone(), - since: Instant::now(), - }, - ); + CACHE.insert(raw_url, TimedCacheValue::new(metadata.clone())); Ok(metadata) } diff --git a/src/impls/profile/mod.rs b/src/impls/profile/mod.rs index 713cfde..702a9c9 100644 --- a/src/impls/profile/mod.rs +++ b/src/impls/profile/mod.rs @@ -13,6 +13,7 @@ pub mod get_app_data; pub mod get_profile; pub mod set_app_data; pub mod update_profile; +pub mod update_status; #[derive(Clone)] pub struct ProfileServer { @@ -57,6 +58,8 @@ impl ProfileService for ProfileServer { set_app_data, SetAppDataRequest, SetAppDataResponse; #[rate(4, 5)] update_profile, UpdateProfileRequest, UpdateProfileResponse; + #[rate(4, 5)] + update_status, UpdateStatusRequest, UpdateStatusResponse; } } @@ -78,7 +81,7 @@ impl ProfileTree { user_id: u64, new_user_name: Option, new_user_avatar: Option, - new_user_status: Option, + new_user_status: Option, ) -> ServerResult<()> { let key = make_user_profile_key(user_id); @@ -98,7 +101,7 @@ impl ProfileTree { } } if let Some(new_status) = new_user_status { - profile.user_status = new_status; + profile.user_status = Some(new_status); } let buf = rkyv_ser(&profile); diff --git a/src/impls/profile/update_profile.rs b/src/impls/profile/update_profile.rs index 53c9c5d..cdccd42 100644 --- a/src/impls/profile/update_profile.rs +++ b/src/impls/profile/update_profile.rs @@ -10,7 +10,6 @@ pub async fn handler( let UpdateProfileRequest { new_user_name, new_user_avatar, - new_user_status, } = request.into_message().await?; if let Some(username) = new_user_name.as_deref() { @@ -25,7 +24,7 @@ pub async fn handler( user_id, new_user_name.clone(), new_user_avatar.clone(), - new_user_status, + None, ) .await?; @@ -35,8 +34,6 @@ pub async fn handler( user_id, new_username: new_user_name, new_avatar: new_user_avatar, - new_status: new_user_status, - new_account_kind: None, }), None, EventContext::new( diff --git a/src/impls/profile/update_status.rs b/src/impls/profile/update_status.rs new file mode 100644 index 0000000..fd689be --- /dev/null +++ b/src/impls/profile/update_status.rs @@ -0,0 +1,33 @@ +use super::*; + +pub async fn handler( + svc: &ProfileServer, + request: Request, +) -> ServerResult> { + #[allow(unused_variables)] + let user_id = svc.deps.auth(&request).await?; + + let UpdateStatusRequest { new_status } = request.into_message().await?; + + svc.deps + .profile_tree + .update_profile_logic(user_id, None, None, new_status.clone()) + .await?; + + svc.send_event_through_chan( + EventSub::Homeserver, + stream_event::Event::StatusUpdated(StatusUpdated { + user_id, + new_status, + }), + None, + EventContext::new( + svc.deps + .chat_tree + .calculate_users_seeing_user(user_id) + .await?, + ), + ); + + Ok(UpdateStatusResponse::new().into_response()) +} diff --git a/src/main.rs b/src/main.rs index 6bd7df6..8164bae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use std::{ }; use harmony_rust_sdk::api::{ - chat::{guild_kind, ChannelKind, Permission}, + chat::{guild, ChannelKind, Permission}, exports::hrpc::server::transport::{http::Hyper, Transport}, }; use hrpc::{ @@ -330,7 +330,7 @@ async fn setup_admin_guild(deps: &Dependencies) { "Admin".to_string(), None, None, - guild_kind::Kind::Normal(guild_kind::Normal::new()), + guild::Kind::NormalUnspecified, ) .await .unwrap(); From 33d68345966c80c5d5704b4bec30b1ee91a067d8 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 6 Mar 2022 19:42:52 +0300 Subject: [PATCH 14/62] feat: print db version on start --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index 8164bae..13f1c09 100644 --- a/src/main.rs +++ b/src/main.rs @@ -179,6 +179,7 @@ async fn setup_db(db_path: String, config: &Config) -> (Db, usize) { let (current_db_version, needs_migration) = get_db_version(&db) .await .expect("something went wrong while checking if the db needs migrations!!!"); + info!("db version is {}", current_db_version); if needs_migration { // Backup db before attempting to apply migrations if current_db_version > 0 { From 562b4659dd53dc26a249ccbbea3dd41ca2e90060 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 6 Mar 2022 19:46:59 +0300 Subject: [PATCH 15/62] fix: migrations length --- src/db/migration/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/migration/mod.rs b/src/db/migration/mod.rs index 548d7f5..7e51ff5 100644 --- a/src/db/migration/mod.rs +++ b/src/db/migration/mod.rs @@ -22,7 +22,7 @@ mod timestamps_are_milliseconds; type Migration = for<'a> fn(&'a Db) -> BoxFuture<'a, DbResult<()>>; -pub const MIGRATIONS: [Migration; 5] = [ +pub const MIGRATIONS: [Migration; 6] = [ initial_db_version::migrate, add_next_msg_ids::migrate, remove_log_chan_id_from_admin_keys::migrate, From 9132cde5e26240ca8adcf28124ddd4498b869785 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 6 Mar 2022 20:09:56 +0300 Subject: [PATCH 16/62] fix: properly apply migrations for migrate_type --- src/db/migration/mod.rs | 10 ---------- src/db/migration/timestamps_are_milliseconds.rs | 4 +--- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/db/migration/mod.rs b/src/db/migration/mod.rs index 7e51ff5..4135358 100644 --- a/src/db/migration/mod.rs +++ b/src/db/migration/mod.rs @@ -1,6 +1,5 @@ use std::future::Future; -use anyhow::Context; use bytecheck::CheckBytes; use hrpc::server::gen_prelude::BoxFuture; use rkyv::{ @@ -103,15 +102,6 @@ where let new_val = migrate(old); let new_val = rkyv_ser(&new_val); batch.insert(key, new_val); - } else if rkyv::check_archived_root::(&val).is_ok() { - // if it's new, then its already fine - continue; - } else { - old.map_err(|err| anyhow::anyhow!(err.to_string())) - .with_context(|| format!("on tree: {}", tree.name())) - .with_context(|| { - format!("invalid state on key: {}", String::from_utf8_lossy(&key)) - })?; } } tree.apply_batch(batch).await?; diff --git a/src/db/migration/timestamps_are_milliseconds.rs b/src/db/migration/timestamps_are_milliseconds.rs index ecd680e..50479c1 100644 --- a/src/db/migration/timestamps_are_milliseconds.rs +++ b/src/db/migration/timestamps_are_milliseconds.rs @@ -1,8 +1,6 @@ use super::*; -use db::{ - rkyv_ser, Batch -}; +use db::{rkyv_ser, Batch}; use harmony_rust_sdk::api::chat::Message as HarmonyMessage; pub(super) fn migrate(db: &Db) -> BoxFuture<'_, DbResult<()>> { From a6536a706be215709631ba9c093e1873c81a1a57 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 6 Mar 2022 21:11:44 +0300 Subject: [PATCH 17/62] feat: print serving address on startup --- src/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main.rs b/src/main.rs index 13f1c09..20552a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -253,6 +253,12 @@ fn setup_transport( .configure_tls_files(tls_config.cert_file.clone(), tls_config.key_file.clone()); } + info!( + "serving on {}://{}", + deps.config.tls.is_some().then(|| "https").unwrap_or("http"), + addr + ); + transport.configure_hyper( HttpConfig::new() .http1_keep_alive(true) From 33effcc6552a2ebe2e9dfe05162c2edc94794b56 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 9 Mar 2022 19:43:55 +0000 Subject: [PATCH 18/62] chore: add gitpod.yml --- .gitpod.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..f14eeb8 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,4 @@ +tasks: + - init: echo "welcome" + + From 2f2f038f5fb8e46800bf37156b381e8a80e7a260 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 9 Mar 2022 20:05:56 +0000 Subject: [PATCH 19/62] chore: update nix flake --- flake.lock | 109 +++++++++++++++++++++++++++++++++++++++-------------- flake.nix | 22 ----------- 2 files changed, 80 insertions(+), 51 deletions(-) diff --git a/flake.lock b/flake.lock index 3610b27..f932818 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,21 @@ { "nodes": { + "crane": { + "flake": false, + "locked": { + "lastModified": 1644785799, + "narHash": "sha256-VpAJO1L0XeBvtCuNGK4IDKp6ENHIpTrlaZT7yfBCvwo=", + "owner": "ipetkov", + "repo": "crane", + "rev": "fc7a94f841347c88f2cb44217b2a3faa93e2a0b2", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, "devshell": { "inputs": { "flake-utils": "flake-utils", @@ -9,11 +25,11 @@ ] }, "locked": { - "lastModified": 1644227066, - "narHash": "sha256-FHcFZtpZEWnUh62xlyY3jfXAXHzJNEDLDzLsJxn+ve0=", + "lastModified": 1646667754, + "narHash": "sha256-LahZHvCC3UVzGQ55iWDRZkuDssXl1rYgqgScrPV9S38=", "owner": "numtide", "repo": "devshell", - "rev": "7033f64dd9ef8d9d8644c5030c73913351d2b660", + "rev": "59fbe1dfc0de8c3332957c16998a7d16dff365d8", "type": "github" }, "original": { @@ -22,6 +38,57 @@ "type": "github" } }, + "dream2nix": { + "inputs": { + "alejandra": [ + "nixCargoIntegration", + "nixpkgs" + ], + "crane": "crane", + "flake-utils-pre-commit": [ + "nixCargoIntegration", + "nixpkgs" + ], + "gomod2nix": [ + "nixCargoIntegration", + "nixpkgs" + ], + "mach-nix": [ + "nixCargoIntegration", + "nixpkgs" + ], + "nixpkgs": [ + "nixCargoIntegration", + "nixpkgs" + ], + "node2nix": [ + "nixCargoIntegration", + "nixpkgs" + ], + "poetry2nix": [ + "nixCargoIntegration", + "nixpkgs" + ], + "pre-commit-hooks": [ + "nixCargoIntegration", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1646710334, + "narHash": "sha256-eLBcDgcbOUfeH4k6SEW5a5v0PTp2KNCn+5ZXIoWGYww=", + "owner": "nix-community", + "repo": "dream2nix", + "rev": "5dcfbfd3b60ce0208b894c1bdea00e2bdf80ca6a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "main", + "repo": "dream2nix", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1642700792, @@ -37,36 +104,21 @@ "type": "github" } }, - "flakeCompat": { - "flake": false, - "locked": { - "lastModified": 1641205782, - "narHash": "sha256-4jY7RCWUoZ9cKD8co0/4tFARpWB+57+r1bLLvXNJliY=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "b7547d3eed6f32d06102ead8991ec52ab0a4f1a7", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, "nixCargoIntegration": { "inputs": { "devshell": "devshell", + "dream2nix": "dream2nix", "nixpkgs": [ "nixpkgs" ], "rustOverlay": "rustOverlay" }, "locked": { - "lastModified": 1645337413, - "narHash": "sha256-H3hDB9EdU19JVfVMthPgrn3oKJSPxEimykw059CuQD0=", + "lastModified": 1646806291, + "narHash": "sha256-rDhFxUZO9HfFbgxEkqDN73KNkLNE+HArq01j2EAgfu0=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "8c882926b94ca60721d17216d60991fd4988d0c8", + "rev": "7efdaa0f6143fc16de66326cc8d7d695d9dec5e8", "type": "github" }, "original": { @@ -78,11 +130,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1644613700, - "narHash": "sha256-wLRPJclMH8vsHuFtyI78aF09lw5mbi3lMB6uiK5S2wE=", + "lastModified": 1646497237, + "narHash": "sha256-Ccpot1h/rV8MgcngDp5OrdmLTMaUTbStZTR5/sI7zW0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "23d785aa6f853e6cf3430119811c334025bbef55", + "rev": "062a0c5437b68f950b081bbfc8a699d57a4ee026", "type": "github" }, "original": { @@ -94,7 +146,6 @@ }, "root": { "inputs": { - "flakeCompat": "flakeCompat", "nixCargoIntegration": "nixCargoIntegration", "nixpkgs": "nixpkgs" } @@ -102,11 +153,11 @@ "rustOverlay": { "flake": false, "locked": { - "lastModified": 1645323562, - "narHash": "sha256-Zv1s9KKgUmxAJqwnrQeanof5wJr9Hti+7odqXnNbPcY=", + "lastModified": 1646792695, + "narHash": "sha256-2drCXIKIQnJMlTZbcCfuHZAh+iPcdlRkCqtZnA6MHLY=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "5893aa14811d0d982128e3730d1addb17754d436", + "rev": "7f599870402c8d2a5806086c8ee0f2d92b175c54", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 6e4ea13..313e345 100644 --- a/flake.nix +++ b/flake.nix @@ -5,15 +5,10 @@ url = "github:yusdacra/nix-cargo-integration/master"; inputs.nixpkgs.follows = "nixpkgs"; }; - flakeCompat = { - url = "github:edolstra/flake-compat"; - flake = false; - }; }; outputs = inputs: inputs.nixCargoIntegration.lib.makeOutputs { root = ./.; - buildPlatform = "crate2nix"; overrides = { crateOverrides = common: _: { mediasoup-sys = prev: @@ -29,28 +24,11 @@ buildInputs = (prev.buildInputs or [ ]) ++ all; nativeBuildInputs = (prev.nativeBuildInputs or [ ]) ++ all; }; - scherzo = prev: { - crateBin = common.lib.filter (bin: bin.name != "scherzo_migrate" && bin.name != "scherzo_cmd") prev.crateBin; - }; }; shell = common: prev: { packages = prev.packages ++ (with common.pkgs; [ - musl.dev mold mkcert - cargo-deny - /*(common.lib.buildCrate { - memberName = "tokio-console"; - - root = builtins.fetchGit { - url = "https://github.com/tokio-rs/console.git"; - rev = "a30264e0b5469ea596430b846b05e6e3541915d1"; - ref = "main"; - }; - - inherit (common) nativeBuildInputs buildInputs; - CARGO_PKG_REPOSITORY = "https://github.com/tokio-rs/console"; - })*/ ]); commands = prev.commands ++ [ { From 24f1765fbfe66c5b3383ae608d639f8a87f1c0bf Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 9 Mar 2022 20:06:54 +0000 Subject: [PATCH 20/62] chore: fix gitpod.yml init command --- .gitpod.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitpod.yml b/.gitpod.yml index f14eeb8..1ff2f5e 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,4 +1,5 @@ tasks: - - init: echo "welcome" + - init: echo "entering devshell..." + command: nix develop From 03abfe3a00b5346632d9137fecd61a2c61b11394 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Fri, 11 Mar 2022 02:54:04 +0000 Subject: [PATCH 21/62] chore: fix nix flake compat --- flake.lock | 17 +++++++++++++++++ flake.nix | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/flake.lock b/flake.lock index f932818..0caec62 100644 --- a/flake.lock +++ b/flake.lock @@ -104,6 +104,22 @@ "type": "github" } }, + "flakeCompat": { + "flake": false, + "locked": { + "lastModified": 1641205782, + "narHash": "sha256-4jY7RCWUoZ9cKD8co0/4tFARpWB+57+r1bLLvXNJliY=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b7547d3eed6f32d06102ead8991ec52ab0a4f1a7", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "nixCargoIntegration": { "inputs": { "devshell": "devshell", @@ -146,6 +162,7 @@ }, "root": { "inputs": { + "flakeCompat": "flakeCompat", "nixCargoIntegration": "nixCargoIntegration", "nixpkgs": "nixpkgs" } diff --git a/flake.nix b/flake.nix index 313e345..91c69ec 100644 --- a/flake.nix +++ b/flake.nix @@ -5,6 +5,10 @@ url = "github:yusdacra/nix-cargo-integration/master"; inputs.nixpkgs.follows = "nixpkgs"; }; + flakeCompat = { + url = "github:edolstra/flake-compat"; + flake = false; + }; }; outputs = inputs: inputs.nixCargoIntegration.lib.makeOutputs { From 685c7ee6bac4ae611bee8ac4f49fee0e9c859423 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Fri, 11 Mar 2022 03:29:14 +0000 Subject: [PATCH 22/62] fix: check if tls files exist, log an error if they dont and skip enabling tls --- src/main.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 20552a0..6c504b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -249,8 +249,13 @@ fn setup_transport( .layer(against::AgainstLayer); if let Some(tls_config) = deps.config.tls.as_ref() { - transport = transport - .configure_tls_files(tls_config.cert_file.clone(), tls_config.key_file.clone()); + if tls_config.cert_file.exists() && tls_config.key_file.exists() { + transport = transport + .configure_tls_files(tls_config.cert_file.clone(), tls_config.key_file.clone()); + } else { + error!("certificate file and key file specified, but the files don't exist"); + warn!("not enabling TLS"); + } } info!( From 7d263132313d96e0030db567ffa8613f616c7ad3 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Fri, 11 Mar 2022 19:03:49 +0000 Subject: [PATCH 23/62] fix: add catch panic layer to catch some panics --- Cargo.lock | 67 +++++++++++++++++++++++++++++----------------------- Cargo.toml | 1 + src/error.rs | 16 ++++++++----- src/main.rs | 24 ++++++++++++++++++- 4 files changed, 71 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3348ad3..f63ccf7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,9 +45,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.55" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" [[package]] name = "arc-swap" @@ -348,7 +348,7 @@ dependencies = [ [[package]] name = "console-api" version = "0.1.2" -source = "git+https://github.com/tokio-rs/console.git?branch=main#b4e6b6a61eb8fc03a623c7d33a98830c2109fe0d" +source = "git+https://github.com/tokio-rs/console.git?branch=main#3c559121e3c5ad175471718a3cf87ada0146a7cd" dependencies = [ "prost", "prost-types", @@ -360,7 +360,7 @@ dependencies = [ [[package]] name = "console-subscriber" version = "0.1.3" -source = "git+https://github.com/tokio-rs/console.git?branch=main#b4e6b6a61eb8fc03a623c7d33a98830c2109fe0d" +source = "git+https://github.com/tokio-rs/console.git?branch=main#3c559121e3c5ad175471718a3cf87ada0146a7cd" dependencies = [ "console-api", "crossbeam-channel", @@ -600,9 +600,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.10.11" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b279436a715a9de95dcd26b151db590a71961cc06e54918b24fe0dd5b7d3fc4" +checksum = "843c03199d0c0ca54bc1ea90ac0d507274c28abcc4f691ae8b4eaa375087c76a" dependencies = [ "futures-core", "futures-sink", @@ -803,7 +803,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -841,9 +841,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" +checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b" dependencies = [ "bytes", "fnv", @@ -996,9 +996,9 @@ dependencies = [ [[package]] name = "hrpc" -version = "0.33.23" +version = "0.33.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e13cd3bc199b303c4e226eb220fd5456982d2fb20d774bd0a0ff963c8c8e48a" +checksum = "7c0098491f2fa0b6e02e724949097a75057c9b261e74b3d4d08366efec3dc2c3" dependencies = [ "axum-server", "base64", @@ -1163,7 +1163,7 @@ dependencies = [ [[package]] name = "image" version = "0.24.1" -source = "git+https://github.com/image-rs/image.git?branch=master#060a41c491a7b9cb7d1ebb3be5a100c8c3c73972" +source = "git+https://github.com/image-rs/image.git?branch=master#53b9c5cd663cf9527615c8180f20b573a3c3a82a" dependencies = [ "bytemuck", "byteorder", @@ -1224,9 +1224,9 @@ checksum = "0e85a1509a128c855368e135cffcde7eac17d8e1083f41e2b98c58bc1a5074be" [[package]] name = "ipnet" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" +checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" [[package]] name = "itertools" @@ -1499,14 +1499,15 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8" dependencies = [ "libc", "log", "miow", "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", "winapi", ] @@ -1547,9 +1548,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "nanorand" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729eb334247daa1803e0a094d0a5c55711b85571179f5ec6e53eccfdf7008958" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ "getrandom", ] @@ -2078,9 +2079,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -2471,9 +2472,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" @@ -3003,9 +3004,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb284cac1883d54083a0edbdc9cabf931dfed87455f8c7266c01ece6394a43a" +checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" dependencies = [ "bitflags", "bytes", @@ -3034,9 +3035,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" +checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" dependencies = [ "cfg-if", "log", @@ -3047,9 +3048,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" dependencies = [ "proc-macro2", "quote", @@ -3058,9 +3059,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" dependencies = [ "lazy_static", "valuable", @@ -3280,6 +3281,12 @@ version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" version = "0.2.79" diff --git a/Cargo.toml b/Cargo.toml index d8a73c3..54b81fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ tower-http = { version = "0.2", default-features = false, features = [ "sensitive-headers", "map-response-body", "cors", + "catch-panic", ] } multer = { version = "2.0", default-features = false, features = ["tokio-io"] } sled = { version = "0.34.6", features = ["compression"], optional = true } diff --git a/src/error.rs b/src/error.rs index d3ecfb9..4494373 100644 --- a/src/error.rs +++ b/src/error.rs @@ -484,12 +484,7 @@ impl ServerError { let status = self.status(); let err = HrpcError::from(self); - http::Response::builder() - .status(status) - .header(version_header_name(), version_header_value()) - .header(http::header::CONTENT_TYPE, content_header_value()) - .body(box_body(Body::full(encode_protobuf_message(&err).freeze()))) - .unwrap() + hrpc_error_response(err, status) } pub fn into_rest_http_response(self) -> HttpResponse { @@ -500,6 +495,15 @@ impl ServerError { } } +pub fn hrpc_error_response(err: HrpcError, status: StatusCode) -> HttpResponse { + http::Response::builder() + .status(status) + .header(version_header_name(), version_header_value()) + .header(http::header::CONTENT_TYPE, content_header_value()) + .body(box_body(Body::full(encode_protobuf_message(&err).freeze()))) + .unwrap() +} + pub fn rest_error_response(mut msg: String, status: StatusCode) -> HttpResponse { msg.insert_str(0, "{ message: \""); msg.push_str("\" }"); diff --git a/src/main.rs b/src/main.rs index 6c504b3..4dbf343 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; use std::{ + any::Any, net::SocketAddr, path::{Path, PathBuf}, time::Duration, @@ -24,7 +25,7 @@ use hrpc::{ MakeRoutes, }, }; -use hyper::header; +use hyper::{header, StatusCode}; use scherzo::{ api::chat::Content, config::Config, @@ -32,6 +33,7 @@ use scherzo::{ migration::{apply_migrations, get_db_version}, Db, }, + error::hrpc_error_response, impls::{ admin_action, against, chat::{AdminGuildKeys, DEFAULT_ROLE_ID}, @@ -42,6 +44,7 @@ use scherzo::{ }; use tower::limit::ConcurrencyLimitLayer; use tower_http::{ + catch_panic::CatchPanicLayer, cors::CorsLayer, map_response_body::MapResponseBodyLayer, sensitive_headers::SetSensitiveRequestHeadersLayer, @@ -230,6 +233,25 @@ fn setup_transport( .expect("failed to create transport") .layer(cors) .layer(MapResponseBodyLayer::new(box_body)) + .layer(CatchPanicLayer::custom(|err: Box| { + let err = err + .downcast_ref::() + .map(String::clone) + .or_else(|| err.downcast_ref::<&str>().map(|s| s.to_string())); + + if let Some(err) = &err { + tracing::error!("service panicked: {}", err); + } else { + tracing::error!("service panicked but unable to extract error message"); + } + + hrpc_error_response( + hrpc::proto::Error::new_internal_server_error( + err.unwrap_or_else(|| "unknown".to_string()), + ), + StatusCode::INTERNAL_SERVER_ERROR, + ) + })) .layer(concurrency_limiter) .layer(SetSensitiveRequestHeadersLayer::new([ header::AUTHORIZATION, From 449264225c7b2849a10e1b88213938d55fe20682 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Fri, 11 Mar 2022 20:28:59 +0000 Subject: [PATCH 24/62] refactor: implement opt_fut --- src/impls/chat/messages/send_message.rs | 15 +++++++-------- src/utils/mod.rs | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/impls/chat/messages/send_message.rs b/src/impls/chat/messages/send_message.rs index 5a0583c..0ca8319 100644 --- a/src/impls/chat/messages/send_message.rs +++ b/src/impls/chat/messages/send_message.rs @@ -1,3 +1,5 @@ +use hrpc::exports::futures_util::FutureExt; + use crate::impls::admin_action; use super::*; @@ -46,14 +48,11 @@ pub async fn handler( ) .await?; - let action_content = if let Some(action) = admin_action { - let msg = admin_action::run(svc.deps.as_ref(), action) - .await - .unwrap_or_else(|err| format!("error: {}", err)); - Some(msg) - } else { - None - }; + let action_content = opt_fut(admin_action.map(|action| { + admin_action::run(svc.deps.as_ref(), action) + .map(|err| err.unwrap_or_else(|err| format!("error: {}", err))) + })) + .await; svc.send_event_through_chan( EventSub::Guild(guild_id), diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 064c160..e9db072 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,6 +4,8 @@ pub mod http_ratelimit; pub mod ratelimit; pub mod test; +use std::future::Future; + use hrpc::exports::{bytes::Bytes, http}; use hyper::HeaderMap; use rand::Rng; @@ -75,3 +77,15 @@ pub fn get_content_length(headers: &HeaderMap) -> http::HeaderValue { http::HeaderValue::from_maybe_shared_unchecked(Bytes::from_static(b"0")) }) } + +pub fn opt_fut(fut: Option) -> impl Future> +where + FutIn: Future, +{ + async { + match fut { + Some(fut) => Some(fut.await), + None => None, + } + } +} From 9f27b0d6e09528164dd9c2db6ab03f2f8307d585 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Fri, 11 Mar 2022 21:09:00 +0000 Subject: [PATCH 25/62] fix: disable inline vec variant for evec for now --- src/utils/evec.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/utils/evec.rs b/src/utils/evec.rs index 2e4c7e7..d2d8219 100644 --- a/src/utils/evec.rs +++ b/src/utils/evec.rs @@ -6,7 +6,7 @@ use sled::IVec; #[derive(Debug, Clone)] pub enum EVec { - #[cfg(feature = "sled")] + #[cfg(feature = "sledaa")] Inline(IVec), Owned(AlignedVec), } @@ -20,7 +20,7 @@ impl Default for EVec { impl From for AlignedVec { fn from(evec: EVec) -> Self { match evec { - #[cfg(feature = "sled")] + #[cfg(feature = "sledaa")] EVec::Inline(inline) => { let mut vec = AlignedVec::with_capacity(inline.len()); vec.extend_from_slice(inline.as_ref()); @@ -34,7 +34,7 @@ impl From for AlignedVec { impl From for Vec { fn from(evec: EVec) -> Self { match evec { - #[cfg(feature = "sled")] + #[cfg(feature = "sledaa")] EVec::Inline(inline) => inline.to_vec(), EVec::Owned(owned) => owned.into_vec(), } @@ -50,7 +50,8 @@ impl From for EVec { #[cfg(feature = "sled")] impl From for EVec { fn from(ivec: IVec) -> Self { - let vec: AlignedVec = EVec::Inline(ivec).into(); + let mut vec = AlignedVec::with_capacity(ivec.len()); + vec.extend_from_slice(ivec.as_ref()); EVec::Owned(vec) } } @@ -59,6 +60,7 @@ impl From for EVec { impl From for IVec { fn from(evec: EVec) -> Self { match evec { + #[cfg(feature = "sledaa")] EVec::Inline(ivec) => ivec, EVec::Owned(vec) => vec.into_vec().into(), } @@ -98,7 +100,7 @@ impl From<[u8; N]> for EVec { impl AsRef<[u8]> for EVec { fn as_ref(&self) -> &[u8] { match self { - #[cfg(feature = "sled")] + #[cfg(feature = "sledaa")] EVec::Inline(inline) => inline.as_ref(), EVec::Owned(owned) => owned.as_slice(), } @@ -108,7 +110,7 @@ impl AsRef<[u8]> for EVec { impl AsMut<[u8]> for EVec { fn as_mut(&mut self) -> &mut [u8] { match self { - #[cfg(feature = "sled")] + #[cfg(feature = "sledaa")] EVec::Inline(inline) => inline.as_mut(), EVec::Owned(owned) => owned.as_mut_slice(), } @@ -146,7 +148,7 @@ impl TryFrom for [u8; N] { fn try_from(v: EVec) -> Result<[u8; N], Self::Error> { match v { - #[cfg(feature = "sled")] + #[cfg(feature = "sledaa")] EVec::Inline(ivec) => ivec.as_ref().try_into().map_err(|_| EVec::Inline(ivec)), EVec::Owned(vec) => vec.as_ref().try_into().map_err(|_| EVec::Owned(vec)), } From f289592e202c32cb613d467b83aec07a8ef3f0b7 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sat, 12 Mar 2022 12:09:08 +0000 Subject: [PATCH 26/62] fix: make serving on log message show http in case of tls error --- src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 4dbf343..952f71a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -270,10 +270,12 @@ fn setup_transport( .layer(rest) .layer(against::AgainstLayer); + let mut enabled_tls = false; if let Some(tls_config) = deps.config.tls.as_ref() { if tls_config.cert_file.exists() && tls_config.key_file.exists() { transport = transport .configure_tls_files(tls_config.cert_file.clone(), tls_config.key_file.clone()); + enabled_tls = true; } else { error!("certificate file and key file specified, but the files don't exist"); warn!("not enabling TLS"); @@ -282,7 +284,7 @@ fn setup_transport( info!( "serving on {}://{}", - deps.config.tls.is_some().then(|| "https").unwrap_or("http"), + enabled_tls.then(|| "https").unwrap_or("http"), addr ); From 73e192322f3d5baea9021bdc245d7e88dc92c891 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sat, 12 Mar 2022 16:20:35 +0000 Subject: [PATCH 27/62] chore(deps): update cargo deps --- Cargo.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f63ccf7..81dfd5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -879,7 +879,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9d41463c376dabde7fc6b43d0ca2aba70132d5b6" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#16e79c54de1237d7e93f00d1f1c9279c1332ce2e" dependencies = [ "hrpc-build", "prost-build", @@ -890,7 +890,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9d41463c376dabde7fc6b43d0ca2aba70132d5b6" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#16e79c54de1237d7e93f00d1f1c9279c1332ce2e" dependencies = [ "proc-macro2", "quote", @@ -900,7 +900,7 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9d41463c376dabde7fc6b43d0ca2aba70132d5b6" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#16e79c54de1237d7e93f00d1f1c9279c1332ce2e" dependencies = [ "bytecheck", "harmony_build", @@ -996,9 +996,9 @@ dependencies = [ [[package]] name = "hrpc" -version = "0.33.24" +version = "0.33.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0098491f2fa0b6e02e724949097a75057c9b261e74b3d4d08366efec3dc2c3" +checksum = "010e31ad6a29de8242b895c7d4e2d2457a6d57bf79fc070d0e859beb557f4da6" dependencies = [ "axum-server", "base64", @@ -1410,9 +1410,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "matchit" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9376a4f0340565ad675d11fc1419227faf5f60cd7ac9cb2e7185a471f30af833" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" [[package]] name = "mediasoup" From fcf6b466425c08a3cbc3c579c7552da73d6cbc2e Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 13 Mar 2022 18:30:57 +0000 Subject: [PATCH 28/62] feat: improve image processing error and logging, get format using infer --- src/error.rs | 9 ++++- src/impls/chat/mod.rs | 94 ++++++++++++++++++++++++++++++------------- src/impls/media.rs | 10 +++++ src/utils/mod.rs | 1 + 4 files changed, 83 insertions(+), 31 deletions(-) diff --git a/src/error.rs b/src/error.rs index 4494373..ad27d5e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -128,6 +128,7 @@ pub enum ServerError { InvalidEmailConfig(toml::de::Error), FailedToFetchLink(reqwest::Error), FailedToDownload(reqwest::Error), + ImageProcessError(image::ImageError), } impl StdError for ServerError { @@ -144,6 +145,7 @@ impl StdError for ServerError { ServerError::FailedToFetchLink(err) => Some(err), ServerError::FailedToDownload(err) => Some(err), ServerError::InvalidEmailConfig(err) => Some(err), + ServerError::ImageProcessError(err) => Some(err), _ => None, } } @@ -153,6 +155,7 @@ impl Display for ServerError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { travel_error(f, self); match self { + ServerError::ImageProcessError(_) => f.write_str("could not process image"), ServerError::InvalidEmailConfig(_) => f.write_str("invalid email config"), ServerError::InvalidProtoMessage(err) => { write!(f, "couldn't decode a response body: {}", err) @@ -378,7 +381,8 @@ impl ServerError { | ServerError::MultipartError(_) | ServerError::InvalidEmailConfig(_) | ServerError::FailedToFetchLink(_) - | ServerError::FailedToDownload(_) => StatusCode::INTERNAL_SERVER_ERROR, + | ServerError::FailedToDownload(_) + | ServerError::ImageProcessError(_) => StatusCode::INTERNAL_SERVER_ERROR, ServerError::TooFast(_) => StatusCode::TOO_MANY_REQUESTS, ServerError::MediaNotFound | ServerError::LinkNotFound(_) => StatusCode::NOT_FOUND, ServerError::NotImplemented => StatusCode::NOT_IMPLEMENTED, @@ -399,7 +403,8 @@ impl ServerError { | ServerError::InvalidProtoMessage(_) | ServerError::InvalidEmailConfig(_) | ServerError::FailedToFetchLink(_) - | ServerError::FailedToDownload(_) => HrpcErrorIdentifier::InternalServerError.as_id(), + | ServerError::FailedToDownload(_) + | ServerError::ImageProcessError(_) => HrpcErrorIdentifier::InternalServerError.as_id(), ServerError::Unauthenticated => "h.blank-session", ServerError::InvalidAuthId => "h.bad-auth-id", ServerError::UserAlreadyExists => "h.already-registered", diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 70969e3..f5e522d 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -1,4 +1,7 @@ -use std::{collections::HashSet, io::BufReader, iter, lazy::SyncOnceCell, mem::size_of, ops::Not}; +use std::{ + collections::HashSet, io::BufReader, iter, lazy::SyncOnceCell, mem::size_of, ops::Not, + path::Path, +}; use crate::api::{ chat::{ @@ -16,7 +19,7 @@ use crate::api::{ Event as DispatchEvent, }, }; -use image::GenericImageView; +use image::{GenericImageView, ImageFormat}; use rand::{Rng, SeedableRng}; use scherzo_derive::*; use smol_str::SmolStr; @@ -1600,35 +1603,56 @@ impl ChatTree { } = info; let media_root = &deps.config.media.media_root; - - let is_animated = file_handle.mime == "image/gif"; - let is_webp = file_handle.mime == "image/webp"; - - let raw = file_handle.read().await?; + let get_format = |path: &Path| { + Result::<_, ServerError>::Ok( + infer::get_from_path(path)? + .and_then(|t| ImageFormat::from_mime_type(t.mime_type())) + .expect("unsupported image format"), + ) + }; // TODO: improve this code let minithumbnail_id = format!("{}_jpegthumb", id); let minithumbnail_path = media_root.join(&minithumbnail_id); + let id = use_original .not() .then(|| format!("{}_jpeg", id)) .unwrap_or(id); + let image_path = media_root.join(&id); + let image_format = + ImageFormat::from_mime_type(&file_handle.mime).expect("unsupported image format"); + + let is_animated = image_format == ImageFormat::Gif; + let is_webp = image_format == ImageFormat::WebP; + + let read_raw_fn = file_handle.read_std().await; + let id_ = id.clone(); let task_fn = move || -> Result<_, ServerError> { + let _guard = + tracing::debug_span!("image_processing", id = %id_, format = ?image_format) + .entered(); if image_path.exists() && minithumbnail_path.exists() { - let ifile = std::fs::File::open(&image_path)?; - let ifile = BufReader::new(ifile); - let ireader = image::io::Reader::new(ifile).with_guessed_format()?; + use image::io::Reader as ImageReader; + + tracing::debug!("loading existing processed image and thumbnail"); + + let image_format = get_format(&image_path)?; + let ifile = BufReader::new(std::fs::File::open(&image_path)?); + let mut ireader = ImageReader::new(ifile); + ireader.set_format(image_format); let idimensions = ireader .into_dimensions() - .map_err(|_| ServerError::InternalServerError)?; + .map_err(ServerError::ImageProcessError)?; - let minireader = - image::io::Reader::open(&minithumbnail_path)?.with_guessed_format()?; + let minithumbnail_format = get_format(&minithumbnail_path)?; + let mut minireader = ImageReader::open(&minithumbnail_path)?; + minireader.set_format(minithumbnail_format); let minisize = minireader .into_dimensions() - .map_err(|_| ServerError::InternalServerError)?; + .map_err(ServerError::ImageProcessError)?; let minithumbnail = Minithumbnail { width: minisize.0, @@ -1638,14 +1662,21 @@ impl ChatTree { Ok((idimensions, minithumbnail)) } else { + tracing::debug!("loading original image and processing"); + + let raw = read_raw_fn()?; + let image = is_webp .then(|| { let decoder = webp::Decoder::new(&raw); decoder.decode().map(|i| i.to_image()) }) - .flatten() - .or_else(|| image::load_from_memory(&raw).ok()) - .ok_or(ServerError::InternalServerError)?; + .flatten(); + let image = match image { + Some(img) => img, + None => image::load_from_memory_with_format(&raw, image_format) + .map_err(ServerError::ImageProcessError)?, + }; let image_size = image.dimensions(); let minithumbnail = image.thumbnail(64, 64); @@ -1679,7 +1710,7 @@ impl ChatTree { let ((width, height), minithumbnail) = tokio::task::spawn_blocking(task_fn) .await - .map_err(|_| ServerError::InternalServerError)??; + .expect("image process task panicked")?; let info = ImageInfo { width, @@ -1700,19 +1731,24 @@ impl ChatTree { ) -> Result<(String, Option), ServerError> { use send_message_request::attachment::Info; - let Some(info) = info else { - return Ok((id, None)); - }; - - let (id, info) = match info { - Info::Image(info) => { - let (id, info) = self.process_image_info(deps, info, id, file_handle).await?; + if let Some(info) = info { + let (id, info) = match info { + Info::Image(info) => { + let (id, info) = self.process_image_info(deps, info, id, file_handle).await?; - (id, attachment::Info::Image(info)) - } - }; + (id, attachment::Info::Image(info)) + } + }; - Ok((id, Some(info))) + Ok((id, Some(info))) + } else if file_handle.mime != "image/svg+xml" && file_handle.mime.starts_with("image") { + let (id, info) = self + .process_image_info(deps, SendImageInfo::default(), id, file_handle) + .await?; + Ok((id, Some(attachment::Info::Image(info)))) + } else { + Ok((id, None)) + } } pub async fn process_attachment( diff --git a/src/impls/media.rs b/src/impls/media.rs index 83019e1..6dac2f3 100644 --- a/src/impls/media.rs +++ b/src/impls/media.rs @@ -1,5 +1,6 @@ use std::{ fs::Metadata, + io::Read, path::{Path, PathBuf}, }; @@ -30,6 +31,15 @@ impl FileHandle { self.file.read_to_end(&mut raw).await?; Ok(raw) } + + pub async fn read_std(self) -> impl FnOnce() -> Result, ServerError> { + let mut file = self.file.into_std().await; + move || { + let mut raw = Vec::with_capacity(self.size as usize); + file.read_to_end(&mut raw)?; + Ok(raw) + } + } } pub struct MediaStore { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index e9db072..831e718 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -8,6 +8,7 @@ use std::future::Future; use hrpc::exports::{bytes::Bytes, http}; use hyper::HeaderMap; +use image::ImageFormat; use rand::Rng; pub use ratelimit::rate_limit; From e3467d215ac555d5640a1aacadeebf81fd9fd5e4 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 14 Mar 2022 18:39:16 +0000 Subject: [PATCH 29/62] fix: correct FileHandle read behaviour --- Cargo.lock | 12 +++++++----- Cargo.toml | 4 ++-- src/impls/chat/mod.rs | 4 +--- src/impls/media.rs | 22 ++++++++-------------- src/impls/rest/download.rs | 2 +- 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81dfd5d..a22e6fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1163,7 +1163,8 @@ dependencies = [ [[package]] name = "image" version = "0.24.1" -source = "git+https://github.com/image-rs/image.git?branch=master#53b9c5cd663cf9527615c8180f20b573a3c3a82a" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db207d030ae38f1eb6f240d5a1c1c88ff422aa005d10f8c6c6fc5e75286ab30e" dependencies = [ "bytemuck", "byteorder", @@ -1333,9 +1334,9 @@ dependencies = [ [[package]] name = "libwebp-sys" -version = "0.2.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e70c064738b35a28fd6f991d27c0d9680353641d167ae3702a8228dd8272ef6" +checksum = "439fd1885aa28937e7edcd68d2e793cb4a22f8733460d2519fbafd2b215672bf" dependencies = [ "cc", ] @@ -3365,8 +3366,9 @@ dependencies = [ [[package]] name = "webp" -version = "0.2.0" -source = "git+https://github.com/yusdacra/webp.git?branch=master#8f721ef1c7fd90da57a66132667b1d99484653f6" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f80f6a431ea17cbe9d6958628e553c17d22df62b301b39940a9dfd60f3dd7c6" dependencies = [ "image", "libwebp-sys", diff --git a/Cargo.toml b/Cargo.toml index 54b81fc..341c06e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,8 +119,8 @@ lazy_static = "1.4" smol_str = { version = "0.1", features = ["serde"] } git-version = "0.3" triomphe = { version = "0.1", default-features = false } -image = { git = "https://github.com/image-rs/image.git", branch = "master" } -webp = { git = "https://github.com/yusdacra/webp.git", branch = "master" } +image = "0.24" +webp = "0.2" infer = "0.7" anyhow = "1" diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index f5e522d..05954f0 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -1627,8 +1627,6 @@ impl ChatTree { let is_animated = image_format == ImageFormat::Gif; let is_webp = image_format == ImageFormat::WebP; - let read_raw_fn = file_handle.read_std().await; - let id_ = id.clone(); let task_fn = move || -> Result<_, ServerError> { let _guard = @@ -1664,7 +1662,7 @@ impl ChatTree { } else { tracing::debug!("loading original image and processing"); - let raw = read_raw_fn()?; + let raw = file_handle.read_blocking()?; let image = is_webp .then(|| { diff --git a/src/impls/media.rs b/src/impls/media.rs index 6dac2f3..b27b2dc 100644 --- a/src/impls/media.rs +++ b/src/impls/media.rs @@ -1,6 +1,5 @@ use std::{ fs::Metadata, - io::Read, path::{Path, PathBuf}, }; @@ -17,7 +16,7 @@ use crate::{config::MediaConfig, utils::gen_rand_inline_str, ServerError}; const SEPERATOR: u8 = b'\n'; pub struct FileHandle { - pub file: File, + pub file: BufReader, pub metadata: Metadata, pub name: String, pub mime: String, @@ -32,13 +31,8 @@ impl FileHandle { Ok(raw) } - pub async fn read_std(self) -> impl FnOnce() -> Result, ServerError> { - let mut file = self.file.into_std().await; - move || { - let mut raw = Vec::with_capacity(self.size as usize); - file.read_to_end(&mut raw)?; - Ok(raw) - } + pub fn read_blocking(self) -> Result, ServerError> { + tokio::runtime::Handle::current().block_on(self.read()) } } @@ -97,8 +91,8 @@ impl MediaStore { pub async fn get_file(&self, id: &str) -> Result { let is_jpeg = is_id_jpeg(id); - let (mut file, metadata, file_path) = self.get_file_handle(id).await?; - let (filename_raw, mimetype_raw, _) = read_bufs(&file_path, &mut file, is_jpeg).await?; + let (file, metadata, file_path) = self.get_file_handle(id).await?; + let (filename_raw, mimetype_raw, buf_file) = read_bufs(&file_path, file, is_jpeg).await?; let (start, end) = calculate_range(&filename_raw, &mimetype_raw, &metadata, is_jpeg); @@ -106,7 +100,7 @@ impl MediaStore { let name = String::from_utf8_lossy(&filename_raw).into_owned(); Ok(FileHandle { - file, + file: buf_file, metadata, mime, name, @@ -131,9 +125,9 @@ impl MediaStore { pub async fn read_bufs<'file>( path: &Path, - file: &'file mut File, + file: File, is_jpeg: bool, -) -> Result<(Vec, Vec, BufReader<&'file mut File>), ServerError> { +) -> Result<(Vec, Vec, BufReader), ServerError> { if is_jpeg { let mimetype = infer::get_from_path(path).ok().flatten().map_or_else( || b"image/jpeg".to_vec(), diff --git a/src/impls/rest/download.rs b/src/impls/rest/download.rs index 6700cc5..14429cb 100644 --- a/src/impls/rest/download.rs +++ b/src/impls/rest/download.rs @@ -190,7 +190,7 @@ pub fn handler(deps: Arc) -> RateLimit { fn file_handle_to_data(handle: FileHandle) -> (HeaderValue, HeaderValue, Body, HeaderValue) { let stream = Body::wrap_stream(file_stream( - handle.file, + handle.file.into_inner(), optimal_buf_size(&handle.metadata), handle.range, )); From bef636396fffe565d62197382080d1a5fedea52d Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 16 Mar 2022 14:27:53 +0000 Subject: [PATCH 30/62] chore(deps): update cargo deps --- Cargo.lock | 85 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a22e6fb..ef81169 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,9 +124,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" dependencies = [ "async-stream-impl", "futures-core", @@ -134,9 +134,9 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" dependencies = [ "proc-macro2", "quote", @@ -195,7 +195,7 @@ dependencies = [ "hyper", "pin-project-lite", "rustls 0.20.4", - "rustls-pemfile", + "rustls-pemfile 0.2.1", "tokio", "tokio-rustls 0.23.2", "tower-service", @@ -348,7 +348,7 @@ dependencies = [ [[package]] name = "console-api" version = "0.1.2" -source = "git+https://github.com/tokio-rs/console.git?branch=main#3c559121e3c5ad175471718a3cf87ada0146a7cd" +source = "git+https://github.com/tokio-rs/console.git?branch=main#9178ecf02f094f8b23dc26f02faaba4ec09fd8f5" dependencies = [ "prost", "prost-types", @@ -360,7 +360,7 @@ dependencies = [ [[package]] name = "console-subscriber" version = "0.1.3" -source = "git+https://github.com/tokio-rs/console.git?branch=main#3c559121e3c5ad175471718a3cf87ada0146a7cd" +source = "git+https://github.com/tokio-rs/console.git?branch=main#9178ecf02f094f8b23dc26f02faaba4ec09fd8f5" dependencies = [ "console-api", "crossbeam-channel", @@ -416,9 +416,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +checksum = "fdbfe11fe19ff083c48923cf179540e8cd0535903dc35e178a1fdeeb59aef51f" dependencies = [ "cfg-if", "crossbeam-utils", @@ -437,10 +437,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ + "autocfg", "cfg-if", "crossbeam-utils", "lazy_static", @@ -450,9 +451,9 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd435b205a4842da59efd07628f921c096bc1cc0a156835b4fa0bcb9a19bcce" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" dependencies = [ "cfg-if", "crossbeam-utils", @@ -460,9 +461,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if", "lazy_static", @@ -879,7 +880,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#16e79c54de1237d7e93f00d1f1c9279c1332ce2e" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f55ede29b9c54aaebc64ea3d3217c1c74c9f3b1f" dependencies = [ "hrpc-build", "prost-build", @@ -890,7 +891,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#16e79c54de1237d7e93f00d1f1c9279c1332ce2e" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f55ede29b9c54aaebc64ea3d3217c1c74c9f3b1f" dependencies = [ "proc-macro2", "quote", @@ -900,7 +901,7 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#16e79c54de1237d7e93f00d1f1c9279c1332ce2e" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f55ede29b9c54aaebc64ea3d3217c1c74c9f3b1f" dependencies = [ "bytecheck", "harmony_build", @@ -1309,7 +1310,7 @@ dependencies = [ "quoted_printable", "regex", "rustls 0.20.4", - "rustls-pemfile", + "rustls-pemfile 0.2.1", "tokio", "tokio-rustls 0.23.2", "webpki-roots 0.22.2", @@ -1317,9 +1318,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.119" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09" [[package]] name = "libsqlite3-sys" @@ -1570,13 +1571,12 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "7.1.0" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ "memchr", "minimal-lexical", - "version_check", ] [[package]] @@ -2115,9 +2115,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.9" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" +checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" dependencies = [ "async-compression", "base64", @@ -2139,7 +2139,7 @@ dependencies = [ "pin-project-lite", "rustls 0.20.4", "rustls-native-certs", - "rustls-pemfile", + "rustls-pemfile 0.3.0", "serde", "serde_json", "serde_urlencoded", @@ -2170,9 +2170,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.35" +version = "0.7.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cdcf5caf69bcc87b1e3f5427b4f21a32fdd53c2847687bdf9861abb1cdaa0d8" +checksum = "5230ae2981a885590b0dc84e0b24c0ed23ad24f7adc0eb824b26cafa961f7c36" dependencies = [ "bytecheck", "hashbrown 0.12.0", @@ -2184,9 +2184,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.35" +version = "0.7.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cf557da1f81b8c7e889c59c9c3abaf6978f7feb156b9579e4f8bf6d7a2bada" +checksum = "0fc752d5925dbcb324522f3a4c93193d17f107b2e11810913aa3ad352fa01480" dependencies = [ "proc-macro2", "quote", @@ -2225,7 +2225,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 0.2.1", "schannel", "security-framework", ] @@ -2239,6 +2239,15 @@ dependencies = [ "base64", ] +[[package]] +name = "rustls-pemfile" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360" +dependencies = [ + "base64", +] + [[package]] name = "ryu" version = "1.0.9" @@ -2673,9 +2682,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.86" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "ebd69e719f31e88618baa1eaa6ee2de5c9a1c004f1e9ecdb58e8352a13f20a01" dependencies = [ "proc-macro2", "quote", @@ -3366,9 +3375,9 @@ dependencies = [ [[package]] name = "webp" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f80f6a431ea17cbe9d6958628e553c17d22df62b301b39940a9dfd60f3dd7c6" +checksum = "cf022f821f166079a407d000ab57e84de020e66ffbbf4edde999bc7d6e371cae" dependencies = [ "image", "libwebp-sys", @@ -3515,9 +3524,9 @@ checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] From 90f809b0acd830af66959e6f1f8df5d4efa18832 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 16 Mar 2022 15:34:30 +0000 Subject: [PATCH 31/62] refactor(sync): seperate pull_events and push_events into functions, rewrite initial logic --- Cargo.lock | 6 +- Cargo.toml | 1 + src/impls/sync/mod.rs | 231 ++++++++++++++++++++++++------------------ 3 files changed, 137 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef81169..6982f4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -437,11 +437,10 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.8" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" dependencies = [ - "autocfg", "cfg-if", "crossbeam-utils", "lazy_static", @@ -2282,6 +2281,7 @@ dependencies = [ "argon2", "bytecheck", "console-subscriber", + "crossbeam-epoch", "dashmap", "ed25519-compact", "git-version", diff --git a/Cargo.toml b/Cargo.toml index 341c06e..5643162 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -111,6 +111,7 @@ tracing-opentelemetry = { version = "0.17" } pin-project = "1" +crossbeam-epoch = "=0.9.7" dashmap = "=4.0" webpage = { git = "https://github.com/yusdacra/webpage-rs.git", branch = "chore/deps", default-features = false } paste = "1.0" diff --git a/src/impls/sync/mod.rs b/src/impls/sync/mod.rs index c59b535..d8ee3cf 100644 --- a/src/impls/sync/mod.rs +++ b/src/impls/sync/mod.rs @@ -12,7 +12,7 @@ use hrpc::exports::futures_util::TryFutureExt; use hrpc::{client::transport::http::Hyper, encode::encode_protobuf_message}; use hyper::{http::HeaderValue, Uri}; use tokio::sync::mpsc::UnboundedReceiver; -use tracing::error; +use tracing::{error, Instrument}; use crate::key::{self, Manager as KeyManager}; @@ -28,9 +28,14 @@ pub struct EventDispatch { pub event: Event, } -struct Clients(DashMap, RandomState>); +#[derive(Clone)] +pub struct Clients(Arc, RandomState>>); impl Clients { + fn new() -> Self { + Self(Arc::new(DashMap::default())) + } + fn get_client( &self, host: SmolStr, @@ -50,109 +55,139 @@ pub struct SyncServer { } impl SyncServer { - pub fn new(deps: Arc, mut dispatch_rx: UnboundedReceiver) -> Self { - let sync = Self { deps }; - let sync2 = sync.clone(); - let clients = Clients(DashMap::default()); - - tokio::spawn(async move { - let span = tracing::info_span!("federation_sync_task"); - let _guard = span.enter(); - loop { - tokio::select! { - _ = async { - let hosts = sync2.deps.sync_tree.scan_prefix(HOST_PREFIX).await.flat_map(|res| { - let key = match res { - Ok((key, _)) => key, - Err(err) => { - let err = ServerError::DbError(err); - error!("error occured while getting hosts for sync: {}", err); - return None; - } - }; - let (_, host_raw) = key.split_at(HOST_PREFIX.len()); - let host = unsafe { std::str::from_utf8_unchecked(host_raw) }; - Some(SmolStr::new(host)) - }); - - for host in hosts { - if sync2.is_host_allowed(&host).is_ok() { - let mut client = clients.get_client(host.clone()); - if let Ok(queue) = sync2 - .generate_request(PullRequest {}) - .map_err(|_| ()) - .and_then(|req| { - client.pull(req).map_err(|_| ()) - }).and_then(|resp| { - resp.into_message().map_err(|_| ()) - }) - .await - { - for event in queue.event_queue { - if let Err(err) = sync2.push_logic(&host, event).await { - error!("error while executing sync event: {}", err); - } - } - } + pub async fn pull_events(&self, clients: &Clients) { + let hosts = self + .deps + .sync_tree + .scan_prefix(HOST_PREFIX) + .await + .flat_map(|res| { + let key = match res { + Ok((key, _)) => key, + Err(err) => { + let err = ServerError::DbError(err); + error!("error occured while getting hosts for sync: {}", err); + return None; + } + }; + let (_, host_raw) = key.split_at(HOST_PREFIX.len()); + let host = unsafe { std::str::from_utf8_unchecked(host_raw) }; + Some(SmolStr::new(host)) + }); + + for host in hosts { + if self.is_host_allowed(&host).is_ok() { + tracing::debug!("pulling from host {host}"); + let mut client = clients.get_client(host.clone()); + if let Ok(queue) = self + .generate_request(PullRequest {}) + .map_err(|_| ()) + .and_then(|req| client.pull(req).map_err(|_| ())) + .and_then(|resp| resp.into_message().map_err(|_| ())) + .await + { + for event in queue.event_queue { + if let Err(err) = self.push_logic(&host, event).await { + error!("error while executing sync event: {}", err); + } + } + } + } + } + } + + pub async fn push_events( + &self, + clients: &Clients, + dispatch_rx: &mut UnboundedReceiver, + ) { + while let Some(EventDispatch { host, event }) = dispatch_rx.recv().await { + if self.is_host_allowed(&host).is_ok() { + match self.get_event_queue_raw(&host).await { + Ok(raw_queue) => { + let maybe_arch_queue = raw_queue + .as_ref() + .map(|raw_queue| rkyv_arch::(raw_queue)); + if !maybe_arch_queue.map_or(false, |v| v.event_queue.is_empty()) { + let queue = maybe_arch_queue.map_or_else(PullResponse::default, |v| { + v.deserialize(&mut rkyv::Infallible).unwrap() + }); + if let Err(err) = self.push_to_event_queue(&host, queue, event).await { + error!("error while pushing to event queue: {}", err); } + continue; + } + + let mut client = clients.get_client(host.clone()); + let mut push_result = self + .generate_request(PushRequest { + event: Some(event.clone()), + }) + .map_err(|_| ()) + .and_then(|req| client.push(req).map_err(|_| ())) + .await; + let mut try_count = 0; + while try_count < 5 && push_result.is_err() { + push_result = self + .generate_request(PushRequest { + event: Some(event.clone()), + }) + .map_err(|_| ()) + .and_then(|req| client.push(req).map_err(|_| ())) + .await; + try_count += 1; } - tokio::time::sleep(Duration::from_secs(60)).await; - } => {} - _ = async { - while let Some(EventDispatch { host, event }) = dispatch_rx.recv().await { - if sync2.is_host_allowed(&host).is_ok() { - match sync2.get_event_queue_raw(&host).await { - Ok(raw_queue) => { - let maybe_arch_queue = raw_queue.as_ref().map(|raw_queue| rkyv_arch::(raw_queue)); - if !maybe_arch_queue.map_or(false, |v| v.event_queue.is_empty()) { - let queue = maybe_arch_queue.map_or_else( - PullResponse::default, - |v| v.deserialize(&mut rkyv::Infallible).unwrap() - ); - if let Err(err) = sync2.push_to_event_queue(&host, queue, event).await { - error!("error while pushing to event queue: {}", err); - } - continue; - } - - let mut client = clients.get_client(host.clone()); - let mut push_result = sync2 - .generate_request(PushRequest { event: Some(event.clone()) }) - .map_err(|_| ()) - .and_then(|req| { - client.push(req).map_err(|_| ()) - }) - .await; - let mut try_count = 0; - while try_count < 5 && push_result.is_err() { - push_result = sync2 - .generate_request(PushRequest { event: Some(event.clone()) }) - .map_err(|_| ()) - .and_then(|req| { - client.push(req).map_err(|_| ()) - }) - .await; - try_count += 1; - } - - if push_result.is_err() { - let queue = maybe_arch_queue.map_or_else( - PullResponse::default, - |v| v.deserialize(&mut rkyv::Infallible).unwrap() - ); - if let Err(err) = sync2.push_to_event_queue(&host, queue, event).await { - error!("error while pushing to event queue: {}", err); - } - } - } - Err(err) => error!("error occured while getting event queue: {}", err), - } + if push_result.is_err() { + let queue = maybe_arch_queue.map_or_else(PullResponse::default, |v| { + v.deserialize(&mut rkyv::Infallible).unwrap() + }); + if let Err(err) = self.push_to_event_queue(&host, queue, event).await { + error!("error while pushing to event queue: {}", err); } } - } => {} + } + Err(err) => error!("error occured while getting event queue: {}", err), } } + } + } + + pub fn new(deps: Arc, mut dispatch_rx: UnboundedReceiver) -> Self { + let sync = Self { deps }; + let clients = Clients::new(); + + let (initial_pull_tx, initial_pull_rx) = tokio::sync::oneshot::channel(); + + tokio::spawn({ + let clients = clients.clone(); + let sync = sync.clone(); + let fut = async move { + tracing::info!("started task"); + sync.pull_events(&clients).await; + initial_pull_tx + .send(()) + .expect("failed to send initial pull complete notification"); + loop { + tokio::time::sleep(Duration::from_secs(60)).await; + sync.pull_events(&clients).await; + } + }; + fut.instrument(tracing::info_span!("federation_pull_task")) + }); + + tokio::spawn({ + let sync = sync.clone(); + let fut = async move { + tracing::info!("started task"); + initial_pull_rx + .await + .expect("failed to get initial pull complete notification"); + loop { + sync.push_events(&clients, &mut dispatch_rx).await; + } + }; + fut.instrument(tracing::info_span!("federation_push_task")) }); sync From 3647952887f12ffc2803444ea6c2d9197dfd3896 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 16 Mar 2022 15:38:48 +0000 Subject: [PATCH 32/62] refactor(sync): set tokio task names for federation tasks --- src/impls/sync/mod.rs | 62 +++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/impls/sync/mod.rs b/src/impls/sync/mod.rs index d8ee3cf..645c057 100644 --- a/src/impls/sync/mod.rs +++ b/src/impls/sync/mod.rs @@ -159,36 +159,40 @@ impl SyncServer { let (initial_pull_tx, initial_pull_rx) = tokio::sync::oneshot::channel(); - tokio::spawn({ - let clients = clients.clone(); - let sync = sync.clone(); - let fut = async move { - tracing::info!("started task"); - sync.pull_events(&clients).await; - initial_pull_tx - .send(()) - .expect("failed to send initial pull complete notification"); - loop { - tokio::time::sleep(Duration::from_secs(60)).await; + tokio::task::Builder::new() + .name("federation_pull_task") + .spawn({ + let clients = clients.clone(); + let sync = sync.clone(); + let fut = async move { + tracing::info!("started task"); sync.pull_events(&clients).await; - } - }; - fut.instrument(tracing::info_span!("federation_pull_task")) - }); - - tokio::spawn({ - let sync = sync.clone(); - let fut = async move { - tracing::info!("started task"); - initial_pull_rx - .await - .expect("failed to get initial pull complete notification"); - loop { - sync.push_events(&clients, &mut dispatch_rx).await; - } - }; - fut.instrument(tracing::info_span!("federation_push_task")) - }); + initial_pull_tx + .send(()) + .expect("failed to send initial pull complete notification"); + loop { + tokio::time::sleep(Duration::from_secs(60)).await; + sync.pull_events(&clients).await; + } + }; + fut.instrument(tracing::info_span!("federation_pull_task")) + }); + + tokio::task::Builder::new() + .name("federation_push_task") + .spawn({ + let sync = sync.clone(); + let fut = async move { + tracing::info!("started task"); + initial_pull_rx + .await + .expect("failed to get initial pull complete notification"); + loop { + sync.push_events(&clients, &mut dispatch_rx).await; + } + }; + fut.instrument(tracing::info_span!("federation_push_task")) + }); sync } From 77277a93206fe5eb6d0909446a257d6f842f74a6 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 16 Mar 2022 16:06:34 +0000 Subject: [PATCH 33/62] chore(sync): add some todos --- src/impls/sync/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/impls/sync/mod.rs b/src/impls/sync/mod.rs index 645c057..0a1189e 100644 --- a/src/impls/sync/mod.rs +++ b/src/impls/sync/mod.rs @@ -55,6 +55,7 @@ pub struct SyncServer { } impl SyncServer { + // TODO: actually print errors here pub async fn pull_events(&self, clients: &Clients) { let hosts = self .deps @@ -96,6 +97,7 @@ impl SyncServer { } } + // TODO: actually print errors here pub async fn push_events( &self, clients: &Clients, @@ -159,6 +161,9 @@ impl SyncServer { let (initial_pull_tx, initial_pull_rx) = tokio::sync::oneshot::channel(); + // TODO: it should probably be made so that when a pull fails for a host, + // we shouldn't try to push anymore events to it until it's pull succeeds again + tokio::task::Builder::new() .name("federation_pull_task") .spawn({ From 799e2a4527b1d509062516554726e1b355f17b3b Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 16 Mar 2022 17:05:45 +0000 Subject: [PATCH 34/62] style: use the new format inline var support --- src/impls/auth/begin_auth.rs | 2 +- src/impls/auth/mod.rs | 6 +++--- src/impls/auth/next_step.rs | 13 +++++-------- src/impls/auth/next_step/email.rs | 2 +- src/impls/auth/next_step/login.rs | 2 +- src/impls/auth/next_step/registration.rs | 2 +- src/impls/auth/step_back.rs | 13 +++++-------- src/impls/auth/stream_steps.rs | 22 ++++++++-------------- src/impls/chat/messages/send_message.rs | 2 +- src/impls/mod.rs | 10 ++++------ src/impls/rest/download.rs | 22 ++++++++++------------ src/impls/rest/upload.rs | 2 +- src/impls/sync/mod.rs | 10 +++++----- 13 files changed, 46 insertions(+), 62 deletions(-) diff --git a/src/impls/auth/begin_auth.rs b/src/impls/auth/begin_auth.rs index aaefe2c..5795030 100644 --- a/src/impls/auth/begin_auth.rs +++ b/src/impls/auth/begin_auth.rs @@ -12,7 +12,7 @@ pub async fn handler( .and_modify(|s| *s = vec![initial_auth_step()]) .or_insert_with(|| vec![initial_auth_step()]); - tracing::debug!("new auth session {}", auth_id); + tracing::debug!("new auth session {auth_id}"); Ok((BeginAuthResponse { auth_id: auth_id.into(), diff --git a/src/impls/auth/mod.rs b/src/impls/auth/mod.rs index 29018e9..ed0c5c3 100644 --- a/src/impls/auth/mod.rs +++ b/src/impls/auth/mod.rs @@ -146,7 +146,7 @@ impl AuthServer { } else if profile.account_kind() != AccountKind::Bot && auth_how_old >= SESSION_EXPIRE { - tracing::debug!("user {} session has expired", id); + tracing::debug!("user {id} session has expired"); batch.remove(auth_key); batch.remove(token_key(id)); batch.remove(atime_key(id)); @@ -161,11 +161,11 @@ impl AuthServer { .await .map_err(ServerError::DbError) { - tracing::error!("error applying auth token batch: {}", err); + tracing::error!("error applying auth token batch: {err}"); } } Err(err) => { - tracing::error!("error scanning tree for tokens: {}", err); + tracing::error!("error scanning tree for tokens: {err}"); } } diff --git a/src/impls/auth/next_step.rs b/src/impls/auth/next_step.rs index ad49ee7..d914a43 100644 --- a/src/impls/auth/next_step.rs +++ b/src/impls/auth/next_step.rs @@ -80,7 +80,7 @@ pub async fn handler( }); }; - tracing::debug!("handling form '{}'", title); + tracing::debug!("handling form '{title}'"); let mut values = Vec::with_capacity(fields.len()); @@ -120,9 +120,9 @@ pub async fn handler( drop(step_stack); if let Some(chan) = svc.send_step.get(auth_id.as_str()) { - tracing::debug!("sending next step: {:?}", next_step); + tracing::debug!("sending next step: {next_step:?}"); if let Err(err) = chan.send(next_step.clone()).await { - tracing::error!("failed to send auth step: {}", err); + tracing::error!("failed to send auth step: {err}"); } } else { tracing::debug!("no stream found, pushing to queue"); @@ -217,10 +217,7 @@ pub fn handle_choice(svc: &AuthServer, choice: &str) -> ServerResult { step: form("register", fields), } } - choice => bail!(( - "h.invalid-choice", - format!("got invalid choice: {}", choice), - )), + choice => bail!(("h.invalid-choice", format!("got invalid choice: {choice}"),)), }; Ok(step) @@ -292,7 +289,7 @@ pub fn handle_fields( } field => bail!(( "h.invalid-field-type", - format!("got invalid field type: {}", field) + format!("got invalid field type: {field}") )), } } diff --git a/src/impls/auth/next_step/email.rs b/src/impls/auth/next_step/email.rs index 1e26849..d8d8b5a 100644 --- a/src/impls/auth/next_step/email.rs +++ b/src/impls/auth/next_step/email.rs @@ -38,7 +38,7 @@ pub async fn send_token_email( ), ];*/ - let subject = format!("Harmony - {} for {}", action, &deps.config.host); + let subject = format!("Harmony - {action} for {}", &deps.config.host); send_email(deps, to, subject, plain_body, None, Vec::new()).await?; diff --git a/src/impls/auth/next_step/login.rs b/src/impls/auth/next_step/login.rs index eaa2e28..1cb5417 100644 --- a/src/impls/auth/next_step/login.rs +++ b/src/impls/auth/next_step/login.rs @@ -35,7 +35,7 @@ pub async fn handle(svc: &AuthServer, values: &mut Vec) -> ServerResult { - tracing::debug!("received auth step to send to id {}", auth_id); + tracing::debug!("received auth step to send to id {auth_id}"); let end_stream = matches!( step, AuthStep { @@ -59,9 +55,7 @@ pub async fn handler( .await { tracing::error!( - "error occured while sending step to id {}: {}", - auth_id, - err + "error occured while sending step to id {auth_id}: {err}" ); // Break from loop since we errored @@ -84,7 +78,7 @@ pub async fn handler( } svc.send_step.remove(&auth_id); - tracing::debug!("removing stream for id {}", auth_id); + tracing::debug!("removing stream for id {auth_id}"); error.map_or(Ok(()), |err| Err(err.into())) } diff --git a/src/impls/chat/messages/send_message.rs b/src/impls/chat/messages/send_message.rs index 0ca8319..bdffb45 100644 --- a/src/impls/chat/messages/send_message.rs +++ b/src/impls/chat/messages/send_message.rs @@ -50,7 +50,7 @@ pub async fn handler( let action_content = opt_fut(admin_action.map(|action| { admin_action::run(svc.deps.as_ref(), action) - .map(|err| err.unwrap_or_else(|err| format!("error: {}", err))) + .map(|err| err.unwrap_or_else(|err| format!("error: {err}"))) })) .await; diff --git a/src/impls/mod.rs b/src/impls/mod.rs index 7ba3e0c..a6c3313 100644 --- a/src/impls/mod.rs +++ b/src/impls/mod.rs @@ -215,7 +215,7 @@ pub async fn send_email( ) -> ServerResult<()> { let to = to .parse::() - .map_err(|err| ("h.invalid-email", format!("email is invalid: {}", err)))?; + .map_err(|err| ("h.invalid-email", format!("email is invalid: {err}")))?; let from = deps .config .email @@ -259,13 +259,11 @@ pub async fn send_email( .map_err(|err| err.to_string())?; if !response.is_positive() { + let code = response.code(); + let error = response.first_line().unwrap_or("unknown error"); bail!(( "scherzo.mailserver-error", - format!( - "failed to send email (code {}): {}", - response.code(), - response.first_line().unwrap_or("unknown error") - ) + format!("failed to send email (code {code}): {error}") )); } diff --git a/src/impls/rest/download.rs b/src/impls/rest/download.rs index 14429cb..33ce775 100644 --- a/src/impls/rest/download.rs +++ b/src/impls/rest/download.rs @@ -77,7 +77,7 @@ impl Service for DownloadService { let (content_disposition, content_type, content_body, content_length) = match file_id { FileId::External(url) => { - info!("Serving external image from {}", url); + info!("Serving external image from {url}"); let filename = url.path().split('/').last().unwrap_or("unknown"); let disposition = unsafe { disposition_header(filename) }; let resp = match make_request(http_client, url.to_string()).await { @@ -122,14 +122,12 @@ impl Service for DownloadService { } else { // Safety: this is always valid, since HMC is a valid URL let url = unsafe { - format!( - "https://{}:{}/_harmony/media/download/{}", - hmc.server(), - hmc.port(), - hmc.id() - ) - .parse() - .unwrap_unchecked() + let server = hmc.server(); + let port = hmc.port(); + let id = hmc.id(); + format!("https://{server}:{port}/_harmony/media/download/{id}") + .parse() + .unwrap_unchecked() }; let resp = match make_request(http_client, url).await { Ok(resp) => resp, @@ -156,7 +154,7 @@ impl Service for DownloadService { } } FileId::Id(id) => { - info!("Serving local media with id {}", id); + info!("Serving local media with id {id}"); match deps.media.get_file(&id).await { Ok(handle) => file_handle_to_data(handle), Err(err) => return Ok(err.into_rest_http_response()), @@ -202,7 +200,7 @@ fn file_handle_to_data(handle: FileHandle) -> (HeaderValue, HeaderValue, Body, H // SAFETY: the `name` argument MUST ONLY contain ASCII characters. unsafe fn disposition_header(name: &str) -> HeaderValue { - string_header(format!("inline; filename={}", name)) + string_header(format!("inline; filename={name}")) } // SAFETY: the `string` argument MUST ONLY contain ASCII characters. @@ -242,7 +240,7 @@ fn file_stream( let n = match ready!(poll_read_buf(Pin::new(&mut f), cx, &mut buf)) { Ok(n) => n as u64, Err(err) => { - tracing::debug!("file read error: {}", err); + tracing::debug!("file read error: {err}"); return Poll::Ready(Some(Err(err))); } }; diff --git a/src/impls/rest/upload.rs b/src/impls/rest/upload.rs index 376a803..18d6ca0 100644 --- a/src/impls/rest/upload.rs +++ b/src/impls/rest/upload.rs @@ -90,7 +90,7 @@ impl Service for UploadService { Ok(http::Response::builder() .status(StatusCode::OK) .body(box_body(Body::from( - format!(r#"{{ "id": "{}" }}"#, id).into_bytes(), + format!(r#"{{ "id": "{id}" }}"#).into_bytes(), ))) .unwrap()) } diff --git a/src/impls/sync/mod.rs b/src/impls/sync/mod.rs index 0a1189e..43ea4d7 100644 --- a/src/impls/sync/mod.rs +++ b/src/impls/sync/mod.rs @@ -67,7 +67,7 @@ impl SyncServer { Ok((key, _)) => key, Err(err) => { let err = ServerError::DbError(err); - error!("error occured while getting hosts for sync: {}", err); + error!("error occured while getting hosts for sync: {err}"); return None; } }; @@ -89,7 +89,7 @@ impl SyncServer { { for event in queue.event_queue { if let Err(err) = self.push_logic(&host, event).await { - error!("error while executing sync event: {}", err); + error!("error while executing sync event: {err}"); } } } @@ -115,7 +115,7 @@ impl SyncServer { v.deserialize(&mut rkyv::Infallible).unwrap() }); if let Err(err) = self.push_to_event_queue(&host, queue, event).await { - error!("error while pushing to event queue: {}", err); + error!("error while pushing to event queue: {err}"); } continue; } @@ -145,11 +145,11 @@ impl SyncServer { v.deserialize(&mut rkyv::Infallible).unwrap() }); if let Err(err) = self.push_to_event_queue(&host, queue, event).await { - error!("error while pushing to event queue: {}", err); + error!("error while pushing to event queue: {err}"); } } } - Err(err) => error!("error occured while getting event queue: {}", err), + Err(err) => error!("error occured while getting event queue: {err}"), } } } From 72a70a0f1335b3b7bbe38407e71213856d6e06c4 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Thu, 17 Mar 2022 12:52:37 +0000 Subject: [PATCH 35/62] feat(mediaproxy): respect cache-control max-age and no-store --- src/impls/mediaproxy/mod.rs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/impls/mediaproxy/mod.rs b/src/impls/mediaproxy/mod.rs index 7f9db49..aa70b59 100644 --- a/src/impls/mediaproxy/mod.rs +++ b/src/impls/mediaproxy/mod.rs @@ -7,7 +7,7 @@ use dashmap::{mapref::one::Ref, DashMap}; use reqwest::Client as HttpClient; use webpage::HTML; -use std::time::Instant; +use std::{ops::Not, time::Instant}; use super::{get_mimetype, http, prelude::*}; @@ -67,16 +67,20 @@ impl From for HarmonyMetadata { } } +const DEFAULT_MAX_AGE: u64 = 30 * 60; + struct TimedCacheValue { value: T, since: Instant, + max_age: u64, } impl TimedCacheValue { - fn new(value: T) -> Self { + fn new(value: T, max_age: u64) -> Self { Self { value, since: Instant::now(), + max_age, } } } @@ -91,7 +95,7 @@ fn get_from_cache(url: &str) -> Option // Value is available, check if it is expired Some(val) => { // Remove value if it is expired - if val.since.elapsed().as_secs() >= 30 * 60 { + if val.since.elapsed().as_secs() >= val.max_age { drop(val); // explicit drop to tell we don't need it anymore CACHE.remove(url); None @@ -140,6 +144,27 @@ impl MediaproxyServer { .error_for_status() .map_err(ServerError::FailedToFetchLink)?; + let max_age = response + .headers() + .get(&http::header::CACHE_CONTROL) + .and_then(|v| { + let s = v.to_str().ok()?; + let parse_max_age = || { + s.split(',') + .map(str::trim) + .find_map(|item| { + item.strip_prefix("max-age=") + .or_else(|| item.strip_prefix("s-maxage=")) + }) + .and_then(|raw| raw.parse::().ok()) + }; + s.contains("no-store") + .not() + .then(parse_max_age) + .unwrap_or(Some(0)) + }) + .unwrap_or(DEFAULT_MAX_AGE); + let is_html = response .headers() .get(&http::header::CONTENT_TYPE) @@ -180,7 +205,7 @@ impl MediaproxyServer { }; // Insert to cache since successful - CACHE.insert(raw_url, TimedCacheValue::new(metadata.clone())); + CACHE.insert(raw_url, TimedCacheValue::new(metadata.clone(), max_age)); Ok(metadata) } From 7634d36f33a6d54e54751f3ccb86c71acea503fa Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Thu, 17 Mar 2022 14:03:07 +0000 Subject: [PATCH 36/62] refactor: use new method for responses, rename event broadcast to something sane --- src/impls/auth/check_logged_in.rs | 2 +- src/impls/chat/channels/create_channel.rs | 2 +- src/impls/chat/channels/delete_channel.rs | 4 ++-- src/impls/chat/channels/typing.rs | 4 ++-- .../chat/channels/update_all_channel_order.rs | 4 ++-- .../channels/update_channel_information.rs | 4 ++-- .../chat/channels/update_channel_order.rs | 4 ++-- src/impls/chat/guilds/delete_guild.rs | 6 +++--- src/impls/chat/guilds/join_guild.rs | 2 +- src/impls/chat/guilds/leave_guild.rs | 4 ++-- .../chat/guilds/update_guild_information.rs | 4 ++-- src/impls/chat/invites/delete_invite.rs | 2 +- src/impls/chat/messages/delete_message.rs | 4 ++-- src/impls/chat/messages/pin_message.rs | 2 +- src/impls/chat/messages/send_message.rs | 4 ++-- src/impls/chat/messages/unpin_message.rs | 2 +- .../chat/messages/update_message_content.rs | 2 +- src/impls/chat/mod.rs | 12 ++++++------ src/impls/chat/moderation/ban_user.rs | 4 ++-- src/impls/chat/moderation/kick_user.rs | 4 ++-- src/impls/chat/moderation/unban_user.rs | 2 +- src/impls/chat/permissions/add_guild_role.rs | 2 +- .../chat/permissions/delete_guild_role.rs | 4 ++-- .../chat/permissions/give_up_ownership.rs | 2 +- src/impls/chat/permissions/grant_ownership.rs | 2 +- .../chat/permissions/manage_user_roles.rs | 4 ++-- .../chat/permissions/modify_guild_role.rs | 4 ++-- src/impls/chat/permissions/move_role.rs | 4 ++-- src/impls/chat/permissions/set_permissions.rs | 6 +++--- src/impls/emote/add_emote_to_pack.rs | 2 +- src/impls/emote/delete_emote_from_pack.rs | 2 +- src/impls/emote/delete_emote_pack.rs | 2 +- src/impls/emote/dequip_emote_pack.rs | 2 +- src/impls/emote/equip_emote_pack.rs | 2 +- src/impls/mediaproxy/mod.rs | 18 +++++++++++++----- src/impls/profile/set_app_data.rs | 2 +- src/impls/profile/update_profile.rs | 2 +- src/impls/sync/push.rs | 2 +- 38 files changed, 74 insertions(+), 66 deletions(-) diff --git a/src/impls/auth/check_logged_in.rs b/src/impls/auth/check_logged_in.rs index fb00c7e..48fcfec 100644 --- a/src/impls/auth/check_logged_in.rs +++ b/src/impls/auth/check_logged_in.rs @@ -5,5 +5,5 @@ pub async fn handler( request: Request, ) -> Result, HrpcServerError> { svc.deps.auth(&request).await?; - Ok((CheckLoggedInResponse {}).into_response()) + Ok(CheckLoggedInResponse::new().into_response()) } diff --git a/src/impls/chat/channels/create_channel.rs b/src/impls/chat/channels/create_channel.rs index 1276355..686b970 100644 --- a/src/impls/chat/channels/create_channel.rs +++ b/src/impls/chat/channels/create_channel.rs @@ -39,7 +39,7 @@ pub async fn handler( ) .await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::CreatedChannel(stream_event::ChannelCreated { guild_id, diff --git a/src/impls/chat/channels/delete_channel.rs b/src/impls/chat/channels/delete_channel.rs index ad4e5c4..4247ded 100644 --- a/src/impls/chat/channels/delete_channel.rs +++ b/src/impls/chat/channels/delete_channel.rs @@ -53,7 +53,7 @@ pub async fn handler( .await .map_err(ServerError::DbError)?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::DeletedChannel(stream_event::ChannelDeleted { guild_id, @@ -63,5 +63,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((DeleteChannelResponse {}).into_response()) + Ok(DeleteChannelResponse::new().into_response()) } diff --git a/src/impls/chat/channels/typing.rs b/src/impls/chat/channels/typing.rs index 56493e8..fd7fc4d 100644 --- a/src/impls/chat/channels/typing.rs +++ b/src/impls/chat/channels/typing.rs @@ -20,7 +20,7 @@ pub async fn handler( .check_perms(guild_id, Some(channel_id), user_id, "messages.send", false) .await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::Typing(stream_event::Typing { user_id, @@ -36,5 +36,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((TypingResponse {}).into_response()) + Ok(TypingResponse::new().into_response()) } diff --git a/src/impls/chat/channels/update_all_channel_order.rs b/src/impls/chat/channels/update_all_channel_order.rs index c6bfd2b..56a5028 100644 --- a/src/impls/chat/channels/update_all_channel_order.rs +++ b/src/impls/chat/channels/update_all_channel_order.rs @@ -44,7 +44,7 @@ pub async fn handler( let serialized_ordering = chat_tree.serialize_list_u64_logic(channel_ids.clone()); chat_tree.insert(key, serialized_ordering).await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::ChannelsReordered(stream_event::ChannelsReordered { guild_id, @@ -54,5 +54,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((UpdateAllChannelOrderResponse {}).into_response()) + Ok(UpdateAllChannelOrderResponse::new().into_response()) } diff --git a/src/impls/chat/channels/update_channel_information.rs b/src/impls/chat/channels/update_channel_information.rs index 4683d97..e5d2bb3 100644 --- a/src/impls/chat/channels/update_channel_information.rs +++ b/src/impls/chat/channels/update_channel_information.rs @@ -50,7 +50,7 @@ pub async fn handler( let buf = rkyv_ser(&chan_info); chat_tree.insert(key, buf).await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::EditedChannel(stream_event::ChannelUpdated { guild_id, @@ -67,5 +67,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((UpdateChannelInformationResponse {}).into_response()) + Ok(UpdateChannelInformationResponse::new().into_response()) } diff --git a/src/impls/chat/channels/update_channel_order.rs b/src/impls/chat/channels/update_channel_order.rs index d244992..07ddcb1 100644 --- a/src/impls/chat/channels/update_channel_order.rs +++ b/src/impls/chat/channels/update_channel_order.rs @@ -32,7 +32,7 @@ pub async fn handler( .update_channel_order_logic(guild_id, channel_id, Some(position.clone())) .await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::EditedChannelPosition(stream_event::ChannelPositionUpdated { guild_id, @@ -44,5 +44,5 @@ pub async fn handler( ); } - Ok((UpdateChannelOrderResponse {}).into_response()) + Ok(UpdateChannelOrderResponse::new().into_response()) } diff --git a/src/impls/chat/guilds/delete_guild.rs b/src/impls/chat/guilds/delete_guild.rs index e4c47ac..bd21c53 100644 --- a/src/impls/chat/guilds/delete_guild.rs +++ b/src/impls/chat/guilds/delete_guild.rs @@ -35,7 +35,7 @@ pub async fn handler( .await .map_err(ServerError::DbError)?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::DeletedGuild(stream_event::GuildDeleted { guild_id }), None, @@ -60,7 +60,7 @@ pub async fn handler( } } } - svc.send_event_through_chan( + svc.broadcast( EventSub::Homeserver, stream_event::Event::GuildRemovedFromList(stream_event::GuildRemovedFromList { guild_id, @@ -70,5 +70,5 @@ pub async fn handler( EventContext::new(local_ids), ); - Ok((DeleteGuildResponse {}).into_response()) + Ok(DeleteGuildResponse::new().into_response()) } diff --git a/src/impls/chat/guilds/join_guild.rs b/src/impls/chat/guilds/join_guild.rs index 0c4812c..14a6820 100644 --- a/src/impls/chat/guilds/join_guild.rs +++ b/src/impls/chat/guilds/join_guild.rs @@ -44,7 +44,7 @@ pub async fn handler( chat_tree.delete_invite_logic(invite_id).await?; } - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::JoinedMember(stream_event::MemberJoined { guild_id, diff --git a/src/impls/chat/guilds/leave_guild.rs b/src/impls/chat/guilds/leave_guild.rs index 71eef6c..4258b9a 100644 --- a/src/impls/chat/guilds/leave_guild.rs +++ b/src/impls/chat/guilds/leave_guild.rs @@ -22,7 +22,7 @@ pub async fn handler( .await .map_err(ServerError::DbError)?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::LeftMember(stream_event::MemberLeft { guild_id, @@ -35,5 +35,5 @@ pub async fn handler( svc.dispatch_guild_leave(guild_id, user_id).await?; - Ok((LeaveGuildResponse {}).into_response()) + Ok(LeaveGuildResponse::new().into_response()) } diff --git a/src/impls/chat/guilds/update_guild_information.rs b/src/impls/chat/guilds/update_guild_information.rs index 550a0ea..7fb63a2 100644 --- a/src/impls/chat/guilds/update_guild_information.rs +++ b/src/impls/chat/guilds/update_guild_information.rs @@ -44,7 +44,7 @@ pub async fn handler( chat_tree.put_guild_logic(guild_id, guild_info).await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::EditedGuild(stream_event::GuildUpdated { guild_id, @@ -56,5 +56,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((UpdateGuildInformationResponse {}).into_response()) + Ok(UpdateGuildInformationResponse::new().into_response()) } diff --git a/src/impls/chat/invites/delete_invite.rs b/src/impls/chat/invites/delete_invite.rs index 4a42a24..7625961 100644 --- a/src/impls/chat/invites/delete_invite.rs +++ b/src/impls/chat/invites/delete_invite.rs @@ -20,5 +20,5 @@ pub async fn handler( chat_tree.delete_invite_logic(invite_id).await?; - Ok((DeleteInviteResponse {}).into_response()) + Ok(DeleteInviteResponse::new().into_response()) } diff --git a/src/impls/chat/messages/delete_message.rs b/src/impls/chat/messages/delete_message.rs index 764d0a0..2382144 100644 --- a/src/impls/chat/messages/delete_message.rs +++ b/src/impls/chat/messages/delete_message.rs @@ -41,7 +41,7 @@ pub async fn handler( .await .map_err(ServerError::DbError)?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::DeletedMessage(stream_event::MessageDeleted { guild_id, @@ -57,5 +57,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((DeleteMessageResponse {}).into_response()) + Ok(DeleteMessageResponse::new().into_response()) } diff --git a/src/impls/chat/messages/pin_message.rs b/src/impls/chat/messages/pin_message.rs index 8e3fa37..7ae98db 100644 --- a/src/impls/chat/messages/pin_message.rs +++ b/src/impls/chat/messages/pin_message.rs @@ -33,7 +33,7 @@ pub async fn handler( pinned_msgs_raw.extend_from_slice(&message_id.to_be_bytes()); chat_tree.insert(key, pinned_msgs_raw).await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::MessagePinned(stream_event::MessagePinned { guild_id, diff --git a/src/impls/chat/messages/send_message.rs b/src/impls/chat/messages/send_message.rs index bdffb45..88bebc2 100644 --- a/src/impls/chat/messages/send_message.rs +++ b/src/impls/chat/messages/send_message.rs @@ -54,7 +54,7 @@ pub async fn handler( })) .await; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::SentMessage(stream_event::MessageSent { echo_id, @@ -77,7 +77,7 @@ pub async fn handler( let (message_id, message) = chat_tree .send_with_system(guild_id, channel_id, content) .await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::SentMessage(stream_event::MessageSent { echo_id, diff --git a/src/impls/chat/messages/unpin_message.rs b/src/impls/chat/messages/unpin_message.rs index 3638d35..fceeea6 100644 --- a/src/impls/chat/messages/unpin_message.rs +++ b/src/impls/chat/messages/unpin_message.rs @@ -39,7 +39,7 @@ pub async fn handler( .insert(make_pinned_msgs_key(guild_id, channel_id), pinned_msgs_raw) .await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::MessageUnpinned(stream_event::MessageUnpinned { guild_id, diff --git a/src/impls/chat/messages/update_message_content.rs b/src/impls/chat/messages/update_message_content.rs index 927e088..2ae7871 100644 --- a/src/impls/chat/messages/update_message_content.rs +++ b/src/impls/chat/messages/update_message_content.rs @@ -54,7 +54,7 @@ pub async fn handler( let buf = rkyv_ser(&message); chat_tree.insert(key, buf).await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::EditedMessage(stream_event::MessageUpdated { guild_id, diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 05954f0..4682c7c 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -309,7 +309,7 @@ impl ChatServer { } #[inline(always)] - fn send_event_through_chan( + fn broadcast( &self, sub: EventSub, event: stream_event::Event, @@ -354,7 +354,7 @@ impl ChatServer { .chat_tree .remove_guild_from_guild_list(user_id, guild_id, "") .await?; - self.send_event_through_chan( + self.broadcast( EventSub::Homeserver, stream_event::Event::GuildRemovedFromList(stream_event::GuildRemovedFromList { guild_id, @@ -382,7 +382,7 @@ impl ChatServer { .chat_tree .add_guild_to_guild_list(user_id, guild_id, "") .await?; - self.send_event_through_chan( + self.broadcast( EventSub::Homeserver, stream_event::Event::GuildAddedToList(stream_event::GuildAddedToList { guild_id, @@ -403,7 +403,7 @@ impl ChatServer { message_id: u64, reaction: Reaction, ) { - self.send_event_through_chan( + self.broadcast( EventSub::Guild(guild_id), stream_event::Event::NewReactionAdded(stream_event::NewReactionAdded { guild_id, @@ -428,7 +428,7 @@ impl ChatServer { message_id: u64, data: String, ) { - self.send_event_through_chan( + self.broadcast( EventSub::Guild(guild_id), stream_event::Event::ReactionAdded(stream_event::ReactionAdded { guild_id, @@ -453,7 +453,7 @@ impl ChatServer { message_id: u64, data: String, ) { - self.send_event_through_chan( + self.broadcast( EventSub::Guild(guild_id), stream_event::Event::ReactionRemoved(stream_event::ReactionRemoved { guild_id, diff --git a/src/impls/chat/moderation/ban_user.rs b/src/impls/chat/moderation/ban_user.rs index 9f8eadf..642d953 100644 --- a/src/impls/chat/moderation/ban_user.rs +++ b/src/impls/chat/moderation/ban_user.rs @@ -32,7 +32,7 @@ pub async fn handler( ) .await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::LeftMember(stream_event::MemberLeft { guild_id, @@ -45,5 +45,5 @@ pub async fn handler( svc.dispatch_guild_leave(guild_id, user_to_ban).await?; - Ok((BanUserResponse {}).into_response()) + Ok(BanUserResponse::new().into_response()) } diff --git a/src/impls/chat/moderation/kick_user.rs b/src/impls/chat/moderation/kick_user.rs index 9ce4ca8..011ceaa 100644 --- a/src/impls/chat/moderation/kick_user.rs +++ b/src/impls/chat/moderation/kick_user.rs @@ -25,7 +25,7 @@ pub async fn handler( chat_tree.kick_user_logic(guild_id, user_to_kick).await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::LeftMember(stream_event::MemberLeft { guild_id, @@ -38,5 +38,5 @@ pub async fn handler( svc.dispatch_guild_leave(guild_id, user_to_kick).await?; - Ok((KickUserResponse {}).into_response()) + Ok(KickUserResponse::new().into_response()) } diff --git a/src/impls/chat/moderation/unban_user.rs b/src/impls/chat/moderation/unban_user.rs index b14ec2f..63bde64 100644 --- a/src/impls/chat/moderation/unban_user.rs +++ b/src/impls/chat/moderation/unban_user.rs @@ -22,5 +22,5 @@ pub async fn handler( .remove(make_banned_member_key(guild_id, user_to_unban)) .await?; - Ok((UnbanUserResponse {}).into_response()) + Ok(UnbanUserResponse::new().into_response()) } diff --git a/src/impls/chat/permissions/add_guild_role.rs b/src/impls/chat/permissions/add_guild_role.rs index 7ddd167..66b8ddd 100644 --- a/src/impls/chat/permissions/add_guild_role.rs +++ b/src/impls/chat/permissions/add_guild_role.rs @@ -29,7 +29,7 @@ pub async fn handler( pingable, }; let role_id = chat_tree.add_guild_role_logic(guild_id, None, role).await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::RoleCreated(stream_event::RoleCreated { guild_id, diff --git a/src/impls/chat/permissions/delete_guild_role.rs b/src/impls/chat/permissions/delete_guild_role.rs index 34f73f0..c2db6c4 100644 --- a/src/impls/chat/permissions/delete_guild_role.rs +++ b/src/impls/chat/permissions/delete_guild_role.rs @@ -22,7 +22,7 @@ pub async fn handler( .map_err(ServerError::DbError)? .ok_or(ServerError::NoSuchRole { guild_id, role_id })?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::RoleDeleted(stream_event::RoleDeleted { guild_id, role_id }), Some(PermCheck::new( @@ -34,5 +34,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((DeleteGuildRoleResponse {}).into_response()) + Ok(DeleteGuildRoleResponse::new().into_response()) } diff --git a/src/impls/chat/permissions/give_up_ownership.rs b/src/impls/chat/permissions/give_up_ownership.rs index b166e9e..c044809 100644 --- a/src/impls/chat/permissions/give_up_ownership.rs +++ b/src/impls/chat/permissions/give_up_ownership.rs @@ -25,5 +25,5 @@ pub async fn handler( return Err(ServerError::MustNotBeLastOwner.into()); } - Ok((GiveUpOwnershipResponse {}).into_response()) + Ok(GiveUpOwnershipResponse::new().into_response()) } diff --git a/src/impls/chat/permissions/grant_ownership.rs b/src/impls/chat/permissions/grant_ownership.rs index 55b3849..fe15110 100644 --- a/src/impls/chat/permissions/grant_ownership.rs +++ b/src/impls/chat/permissions/grant_ownership.rs @@ -24,5 +24,5 @@ pub async fn handler( guild.owner_ids.push(new_owner_id); chat_tree.put_guild_logic(guild_id, guild).await?; - Ok((GrantOwnershipResponse {}).into_response()) + Ok(GrantOwnershipResponse::new().into_response()) } diff --git a/src/impls/chat/permissions/manage_user_roles.rs b/src/impls/chat/permissions/manage_user_roles.rs index aec1239..e69b45e 100644 --- a/src/impls/chat/permissions/manage_user_roles.rs +++ b/src/impls/chat/permissions/manage_user_roles.rs @@ -30,7 +30,7 @@ pub async fn handler( .manage_user_roles_logic(guild_id, user_to_manage, give_role_ids, take_role_ids) .await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::UserRolesUpdated(stream_event::UserRolesUpdated { guild_id, @@ -41,5 +41,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((ManageUserRolesResponse {}).into_response()) + Ok(ManageUserRolesResponse::new().into_response()) } diff --git a/src/impls/chat/permissions/modify_guild_role.rs b/src/impls/chat/permissions/modify_guild_role.rs index bdd138f..a19f42e 100644 --- a/src/impls/chat/permissions/modify_guild_role.rs +++ b/src/impls/chat/permissions/modify_guild_role.rs @@ -45,7 +45,7 @@ pub async fn handler( let ser_role = rkyv_ser(&role); chat_tree.insert(key, ser_role).await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::RoleUpdated(stream_event::RoleUpdated { guild_id, @@ -64,5 +64,5 @@ pub async fn handler( EventContext::empty(), ); - Ok((ModifyGuildRoleResponse {}).into_response()) + Ok(ModifyGuildRoleResponse::new().into_response()) } diff --git a/src/impls/chat/permissions/move_role.rs b/src/impls/chat/permissions/move_role.rs index 0898cef..8a2efd9 100644 --- a/src/impls/chat/permissions/move_role.rs +++ b/src/impls/chat/permissions/move_role.rs @@ -24,7 +24,7 @@ pub async fn handler( chat_tree .move_role_logic(guild_id, role_id, Some(pos.clone())) .await?; - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::RoleMoved(stream_event::RoleMoved { guild_id, @@ -41,5 +41,5 @@ pub async fn handler( ); } - Ok((MoveRoleResponse {}).into_response()) + Ok(MoveRoleResponse::new().into_response()) } diff --git a/src/impls/chat/permissions/set_permissions.rs b/src/impls/chat/permissions/set_permissions.rs index 7884c0d..320efcf 100644 --- a/src/impls/chat/permissions/set_permissions.rs +++ b/src/impls/chat/permissions/set_permissions.rs @@ -47,7 +47,7 @@ pub async fn handler( } } for perm in &perms_to_give { - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::PermissionUpdated(stream_event::PermissionUpdated { guild_id, @@ -59,7 +59,7 @@ pub async fn handler( EventContext::new(for_users.clone()), ); } - svc.send_event_through_chan( + svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::RolePermsUpdated(stream_event::RolePermissionsUpdated { guild_id, @@ -75,7 +75,7 @@ pub async fn handler( )), EventContext::empty(), ); - Ok((SetPermissionsResponse {}).into_response()) + Ok(SetPermissionsResponse::new().into_response()) } else { Err(ServerError::NoPermissionsSpecified.into()) } diff --git a/src/impls/emote/add_emote_to_pack.rs b/src/impls/emote/add_emote_to_pack.rs index e739c86..00132ee 100644 --- a/src/impls/emote/add_emote_to_pack.rs +++ b/src/impls/emote/add_emote_to_pack.rs @@ -40,5 +40,5 @@ pub async fn handler( EventContext::new(equipped_users), ); - Ok((AddEmoteToPackResponse {}).into_response()) + Ok(AddEmoteToPackResponse::new().into_response()) } diff --git a/src/impls/emote/delete_emote_from_pack.rs b/src/impls/emote/delete_emote_from_pack.rs index d7289a8..ce26851 100644 --- a/src/impls/emote/delete_emote_from_pack.rs +++ b/src/impls/emote/delete_emote_from_pack.rs @@ -33,5 +33,5 @@ pub async fn handler( EventContext::new(equipped_users), ); - Ok((DeleteEmoteFromPackResponse {}).into_response()) + Ok(DeleteEmoteFromPackResponse::new().into_response()) } diff --git a/src/impls/emote/delete_emote_pack.rs b/src/impls/emote/delete_emote_pack.rs index f4a3e06..c7213d7 100644 --- a/src/impls/emote/delete_emote_pack.rs +++ b/src/impls/emote/delete_emote_pack.rs @@ -45,5 +45,5 @@ pub async fn handler( EventContext::new(equipped_users), ); - Ok((DeleteEmotePackResponse {}).into_response()) + Ok(DeleteEmotePackResponse::new().into_response()) } diff --git a/src/impls/emote/dequip_emote_pack.rs b/src/impls/emote/dequip_emote_pack.rs index a9f0bbd..7b7276d 100644 --- a/src/impls/emote/dequip_emote_pack.rs +++ b/src/impls/emote/dequip_emote_pack.rs @@ -20,5 +20,5 @@ pub async fn handler( EventContext::new(vec![user_id]), ); - Ok((DequipEmotePackResponse {}).into_response()) + Ok(DequipEmotePackResponse::new().into_response()) } diff --git a/src/impls/emote/equip_emote_pack.rs b/src/impls/emote/equip_emote_pack.rs index 4bef94a..44daf1e 100644 --- a/src/impls/emote/equip_emote_pack.rs +++ b/src/impls/emote/equip_emote_pack.rs @@ -25,5 +25,5 @@ pub async fn handler( return Err(ServerError::EmotePackNotFound.into()); } - Ok((EquipEmotePackResponse {}).into_response()) + Ok(EquipEmotePackResponse::new().into_response()) } diff --git a/src/impls/mediaproxy/mod.rs b/src/impls/mediaproxy/mod.rs index aa70b59..6186653 100644 --- a/src/impls/mediaproxy/mod.rs +++ b/src/impls/mediaproxy/mod.rs @@ -72,6 +72,7 @@ const DEFAULT_MAX_AGE: u64 = 30 * 60; struct TimedCacheValue { value: T, since: Instant, + /// this corresponds to the `max-age` of `cache-control` header max_age: u64, } @@ -83,6 +84,11 @@ impl TimedCacheValue { max_age, } } + + /// whether this value is stale (and should not be used) or not + fn is_stale(&self) -> bool { + self.since.elapsed().as_secs() >= self.max_age + } } // TODO: investigate possible optimization since the key will always be an URL? @@ -95,7 +101,7 @@ fn get_from_cache(url: &str) -> Option // Value is available, check if it is expired Some(val) => { // Remove value if it is expired - if val.since.elapsed().as_secs() >= val.max_age { + if val.is_stale() { drop(val); // explicit drop to tell we don't need it anymore CACHE.remove(url); None @@ -147,10 +153,11 @@ impl MediaproxyServer { let max_age = response .headers() .get(&http::header::CACHE_CONTROL) - .and_then(|v| { - let s = v.to_str().ok()?; + .and_then(|header| { + let header_str = header.to_str().ok()?; let parse_max_age = || { - s.split(',') + header_str + .split(',') .map(str::trim) .find_map(|item| { item.strip_prefix("max-age=") @@ -158,7 +165,8 @@ impl MediaproxyServer { }) .and_then(|raw| raw.parse::().ok()) }; - s.contains("no-store") + header_str + .contains("no-store") .not() .then(parse_max_age) .unwrap_or(Some(0)) diff --git a/src/impls/profile/set_app_data.rs b/src/impls/profile/set_app_data.rs index a661f10..44f5e7d 100644 --- a/src/impls/profile/set_app_data.rs +++ b/src/impls/profile/set_app_data.rs @@ -12,5 +12,5 @@ pub async fn handler( .insert(make_user_metadata_key(user_id, &app_id), app_data) .await?; - Ok((SetAppDataResponse {}).into_response()) + Ok(SetAppDataResponse::new().into_response()) } diff --git a/src/impls/profile/update_profile.rs b/src/impls/profile/update_profile.rs index cdccd42..d85b002 100644 --- a/src/impls/profile/update_profile.rs +++ b/src/impls/profile/update_profile.rs @@ -44,5 +44,5 @@ pub async fn handler( ), ); - Ok((UpdateProfileResponse {}).into_response()) + Ok(UpdateProfileResponse::new().into_response()) } diff --git a/src/impls/sync/push.rs b/src/impls/sync/push.rs index 815760c..083211f 100644 --- a/src/impls/sync/push.rs +++ b/src/impls/sync/push.rs @@ -22,5 +22,5 @@ pub async fn handler( if let Some(event) = request.into_message().await?.event { svc.push_logic(&host, event).await?; } - Ok((PushResponse {}).into_response()) + Ok(PushResponse::new().into_response()) } From 9c7cac376342bbd957e2e2469c2cf06db07005fc Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sat, 2 Apr 2022 20:13:23 +0000 Subject: [PATCH 37/62] refactor: use bail in more places, change is_user_in_guild to return bool --- src/impls/chat/guilds/join_guild.rs | 6 +++--- src/impls/chat/mod.rs | 10 ++++++++-- src/impls/chat/moderation/ban_user.rs | 4 ++-- src/impls/chat/moderation/kick_user.rs | 6 ++++-- src/impls/chat/permissions/get_user_roles.rs | 4 +++- src/impls/chat/permissions/give_up_ownership.rs | 2 +- src/impls/chat/permissions/grant_ownership.rs | 4 +++- src/impls/chat/permissions/manage_user_roles.rs | 4 +++- src/impls/chat/permissions/modify_guild_role.rs | 2 +- src/utils/mod.rs | 1 - 10 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/impls/chat/guilds/join_guild.rs b/src/impls/chat/guilds/join_guild.rs index 14a6820..574469b 100644 --- a/src/impls/chat/guilds/join_guild.rs +++ b/src/impls/chat/guilds/join_guild.rs @@ -14,15 +14,15 @@ pub async fn handler( let (guild_id, mut invite) = if let Some(raw) = chat_tree.get(&key).await? { db::deser_invite_entry(raw) } else { - return Err(ServerError::NoSuchInvite(invite_id.into()).into()); + bail!(ServerError::NoSuchInvite(invite_id.into())); }; if chat_tree.is_user_banned_in_guild(guild_id, user_id).await? { - return Err(ServerError::UserBanned.into()); + bail!(ServerError::UserBanned); } chat_tree - .is_user_in_guild(guild_id, user_id) + .check_user_in_guild(guild_id, user_id) .await .ok() .map_or(Ok(()), |_| Err(ServerError::UserAlreadyInGuild))?; diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 4682c7c..96a8c7f 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -617,8 +617,14 @@ impl ChatTree { }) } - pub async fn is_user_in_guild(&self, guild_id: u64, user_id: u64) -> ServerResult<()> { + pub async fn is_user_in_guild(&self, guild_id: u64, user_id: u64) -> ServerResult { self.contains_key(&make_member_key(guild_id, user_id)) + .await + .map_err(Into::into) + } + + pub async fn check_user_in_guild(&self, guild_id: u64, user_id: u64) -> ServerResult<()> { + self.is_user_in_guild(guild_id, user_id) .await? .then(|| Ok(())) .unwrap_or(Err(ServerError::UserNotInGuild { guild_id, user_id })) @@ -700,7 +706,7 @@ impl ChatTree { pub async fn check_guild_user(&self, guild_id: u64, user_id: u64) -> ServerResult<()> { self.check_guild(guild_id).await?; - self.is_user_in_guild(guild_id, user_id).await + self.check_user_in_guild(guild_id, user_id).await } #[inline(always)] diff --git a/src/impls/chat/moderation/ban_user.rs b/src/impls/chat/moderation/ban_user.rs index 642d953..fc3eb8a 100644 --- a/src/impls/chat/moderation/ban_user.rs +++ b/src/impls/chat/moderation/ban_user.rs @@ -12,13 +12,13 @@ pub async fn handler( } = request.into_message().await?; if user_id == user_to_ban { - return Err(ServerError::CantKickOrBanYourself.into()); + bail!(ServerError::CantKickOrBanYourself); } let chat_tree = &svc.deps.chat_tree; chat_tree.check_guild_user(guild_id, user_id).await?; - chat_tree.is_user_in_guild(guild_id, user_to_ban).await?; + chat_tree.check_user_in_guild(guild_id, user_to_ban).await?; chat_tree .check_perms(guild_id, None, user_id, "user.manage.ban", false) .await?; diff --git a/src/impls/chat/moderation/kick_user.rs b/src/impls/chat/moderation/kick_user.rs index 011ceaa..c3dc19c 100644 --- a/src/impls/chat/moderation/kick_user.rs +++ b/src/impls/chat/moderation/kick_user.rs @@ -12,13 +12,15 @@ pub async fn handler( } = request.into_message().await?; if user_id == user_to_kick { - return Err(ServerError::CantKickOrBanYourself.into()); + bail!(ServerError::CantKickOrBanYourself); } let chat_tree = &svc.deps.chat_tree; chat_tree.check_guild_user(guild_id, user_id).await?; - chat_tree.is_user_in_guild(guild_id, user_to_kick).await?; + chat_tree + .check_user_in_guild(guild_id, user_to_kick) + .await?; chat_tree .check_perms(guild_id, None, user_id, "user.manage.kick", false) .await?; diff --git a/src/impls/chat/permissions/get_user_roles.rs b/src/impls/chat/permissions/get_user_roles.rs index aad55a4..4e674ec 100644 --- a/src/impls/chat/permissions/get_user_roles.rs +++ b/src/impls/chat/permissions/get_user_roles.rs @@ -26,7 +26,9 @@ pub async fn handler( if user_to_fetch == user_id { fetch_other_user = true; } - chat_tree.is_user_in_guild(guild_id, user_to_fetch).await?; + chat_tree + .check_user_in_guild(guild_id, user_to_fetch) + .await?; } if fetch_other_user { chat_tree diff --git a/src/impls/chat/permissions/give_up_ownership.rs b/src/impls/chat/permissions/give_up_ownership.rs index c044809..9e24f41 100644 --- a/src/impls/chat/permissions/give_up_ownership.rs +++ b/src/impls/chat/permissions/give_up_ownership.rs @@ -22,7 +22,7 @@ pub async fn handler( guild.owner_ids.remove(pos); } } else { - return Err(ServerError::MustNotBeLastOwner.into()); + bail!(ServerError::MustNotBeLastOwner); } Ok(GiveUpOwnershipResponse::new().into_response()) diff --git a/src/impls/chat/permissions/grant_ownership.rs b/src/impls/chat/permissions/grant_ownership.rs index fe15110..a7d52c9 100644 --- a/src/impls/chat/permissions/grant_ownership.rs +++ b/src/impls/chat/permissions/grant_ownership.rs @@ -14,7 +14,9 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree.check_guild_user(guild_id, user_id).await?; - chat_tree.is_user_in_guild(guild_id, new_owner_id).await?; + chat_tree + .check_user_in_guild(guild_id, new_owner_id) + .await?; chat_tree .check_perms(guild_id, None, user_id, "", true) diff --git a/src/impls/chat/permissions/manage_user_roles.rs b/src/impls/chat/permissions/manage_user_roles.rs index e69b45e..4532fc8 100644 --- a/src/impls/chat/permissions/manage_user_roles.rs +++ b/src/impls/chat/permissions/manage_user_roles.rs @@ -16,7 +16,9 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree.check_guild_user(guild_id, user_id).await?; - chat_tree.is_user_in_guild(guild_id, user_to_manage).await?; + chat_tree + .check_user_in_guild(guild_id, user_to_manage) + .await?; chat_tree .check_perms(guild_id, None, user_id, "roles.user.manage", false) .await?; diff --git a/src/impls/chat/permissions/modify_guild_role.rs b/src/impls/chat/permissions/modify_guild_role.rs index a19f42e..cdf8358 100644 --- a/src/impls/chat/permissions/modify_guild_role.rs +++ b/src/impls/chat/permissions/modify_guild_role.rs @@ -26,7 +26,7 @@ pub async fn handler( let mut role = if let Some(raw) = chat_tree.get(key).await? { db::deser_role(raw) } else { - return Err(ServerError::NoSuchRole { guild_id, role_id }.into()); + bail!(ServerError::NoSuchRole { guild_id, role_id }); }; if let Some(new_name) = new_name.clone() { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 831e718..e9db072 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -8,7 +8,6 @@ use std::future::Future; use hrpc::exports::{bytes::Bytes, http}; use hyper::HeaderMap; -use image::ImageFormat; use rand::Rng; pub use ratelimit::rate_limit; From a229f73b30c0bd83ee020d6b8ed3c6e829d4e764 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sat, 2 Apr 2022 23:15:38 +0300 Subject: [PATCH 38/62] chore: update flake deps, format nix files --- default.nix | 16 +++++++------ flake.lock | 42 +++++++++++++++++----------------- flake.nix | 66 ++++++++++++++++++++++++++++------------------------- shell.nix | 16 +++++++------ 4 files changed, 74 insertions(+), 66 deletions(-) diff --git a/default.nix b/default.nix index 78f09ba..054d96c 100644 --- a/default.nix +++ b/default.nix @@ -1,12 +1,14 @@ # Flake's default package for non-flake-enabled nix instances (import ( - let lock = builtins.fromJSON (builtins.readFile ./flake.lock); + let + lock = builtins.fromJSON (builtins.readFile ./flake.lock); in - fetchTarball { - url = - "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flakeCompat.locked.rev}.tar.gz"; - sha256 = lock.nodes.flakeCompat.locked.narHash; - } + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flakeCompat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flakeCompat.locked.narHash; + } ) - { src = ./.; }).defaultNix.default + {src = ./.;}) +.defaultNix +.default diff --git a/flake.lock b/flake.lock index 0caec62..4639fd2 100644 --- a/flake.lock +++ b/flake.lock @@ -25,11 +25,11 @@ ] }, "locked": { - "lastModified": 1646667754, - "narHash": "sha256-LahZHvCC3UVzGQ55iWDRZkuDssXl1rYgqgScrPV9S38=", + "lastModified": 1647857022, + "narHash": "sha256-Aw70NWLOIwKhT60MHDGjgWis3DP3faCzr6ap9CSayek=", "owner": "numtide", "repo": "devshell", - "rev": "59fbe1dfc0de8c3332957c16998a7d16dff365d8", + "rev": "0a5ff74dacb9ea22614f64e61aeb3ca0bf0e7311", "type": "github" }, "original": { @@ -75,16 +75,16 @@ ] }, "locked": { - "lastModified": 1646710334, - "narHash": "sha256-eLBcDgcbOUfeH4k6SEW5a5v0PTp2KNCn+5ZXIoWGYww=", - "owner": "nix-community", + "lastModified": 1648842063, + "narHash": "sha256-9EF3wHY6EHCywPqsahlyUd++yAQI+0G6dZGgKagxgJo=", + "owner": "yusdacra", "repo": "dream2nix", - "rev": "5dcfbfd3b60ce0208b894c1bdea00e2bdf80ca6a", + "rev": "ca6d145e972141f9c08050f0c713163bfc00afb2", "type": "github" }, "original": { - "owner": "nix-community", - "ref": "main", + "owner": "yusdacra", + "ref": "fix/rust-discoverer", "repo": "dream2nix", "type": "github" } @@ -107,11 +107,11 @@ "flakeCompat": { "flake": false, "locked": { - "lastModified": 1641205782, - "narHash": "sha256-4jY7RCWUoZ9cKD8co0/4tFARpWB+57+r1bLLvXNJliY=", + "lastModified": 1648199409, + "narHash": "sha256-JwPKdC2PoVBkG6E+eWw3j6BMR6sL3COpYWfif7RVb8Y=", "owner": "edolstra", "repo": "flake-compat", - "rev": "b7547d3eed6f32d06102ead8991ec52ab0a4f1a7", + "rev": "64a525ee38886ab9028e6f61790de0832aa3ef03", "type": "github" }, "original": { @@ -130,11 +130,11 @@ "rustOverlay": "rustOverlay" }, "locked": { - "lastModified": 1646806291, - "narHash": "sha256-rDhFxUZO9HfFbgxEkqDN73KNkLNE+HArq01j2EAgfu0=", + "lastModified": 1648879890, + "narHash": "sha256-rctrX+JiWWC6RijGm7JjGq/WUYf68b/9gq+6sqEyXro=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "7efdaa0f6143fc16de66326cc8d7d695d9dec5e8", + "rev": "50e24fdbc8414984f514cfa0e0a431e8ddf44367", "type": "github" }, "original": { @@ -146,11 +146,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1646497237, - "narHash": "sha256-Ccpot1h/rV8MgcngDp5OrdmLTMaUTbStZTR5/sI7zW0=", + "lastModified": 1648632716, + "narHash": "sha256-kCmnDeiaMsdhfnNKjxdOzwRh2H6eQb8yWAL+nNabC/Y=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "062a0c5437b68f950b081bbfc8a699d57a4ee026", + "rev": "710fed5a2483f945b14f4a58af2cd3676b42d8c8", "type": "github" }, "original": { @@ -170,11 +170,11 @@ "rustOverlay": { "flake": false, "locked": { - "lastModified": 1646792695, - "narHash": "sha256-2drCXIKIQnJMlTZbcCfuHZAh+iPcdlRkCqtZnA6MHLY=", + "lastModified": 1648866882, + "narHash": "sha256-yMs/RKA9pX47a03zupmQp8/RLRmKzdSDk+h5Yt7K9xU=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "7f599870402c8d2a5806086c8ee0f2d92b175c54", + "rev": "7c90e17cd7c0b9e81d5b23f78b482088ac9961d1", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 91c69ec..64365b1 100644 --- a/flake.nix +++ b/flake.nix @@ -11,40 +11,44 @@ }; }; - outputs = inputs: inputs.nixCargoIntegration.lib.makeOutputs { - root = ./.; - overrides = { - crateOverrides = common: _: { - mediasoup-sys = prev: - let + outputs = inputs: + inputs.nixCargoIntegration.lib.makeOutputs { + root = ./.; + overrides = { + crateOverrides = common: _: { + mediasoup-sys = prev: let pkgs = common.pkgs; - pythonPkgs = pkgs: with pkgs; [ - pip - ]; + pythonPkgs = pkgs: + with pkgs; [ + pip + ]; pythonWithPkgs = pkgs.python3.withPackages pythonPkgs; - all = (with pkgs; [ cmake gnumake nodejs meson ninja ]) ++ [ pythonWithPkgs ]; - in - { - buildInputs = (prev.buildInputs or [ ]) ++ all; - nativeBuildInputs = (prev.nativeBuildInputs or [ ]) ++ all; + all = (with pkgs; [cmake gnumake nodejs meson ninja]) ++ [pythonWithPkgs]; + in { + buildInputs = (prev.buildInputs or []) ++ all; + nativeBuildInputs = (prev.nativeBuildInputs or []) ++ all; }; - }; - shell = common: prev: { - packages = prev.packages ++ (with common.pkgs; [ - mold - mkcert - ]); - commands = prev.commands ++ [ - { - name = "generate-cert"; - command = '' - mkcert localhost 127.0.0.1 ::1 - mv localhost+2.pem cert.pem - mv localhost+2-key.pem key.pem - ''; - } - ]; + }; + shell = common: prev: { + packages = + prev.packages + ++ (with common.pkgs; [ + mold + mkcert + ]); + commands = + prev.commands + ++ [ + { + name = "generate-cert"; + command = '' + mkcert localhost 127.0.0.1 ::1 + mv localhost+2.pem cert.pem + mv localhost+2-key.pem key.pem + ''; + } + ]; + }; }; }; - }; } diff --git a/shell.nix b/shell.nix index bd18cba..8c9a5e6 100644 --- a/shell.nix +++ b/shell.nix @@ -1,12 +1,14 @@ # Flake's devShell for non-flake-enabled nix instances (import ( - let lock = builtins.fromJSON (builtins.readFile ./flake.lock); + let + lock = builtins.fromJSON (builtins.readFile ./flake.lock); in - fetchTarball { - url = - "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flakeCompat.locked.rev}.tar.gz"; - sha256 = lock.nodes.flakeCompat.locked.narHash; - } + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flakeCompat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flakeCompat.locked.narHash; + } ) - { src = ./.; }).shellNix.default + {src = ./.;}) +.shellNix +.default From 6afd1610de75cbfbda1f164d66b89a16f2bd9567 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sat, 2 Apr 2022 23:56:14 +0300 Subject: [PATCH 39/62] chore: bump prost, update cargo deps, update rust toolchain --- Cargo.lock | 323 +++++++++++++++++++++++++++----------------- Cargo.toml | 4 +- rust-toolchain.toml | 2 +- 3 files changed, 205 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6982f4f..9a96b06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,9 +57,9 @@ checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" [[package]] name = "argon2" -version = "0.3.4" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25df3c03f1040d0069fcd3907e24e36d59f9b6fa07ba49be0eb25a794f036ba7" +checksum = "a27e27b63e4a34caee411ade944981136fdfa535522dc9944d6700196cbd899f" dependencies = [ "base64ct", "blake2", @@ -151,9 +151,9 @@ checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" [[package]] name = "async-trait" -version = "0.1.52" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" dependencies = [ "proc-macro2", "quote", @@ -197,7 +197,7 @@ dependencies = [ "rustls 0.20.4", "rustls-pemfile 0.2.1", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls 0.23.3", "tower-service", ] @@ -209,9 +209,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "base64ct" -version = "1.0.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" +checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" [[package]] name = "bit_field" @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead" +checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" [[package]] name = "byteorder" @@ -330,6 +330,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -350,8 +359,8 @@ name = "console-api" version = "0.1.2" source = "git+https://github.com/tokio-rs/console.git?branch=main#9178ecf02f094f8b23dc26f02faaba4ec09fd8f5" dependencies = [ - "prost", - "prost-types", + "prost 0.9.0", + "prost-types 0.9.0", "tonic", "tonic-build", "tracing-core", @@ -368,7 +377,7 @@ dependencies = [ "futures", "hdrhistogram", "humantime", - "prost-types", + "prost-types 0.9.0", "serde", "serde_json", "thread_local", @@ -398,9 +407,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ "libc", ] @@ -416,9 +425,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbfe11fe19ff083c48923cf179540e8cd0535903dc35e178a1fdeeb59aef51f" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ "cfg-if", "crossbeam-utils", @@ -529,6 +538,15 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "email-encoding" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6690291166824e467790ac08ba42f241791567e8337bbf00c5a6e87889629f98" +dependencies = [ + "base64", +] + [[package]] name = "encoding_rs" version = "0.8.30" @@ -796,9 +814,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ "cfg-if", "js-sys", @@ -841,9 +859,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" dependencies = [ "bytes", "fnv", @@ -854,7 +872,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.6.9", + "tokio-util 0.7.1", "tracing", ] @@ -879,10 +897,10 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f55ede29b9c54aaebc64ea3d3217c1c74c9f3b1f" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#b0879d5e5aa9854a18577d135aad1483c0dd2f79" dependencies = [ "hrpc-build", - "prost-build", + "prost-build 0.10.0", "regex", "walkdir", ] @@ -890,7 +908,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f55ede29b9c54aaebc64ea3d3217c1c74c9f3b1f" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#b0879d5e5aa9854a18577d135aad1483c0dd2f79" dependencies = [ "proc-macro2", "quote", @@ -900,14 +918,14 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f55ede29b9c54aaebc64ea3d3217c1c74c9f3b1f" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#b0879d5e5aa9854a18577d135aad1483c0dd2f79" dependencies = [ "bytecheck", "harmony_build", "harmony_derive", "hrpc", "http", - "prost", + "prost 0.10.0", "rkyv", "serde", "urlencoding", @@ -968,6 +986,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -996,9 +1020,9 @@ dependencies = [ [[package]] name = "hrpc" -version = "0.33.27" +version = "0.33.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "010e31ad6a29de8242b895c7d4e2d2457a6d57bf79fc070d0e859beb557f4da6" +checksum = "ec96f52f3fcbd55e0add26fbda0bc6103b15cd3b382db644f653a25d29f9b4eb" dependencies = [ "axum-server", "base64", @@ -1012,8 +1036,8 @@ dependencies = [ "hyper-rustls", "matchit", "pin-project-lite", - "prost", - "prost-build", + "prost 0.10.0", + "prost-build 0.10.0", "sha-1", "tokio", "tokio-tungstenite", @@ -1023,12 +1047,12 @@ dependencies = [ [[package]] name = "hrpc-build" -version = "0.33.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370eb264a57b2841bf588ab01a4de725df1a99a0410956b3010dc3663044f34d" +checksum = "ace803952c7504e41d30016a4e2573cc3f97bdd32479f951eb3e68c2b48d6a24" dependencies = [ "proc-macro2", - "prost-build", + "prost-build 0.10.0", "quote", "syn", ] @@ -1041,9 +1065,9 @@ checksum = "c4b491508ac546892d0218449993ca8def58c98e3cfffa7073fb0f67843ee461" [[package]] name = "html5ever" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b" +checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148" dependencies = [ "log", "mac", @@ -1101,9 +1125,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.17" +version = "0.14.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" dependencies = [ "bytes", "futures-channel", @@ -1134,7 +1158,7 @@ dependencies = [ "rustls 0.20.4", "rustls-native-certs", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls 0.23.3", ] [[package]] @@ -1171,7 +1195,7 @@ dependencies = [ "color_quant", "exr", "gif", - "jpeg-decoder 0.2.2", + "jpeg-decoder 0.2.4", "num-iter", "num-rational", "num-traits", @@ -1182,9 +1206,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" dependencies = [ "autocfg", "hashbrown 0.11.2", @@ -1261,9 +1285,9 @@ checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" [[package]] name = "jpeg-decoder" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "105fb082d64e2100074587f59a74231f771750c664af903f1f9f76c9dedfc6f1" +checksum = "744c24117572563a98a7e9168a5ac1ee4a1ca7f702211258797bbe0ed0346c3c" dependencies = [ "rayon", ] @@ -1291,12 +1315,13 @@ checksum = "7efd1d698db0759e6ef11a7cd44407407399a910c774dd804c64c032da7826ff" [[package]] name = "lettre" -version = "0.10.0-rc.4" +version = "0.10.0-rc.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d8da8f34d086b081c9cc3b57d3bb3b51d16fc06b5c848a188e2f14d58ac2a5" +checksum = "5144148f337be14dabfc0f0d85b691a68ac6c77ef22a5c47c5504b70a7c9fcf3" dependencies = [ "async-trait", "base64", + "email-encoding", "fastrand", "futures-io", "futures-util", @@ -1309,17 +1334,17 @@ dependencies = [ "quoted_printable", "regex", "rustls 0.20.4", - "rustls-pemfile 0.2.1", + "rustls-pemfile 0.3.0", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls 0.23.3", "webpki-roots 0.22.2", ] [[package]] name = "libc" -version = "0.2.120" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "libsqlite3-sys" @@ -1343,19 +1368,20 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg", "scopeguard", "serde", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" dependencies = [ "cfg-if", ] @@ -1417,9 +1443,9 @@ checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" [[package]] name = "mediasoup" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "517582a7a65fefeb305b9a9b9dc711a5f91a28bc0d2f4a52d8bca935a4a7b4aa" +checksum = "447fce54609d17f3a91084cd6911cfb4e0e117a637617054e17a78859c830572" dependencies = [ "async-channel", "async-executor", @@ -1448,9 +1474,9 @@ dependencies = [ [[package]] name = "mediasoup-sys" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83eda72bddffb50bd363b3d598a9c4634f7458be4b5ec67c459b38237b6d301" +checksum = "4475c581332565ff35669f3dbb155a4dbbe227932759c281d78d3d1adbb7f98d" [[package]] name = "memchr" @@ -1500,9 +1526,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" dependencies = [ "libc", "log", @@ -1728,7 +1754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ "lock_api", - "parking_lot_core 0.9.1", + "parking_lot_core 0.9.2", ] [[package]] @@ -1747,9 +1773,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" dependencies = [ "cfg-if", "libc", @@ -1760,9 +1786,9 @@ dependencies = [ [[package]] name = "password-hash" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" +checksum = "aa26fd5c3cd6e6bb83dd9c0cef40fbeb77d7596339ca46c18a6f66919bb07769" dependencies = [ "base64ct", "rand_core", @@ -1781,9 +1807,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" [[package]] name = "paste-impl" @@ -1882,9 +1908,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "png" @@ -1932,7 +1958,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.9.0", +] + +[[package]] +name = "prost" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd5316aa8f5c82add416dfbc25116b84b748a21153f512917e8143640a71bbd" +dependencies = [ + "bytes", + "prost-derive 0.10.0", ] [[package]] @@ -1942,14 +1978,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" dependencies = [ "bytes", - "heck", + "heck 0.3.3", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost 0.9.0", + "prost-types 0.9.0", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-build" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328f9f29b82409216decb172d81e936415d21245befa79cd34c3f29d87d1c50b" +dependencies = [ + "bytes", + "cfg-if", + "cmake", + "heck 0.4.0", "itertools", "lazy_static", "log", "multimap", "petgraph", - "prost", - "prost-types", + "prost 0.10.0", + "prost-types 0.10.0", "regex", "tempfile", "which", @@ -1968,6 +2026,19 @@ dependencies = [ "syn", ] +[[package]] +name = "prost-derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df35198f0777b75e9ff669737c6da5136b59dba33cf5a010a6d1cc4d56defc6f" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "prost-types" version = "0.9.0" @@ -1975,7 +2046,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" dependencies = [ "bytes", - "prost", + "prost 0.9.0", +] + +[[package]] +name = "prost-types" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926681c118ae6e512a3ccefd4abbe5521a14f4cc1e207356d4d00c0b7f2006fd" +dependencies = [ + "bytes", + "prost 0.10.0", ] [[package]] @@ -2000,9 +2081,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" dependencies = [ "proc-macro2", ] @@ -2070,9 +2151,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] @@ -2143,7 +2224,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls 0.23.3", "tokio-util 0.6.9", "url", "wasm-bindgen", @@ -2169,9 +2250,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.36" +version = "0.7.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5230ae2981a885590b0dc84e0b24c0ed23ad24f7adc0eb824b26cafa961f7c36" +checksum = "1f08c8062c1fe1253064043b8fc07bfea1b9702b71b4a86c11ea3588183b12e1" dependencies = [ "bytecheck", "hashbrown 0.12.0", @@ -2183,9 +2264,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.36" +version = "0.7.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc752d5925dbcb324522f3a4c93193d17f107b2e11810913aa3ad352fa01480" +checksum = "e289706df51226e84814bf6ba1a9e1013112ae29bc7a9878f73fce360520c403" dependencies = [ "proc-macro2", "quote", @@ -2300,9 +2381,9 @@ dependencies = [ "opentelemetry", "opentelemetry-jaeger", "parking_lot 0.12.0", - "paste 1.0.6", + "paste 1.0.7", "pin-project", - "prost", + "prost 0.10.0", "rand", "reqwest", "rkyv", @@ -2314,7 +2395,7 @@ dependencies = [ "sqlx", "tikv-jemallocator", "tokio", - "tokio-util 0.7.0", + "tokio-util 0.7.1", "toml", "tower", "tower-http", @@ -2488,9 +2569,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "sled" @@ -2598,7 +2679,7 @@ dependencies = [ "log", "memchr", "once_cell", - "paste 1.0.6", + "paste 1.0.7", "percent-encoding", "rustls 0.19.1", "smallvec", @@ -2620,7 +2701,7 @@ checksum = "eee35713129561f5e55c554bba1c378e2a7e67f81257b7311183de98c50e6f94" dependencies = [ "dotenv", "either", - "heck", + "heck 0.3.3", "once_cell", "proc-macro2", "quote", @@ -2682,9 +2763,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.88" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd69e719f31e88618baa1eaa6ee2de5c9a1c004f1e9ecdb58e8352a13f20a01" +checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" dependencies = [ "proc-macro2", "quote", @@ -2707,9 +2788,9 @@ dependencies = [ [[package]] name = "tendril" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9ef557cb397a4f0a5a3a628f06515f78563f2209e64d47055d9dc6052bf5e33" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" dependencies = [ "futf", "mac", @@ -2876,9 +2957,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.2" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +checksum = "4151fda0cf2798550ad0b34bcfc9b9dcc2a9d2471c895c68f3a8818e54f2389e" dependencies = [ "rustls 0.20.4", "tokio", @@ -2907,7 +2988,7 @@ dependencies = [ "rustls 0.20.4", "rustls-native-certs", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls 0.23.3", "tungstenite", "webpki 0.22.0", ] @@ -2928,16 +3009,16 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1" +checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" dependencies = [ "bytes", "futures-core", "futures-sink", - "log", "pin-project-lite", "tokio", + "tracing", ] [[package]] @@ -2968,8 +3049,8 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost", - "prost-derive", + "prost 0.9.0", + "prost-derive 0.9.0", "tokio", "tokio-stream", "tokio-util 0.6.9", @@ -2987,7 +3068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757" dependencies = [ "proc-macro2", - "prost-build", + "prost-build 0.9.0", "quote", "syn", ] @@ -3006,7 +3087,7 @@ dependencies = [ "rand", "slab", "tokio", - "tokio-util 0.7.0", + "tokio-util 0.7.1", "tower-layer", "tower-service", "tracing", @@ -3069,9 +3150,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" +checksum = "90442985ee2f57c9e1b548ee72ae842f4a9a20e3f417cc38dbc5dc684d9bb4ee" dependencies = [ "lazy_static", "valuable", @@ -3113,9 +3194,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce" +checksum = "b9df98b037d039d03400d9dd06b0f8ce05486b5f25e9a2d7d36196e142ebbc52" dependencies = [ "ansi_term", "sharded-slab", @@ -3439,9 +3520,9 @@ checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e" [[package]] name = "which" -version = "4.2.4" +version = "4.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" dependencies = [ "either", "lazy_static", @@ -3481,9 +3562,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -3494,33 +3575,33 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" [[package]] name = "windows_i686_gnu" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" [[package]] name = "windows_i686_msvc" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" [[package]] name = "windows_x86_64_gnu" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" [[package]] name = "windows_x86_64_msvc" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" [[package]] name = "winreg" diff --git a/Cargo.toml b/Cargo.toml index 5643162..5a6ba03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ harmony_rust_sdk = { git = "https://github.com/harmony-development/harmony_rust_ "rkyv", "rkyv_validation", ] } -prost = { version = "0.9" } +prost = { version = "0.10" } hrpc = { version = "0.33", features = [ "http_server", "http_hyper_client", @@ -83,7 +83,7 @@ itertools = { version = "0.10", default-features = false, features = [ ], optional = true } rand = "0.8" -argon2 = "0.3" +argon2 = "0.4" ed25519-compact = "1" ahash = "0.7" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 32a4fa8..e271ee9 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-02-20" +channel = "nightly-2022-04-02" targets = ["x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl"] \ No newline at end of file From fdfbf36bbb94ddb4726617206cdc28cf73cf0c33 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 3 Apr 2022 22:21:11 +0300 Subject: [PATCH 40/62] feat: update protocol --- Cargo.lock | 6 +- Cargo.toml | 2 +- src/db/migration/proto_v2.rs | 15 +- src/db/mod.rs | 78 ++++++- src/error.rs | 27 ++- src/impls/chat/channels/create_channel.rs | 7 +- src/impls/chat/channels/typing.rs | 11 +- .../channels/update_channel_information.rs | 7 +- .../chat/guilds/create_direct_message.rs | 8 - src/impls/chat/guilds/create_guild.rs | 8 +- .../chat/guilds/create_private_channel.rs | 8 + src/impls/chat/guilds/create_room.rs | 8 - src/impls/chat/guilds/delete_guild.rs | 2 +- src/impls/chat/guilds/mod.rs | 4 +- .../chat/guilds/upgrade_room_to_guild.rs | 8 - src/impls/chat/messages/add_reaction.rs | 4 + src/impls/chat/messages/delete_message.rs | 11 +- .../chat/messages/get_channel_messages.rs | 2 +- src/impls/chat/messages/get_message.rs | 2 +- .../chat/messages/get_pinned_messages.rs | 2 +- src/impls/chat/messages/pin_message.rs | 13 +- src/impls/chat/messages/remove_reaction.rs | 4 + src/impls/chat/messages/send_message.rs | 35 ++-- src/impls/chat/messages/unpin_message.rs | 11 +- .../chat/messages/update_message_content.rs | 13 +- src/impls/chat/mod.rs | 192 ++++++++++++------ src/impls/chat/permissions/add_guild_role.rs | 7 +- .../chat/permissions/delete_guild_role.rs | 7 +- .../chat/permissions/manage_user_roles.rs | 2 +- .../chat/permissions/modify_guild_role.rs | 7 +- src/impls/chat/permissions/move_role.rs | 7 +- src/impls/chat/permissions/set_permissions.rs | 1 - src/impls/mod.rs | 17 +- src/impls/{voice => webrtc}/mod.rs | 16 +- src/impls/{voice => webrtc}/stream_message.rs | 0 src/lib.rs | 1 - 36 files changed, 314 insertions(+), 239 deletions(-) delete mode 100644 src/impls/chat/guilds/create_direct_message.rs create mode 100644 src/impls/chat/guilds/create_private_channel.rs delete mode 100644 src/impls/chat/guilds/create_room.rs delete mode 100644 src/impls/chat/guilds/upgrade_room_to_guild.rs rename src/impls/{voice => webrtc}/mod.rs (96%) rename src/impls/{voice => webrtc}/stream_message.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 9a96b06..5dae350 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -897,7 +897,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#b0879d5e5aa9854a18577d135aad1483c0dd2f79" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#a4de99a9aa35a9c22c20204379cf4feca11275a9" dependencies = [ "hrpc-build", "prost-build 0.10.0", @@ -908,7 +908,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#b0879d5e5aa9854a18577d135aad1483c0dd2f79" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#a4de99a9aa35a9c22c20204379cf4feca11275a9" dependencies = [ "proc-macro2", "quote", @@ -918,7 +918,7 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#b0879d5e5aa9854a18577d135aad1483c0dd2f79" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#a4de99a9aa35a9c22c20204379cf4feca11275a9" dependencies = [ "bytecheck", "harmony_build", diff --git a/Cargo.toml b/Cargo.toml index 5a6ba03..22fd86b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ required-features = ["sled", "sqlite"] [features] default = ["sled"] -voice = ["mediasoup"] +webrtc = ["mediasoup"] jemalloc = ["tikv-jemallocator"] # dbs diff --git a/src/db/migration/proto_v2.rs b/src/db/migration/proto_v2.rs index 18fc7d8..4ecb640 100644 --- a/src/db/migration/proto_v2.rs +++ b/src/db/migration/proto_v2.rs @@ -68,6 +68,7 @@ define_migration!(|db| { metadata: old.metadata.map(Into::into), overrides: old.overrides.map(Into::into), reactions: old.reactions.into_iter().map(Into::into).collect(), + actions: Vec::new(), }) .await?; let profile_tree = db.open_tree(b"profile").await?; @@ -135,9 +136,20 @@ impl From for EmbedHeading { impl From for Action { fn from(old: chat::Action) -> Self { + let info = old + .kind + .as_ref() + .map(|kind| match kind { + chat::action::Kind::Button(old) => old.data.clone(), + chat::action::Kind::Input(old) => old.data.clone(), + _ => Vec::new(), + }) + .unwrap_or_else(Vec::new); + Action { action_type: old.action_type, kind: old.kind.map(Into::into), + info, } } } @@ -146,7 +158,6 @@ impl From for ActionKind { fn from(old: chat::action::Kind) -> Self { match old { chat::action::Kind::Button(old) => ActionKind::Button(ButtonAction { - data: old.data, text: old.text, url: old.url, }), @@ -155,9 +166,9 @@ impl From for ActionKind { label: old.label, }), chat::action::Kind::Input(old) => ActionKind::Input(InputAction { - data: old.data, label: old.label, multiline: old.multiline, + default: None, }), } } diff --git a/src/db/mod.rs b/src/db/mod.rs index 511b051..315bcc4 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -191,10 +191,20 @@ pub mod chat { use super::concat_static; pub const INVITE_PREFIX: &[u8] = b"invite_"; + pub const PRIV_CHANNEL_PREFIX: &[u8] = b"priv_"; pub const ADMIN_GUILD_KEY: &[u8] = b"admin_guild_key_data"; // perms + #[inline(always)] + pub const fn make_guild_key(guild_id: u64) -> [u8; 8] { + guild_id.to_be_bytes() + } + + pub const fn make_pc_key(channel_id: u64) -> [u8; 13] { + concat_static(&[PRIV_CHANNEL_PREFIX, &channel_id.to_be_bytes()]) + } + pub fn make_guild_perm_key(guild_id: u64, role_id: u64, matches: &str) -> Vec { [ &make_role_guild_perms_prefix(guild_id, role_id), @@ -239,14 +249,36 @@ pub mod chat { // message - pub const fn make_pinned_msgs_key(guild_id: u64, channel_id: u64) -> [u8; 18] { + pub const fn make_pinned_msgs_key_guild(guild_id: u64, channel_id: u64) -> [u8; 18] { concat_static(&[&make_chan_key(guild_id, channel_id), &[6]]) } - pub const fn make_next_msg_id_key(guild_id: u64, channel_id: u64) -> [u8; 18] { + pub const fn make_pinned_msgs_key_pc(channel_id: u64) -> [u8; 14] { + concat_static(&[&make_pc_key(channel_id), &[6]]) + } + + pub fn make_pinned_msgs_key(guild_id: Option, channel_id: u64) -> Vec { + guild_id.map_or_else( + || make_pinned_msgs_key_pc(channel_id).to_vec(), + |guild_id| make_pinned_msgs_key_guild(guild_id, channel_id).to_vec(), + ) + } + + pub const fn make_next_msg_id_key_guild(guild_id: u64, channel_id: u64) -> [u8; 18] { concat_static(&[&make_chan_key(guild_id, channel_id), &[7]]) } + pub const fn make_next_msg_id_key_pc(channel_id: u64) -> [u8; 14] { + concat_static(&[&make_pc_key(channel_id), &[7]]) + } + + pub fn make_next_msg_id_key(guild_id: Option, channel_id: u64) -> Vec { + guild_id.map_or_else( + || make_next_msg_id_key_pc(channel_id).to_vec(), + |guild_id| make_next_msg_id_key_guild(guild_id, channel_id).to_vec(), + ) + } + pub const fn make_role_channel_perms_prefix( guild_id: u64, channel_id: u64, @@ -259,17 +291,47 @@ pub mod chat { ]) } + pub const fn make_msg_prefix_pc(channel_id: u64) -> [u8; 13] { + concat_static(&[&make_pc_key(channel_id), &[9]]) + } + pub const fn make_msg_prefix(guild_id: u64, channel_id: u64) -> [u8; 18] { concat_static(&[&make_chan_key(guild_id, channel_id), &[9]]) } - pub const fn make_msg_key(guild_id: u64, channel_id: u64, message_id: u64) -> [u8; 26] { + pub const fn make_msg_key_pc(channel_id: u64, message_id: u64) -> [u8; 21] { + concat_static(&[&make_msg_prefix_pc(channel_id), &message_id.to_be_bytes()]) + } + + pub const fn make_msg_key_guild(guild_id: u64, channel_id: u64, message_id: u64) -> [u8; 26] { concat_static(&[ &make_msg_prefix(guild_id, channel_id), &message_id.to_be_bytes(), ]) } + pub fn make_msg_key(guild_id: Option, channel_id: u64, message_id: u64) -> Vec { + guild_id.map_or_else( + || make_msg_key_pc(channel_id, message_id).to_vec(), + |guild_id| make_msg_key_guild(guild_id, channel_id, message_id).to_vec(), + ) + } + + pub fn make_user_reacted_msg_key_pc( + channel_id: u64, + message_id: u64, + user_id: u64, + data: &str, + ) -> Vec { + [ + make_msg_key_pc(channel_id, message_id).as_ref(), + &[0], + user_id.to_be_bytes().as_ref(), + data.as_bytes(), + ] + .concat() + } + pub fn make_user_reacted_msg_key( guild_id: u64, channel_id: u64, @@ -278,7 +340,7 @@ pub mod chat { data: &str, ) -> Vec { [ - make_msg_key(guild_id, channel_id, message_id).as_ref(), + make_msg_key_guild(guild_id, channel_id, message_id).as_ref(), &[0], user_id.to_be_bytes().as_ref(), data.as_bytes(), @@ -290,6 +352,14 @@ pub mod chat { // member + pub const fn make_pc_mem_prefix(channel_id: u64) -> [u8; 14] { + concat_static(&[&make_pc_key(channel_id), &[8]]) + } + + pub const fn make_member_key_pc(channel_id: u64, user_id: u64) -> [u8; 22] { + concat_static(&[&make_pc_mem_prefix(channel_id), &user_id.to_be_bytes()]) + } + pub const fn make_member_key(guild_id: u64, user_id: u64) -> [u8; 17] { concat_static(&[&make_guild_mem_prefix(guild_id), &user_id.to_be_bytes()]) } diff --git a/src/error.rs b/src/error.rs index ad27d5e..d816118 100644 --- a/src/error.rs +++ b/src/error.rs @@ -54,15 +54,20 @@ pub enum ServerError { guild_id: u64, user_id: u64, }, + UserNotInPrivateChannel { + channel_id: u64, + user_id: u64, + }, Unauthenticated, NotImplemented, NoSuchMessage { - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, }, GuildAlreadyExists(u64), NoSuchGuild(u64), + NoSuchPrivateChannel(u64), ChannelAlreadyExists { guild_id: u64, channel_id: u64, @@ -193,6 +198,12 @@ impl Display for ServerError { ServerError::UserNotInGuild { guild_id, user_id } => { write!(f, "user {} not in guild {}", user_id, guild_id) } + ServerError::UserNotInPrivateChannel { + channel_id, + user_id, + } => { + write!(f, "user {} not in private channel {}", user_id, channel_id) + } ServerError::UserAlreadyExists => f.write_str("user already exists"), ServerError::UserAlreadyInGuild => f.write_str("user already in guild"), ServerError::Unauthenticated => f.write_str("invalid-session"), @@ -220,6 +231,9 @@ impl Display for ServerError { write!(f, "guild {} already exists", guild_id) } ServerError::NoSuchGuild(id) => write!(f, "no such guild with id {}", id), + ServerError::NoSuchPrivateChannel(id) => { + write!(f, "no such private channel with id {}", id) + } ServerError::NoSuchUser(id) => write!(f, "no such user with id {}", id), ServerError::NoSuchMessage { guild_id, @@ -227,7 +241,7 @@ impl Display for ServerError { message_id, } => write!( f, - "no such message {} in channel {} in guild {}", + "no such message {} in channel {} in guild {:?}", message_id, channel_id, guild_id ), ServerError::NoSuchInvite(id) => write!(f, "no such invite with id {}", id), @@ -368,7 +382,9 @@ impl ServerError { ) | ServerError::MustNotBeLastOwner | ServerError::ContentCantBeSentByUser - | ServerError::InvalidProtoMessage(_) => StatusCode::BAD_REQUEST, + | ServerError::InvalidProtoMessage(_) + | ServerError::NoSuchPrivateChannel(_) + | ServerError::UserNotInPrivateChannel { .. } => StatusCode::BAD_REQUEST, ServerError::FederationDisabled | ServerError::HostNotAllowed => StatusCode::FORBIDDEN, ServerError::IoError(_) | ServerError::InternalServerError @@ -426,7 +442,9 @@ impl ServerError { ServerError::WrongStep { .. } => "h.bad-auth-choice", ServerError::WrongTypeForField { .. } => "h.missing-form", ServerError::WrongEmailOrPassword { .. } => "h.bad-password\nh.bad-email", - ServerError::UserNotInGuild { .. } => "h.not-joined", + ServerError::UserNotInGuild { .. } | ServerError::UserNotInPrivateChannel { .. } => { + "h.not-joined" + } ServerError::NotImplemented => HrpcErrorIdentifier::NotImplemented.as_id(), ServerError::ChannelAlreadyExists { .. } => "h.channel-already-exists", ServerError::GuildAlreadyExists(_) => "h.guild-already-exists", @@ -434,6 +452,7 @@ impl ServerError { ServerError::NoSuchChannel { .. } => "h.bad-channel-id", ServerError::UnderSpecifiedChannels => "h.underspecified-channels", ServerError::NoSuchGuild(_) => "h.bad-guild-id", + ServerError::NoSuchPrivateChannel(_) => "h.bad-private-channel-id", ServerError::NoSuchInvite(_) | ServerError::InviteNameEmpty => "h.bad-invite-id", ServerError::NoSuchUser(_) => "h.bad-user-id", ServerError::SessionExpired => "h.bad-session", diff --git a/src/impls/chat/channels/create_channel.rs b/src/impls/chat/channels/create_channel.rs index 686b970..3a91398 100644 --- a/src/impls/chat/channels/create_channel.rs +++ b/src/impls/chat/channels/create_channel.rs @@ -49,12 +49,7 @@ pub async fn handler( kind, metadata, }), - Some(PermCheck::new( - guild_id, - Some(channel_id), - "messages.view", - false, - )), + Some(PermCheck::new(guild_id, Some(channel_id), "messages.view")), EventContext::empty(), ); diff --git a/src/impls/chat/channels/typing.rs b/src/impls/chat/channels/typing.rs index fd7fc4d..9bc3899 100644 --- a/src/impls/chat/channels/typing.rs +++ b/src/impls/chat/channels/typing.rs @@ -14,25 +14,20 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree - .check_guild_user_channel(guild_id, user_id, channel_id) + .check_channel_user(guild_id, user_id, channel_id) .await?; chat_tree .check_perms(guild_id, Some(channel_id), user_id, "messages.send", false) .await?; svc.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::Typing(stream_event::Typing { user_id, guild_id, channel_id, }), - Some(PermCheck::new( - guild_id, - Some(channel_id), - "messages.view", - false, - )), + PermCheck::maybe_new(guild_id, channel_id, "messages.view"), EventContext::empty(), ); diff --git a/src/impls/chat/channels/update_channel_information.rs b/src/impls/chat/channels/update_channel_information.rs index e5d2bb3..6a9ae58 100644 --- a/src/impls/chat/channels/update_channel_information.rs +++ b/src/impls/chat/channels/update_channel_information.rs @@ -58,12 +58,7 @@ pub async fn handler( new_name, new_metadata, }), - Some(PermCheck::new( - guild_id, - Some(channel_id), - "messages.view", - false, - )), + Some(PermCheck::new(guild_id, Some(channel_id), "messages.view")), EventContext::empty(), ); diff --git a/src/impls/chat/guilds/create_direct_message.rs b/src/impls/chat/guilds/create_direct_message.rs deleted file mode 100644 index 9c41d48..0000000 --- a/src/impls/chat/guilds/create_direct_message.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::*; - -pub async fn handler( - _svc: &ChatServer, - _request: Request, -) -> ServerResult> { - Err(ServerError::NotImplemented.into()) -} diff --git a/src/impls/chat/guilds/create_guild.rs b/src/impls/chat/guilds/create_guild.rs index 717c8df..b4d6657 100644 --- a/src/impls/chat/guilds/create_guild.rs +++ b/src/impls/chat/guilds/create_guild.rs @@ -23,13 +23,7 @@ pub async fn handler( let guild_id = svc .deps .chat_tree - .create_guild_logic( - user_id, - name, - picture, - metadata, - guild::Kind::NormalUnspecified, - ) + .create_guild_logic(user_id, name, picture, metadata) .await?; svc.dispatch_guild_join(guild_id, user_id).await?; diff --git a/src/impls/chat/guilds/create_private_channel.rs b/src/impls/chat/guilds/create_private_channel.rs new file mode 100644 index 0000000..c6a7c68 --- /dev/null +++ b/src/impls/chat/guilds/create_private_channel.rs @@ -0,0 +1,8 @@ +use super::*; + +pub async fn handler( + _svc: &ChatServer, + _request: Request, +) -> ServerResult> { + Err(ServerError::NotImplemented.into()) +} diff --git a/src/impls/chat/guilds/create_room.rs b/src/impls/chat/guilds/create_room.rs deleted file mode 100644 index dbd93cf..0000000 --- a/src/impls/chat/guilds/create_room.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::*; - -pub async fn handler( - _svc: &ChatServer, - _request: Request, -) -> ServerResult> { - Err(ServerError::NotImplemented.into()) -} diff --git a/src/impls/chat/guilds/delete_guild.rs b/src/impls/chat/guilds/delete_guild.rs index bd21c53..2722c29 100644 --- a/src/impls/chat/guilds/delete_guild.rs +++ b/src/impls/chat/guilds/delete_guild.rs @@ -64,7 +64,7 @@ pub async fn handler( EventSub::Homeserver, stream_event::Event::GuildRemovedFromList(stream_event::GuildRemovedFromList { guild_id, - homeserver: String::new(), + server_id: String::new(), }), None, EventContext::new(local_ids), diff --git a/src/impls/chat/guilds/mod.rs b/src/impls/chat/guilds/mod.rs index d9c1094..0647504 100644 --- a/src/impls/chat/guilds/mod.rs +++ b/src/impls/chat/guilds/mod.rs @@ -1,8 +1,7 @@ use super::*; -pub mod create_direct_message; pub mod create_guild; -pub mod create_room; +pub mod create_private_channel; pub mod delete_guild; pub mod get_guild; pub mod get_guild_list; @@ -11,4 +10,3 @@ pub mod join_guild; pub mod leave_guild; pub mod preview_guild; pub mod update_guild_information; -pub mod upgrade_room_to_guild; diff --git a/src/impls/chat/guilds/upgrade_room_to_guild.rs b/src/impls/chat/guilds/upgrade_room_to_guild.rs deleted file mode 100644 index 09f43f1..0000000 --- a/src/impls/chat/guilds/upgrade_room_to_guild.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::*; - -pub async fn handler( - _svc: &ChatServer, - _request: Request, -) -> ServerResult> { - Err(ServerError::NotImplemented.into()) -} diff --git a/src/impls/chat/messages/add_reaction.rs b/src/impls/chat/messages/add_reaction.rs index 06b4bd8..c6b0812 100644 --- a/src/impls/chat/messages/add_reaction.rs +++ b/src/impls/chat/messages/add_reaction.rs @@ -18,6 +18,10 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; + chat_tree + .check_channel_user(guild_id, user_id, channel_id) + .await?; + chat_tree .check_perms( guild_id, diff --git a/src/impls/chat/messages/delete_message.rs b/src/impls/chat/messages/delete_message.rs index 2382144..39ff960 100644 --- a/src/impls/chat/messages/delete_message.rs +++ b/src/impls/chat/messages/delete_message.rs @@ -15,7 +15,7 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree - .check_guild_user_channel(guild_id, user_id, channel_id) + .check_channel_user(guild_id, user_id, channel_id) .await?; if chat_tree .get_message_logic(guild_id, channel_id, message_id) @@ -42,18 +42,13 @@ pub async fn handler( .map_err(ServerError::DbError)?; svc.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::DeletedMessage(stream_event::MessageDeleted { guild_id, channel_id, message_id, }), - Some(PermCheck::new( - guild_id, - Some(channel_id), - "messages.view", - false, - )), + PermCheck::maybe_new(guild_id, channel_id, "messages.view"), EventContext::empty(), ); diff --git a/src/impls/chat/messages/get_channel_messages.rs b/src/impls/chat/messages/get_channel_messages.rs index 7adc637..3e0091f 100644 --- a/src/impls/chat/messages/get_channel_messages.rs +++ b/src/impls/chat/messages/get_channel_messages.rs @@ -17,7 +17,7 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree - .check_guild_user_channel(guild_id, user_id, channel_id) + .check_channel_user(guild_id, user_id, channel_id) .await?; chat_tree .check_perms(guild_id, Some(channel_id), user_id, "messages.view", false) diff --git a/src/impls/chat/messages/get_message.rs b/src/impls/chat/messages/get_message.rs index 3a0ff65..dfab468 100644 --- a/src/impls/chat/messages/get_message.rs +++ b/src/impls/chat/messages/get_message.rs @@ -17,7 +17,7 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree - .check_guild_user_channel(guild_id, user_id, channel_id) + .check_channel_user(guild_id, user_id, channel_id) .await?; chat_tree .check_perms(guild_id, Some(channel_id), user_id, "messages.view", false) diff --git a/src/impls/chat/messages/get_pinned_messages.rs b/src/impls/chat/messages/get_pinned_messages.rs index da18682..9cd7293 100644 --- a/src/impls/chat/messages/get_pinned_messages.rs +++ b/src/impls/chat/messages/get_pinned_messages.rs @@ -14,7 +14,7 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree - .check_guild_user_channel(guild_id, user_id, channel_id) + .check_channel_user(guild_id, user_id, channel_id) .await?; chat_tree diff --git a/src/impls/chat/messages/pin_message.rs b/src/impls/chat/messages/pin_message.rs index 7ae98db..a312e8c 100644 --- a/src/impls/chat/messages/pin_message.rs +++ b/src/impls/chat/messages/pin_message.rs @@ -15,7 +15,7 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree - .check_guild_user_channel(guild_id, user_id, channel_id) + .check_channel_user(guild_id, user_id, channel_id) .await?; chat_tree @@ -29,23 +29,18 @@ pub async fn handler( .await?; let key = make_pinned_msgs_key(guild_id, channel_id); - let mut pinned_msgs_raw = chat_tree.get(key).await?.map_or_else(Vec::new, EVec::into); + let mut pinned_msgs_raw = chat_tree.get(&key).await?.map_or_else(Vec::new, EVec::into); pinned_msgs_raw.extend_from_slice(&message_id.to_be_bytes()); chat_tree.insert(key, pinned_msgs_raw).await?; svc.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::MessagePinned(stream_event::MessagePinned { guild_id, channel_id, message_id, }), - Some(PermCheck::new( - guild_id, - Some(channel_id), - all_permissions::MESSAGES_VIEW, - false, - )), + PermCheck::maybe_new(guild_id, channel_id, all_permissions::MESSAGES_VIEW), EventContext::empty(), ); diff --git a/src/impls/chat/messages/remove_reaction.rs b/src/impls/chat/messages/remove_reaction.rs index dedebef..d2c373e 100644 --- a/src/impls/chat/messages/remove_reaction.rs +++ b/src/impls/chat/messages/remove_reaction.rs @@ -15,6 +15,10 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; + chat_tree + .check_channel_user(guild_id, user_id, channel_id) + .await?; + chat_tree .check_perms( guild_id, diff --git a/src/impls/chat/messages/send_message.rs b/src/impls/chat/messages/send_message.rs index 88bebc2..2cc5d41 100644 --- a/src/impls/chat/messages/send_message.rs +++ b/src/impls/chat/messages/send_message.rs @@ -18,7 +18,7 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree - .check_guild_user_channel(guild_id, user_id, channel_id) + .check_channel_user(guild_id, user_id, channel_id) .await?; chat_tree .check_perms(guild_id, Some(channel_id), user_id, "messages.send", false) @@ -29,12 +29,14 @@ pub async fn handler( .process_message_content(svc.deps.as_ref(), request.content.take()) .await?; - let admin_action = chat_tree - .admin_guild_keys - .get() - .map_or(false, |keys| keys.check_if_cmd(guild_id, channel_id)) - .then(|| content.text.parse::().ok()) - .flatten(); + let admin_action = guild_id.and_then(|guild_id| { + chat_tree + .admin_guild_keys + .get() + .map_or(false, |keys| keys.check_if_cmd(guild_id, channel_id)) + .then(|| content.text.parse::().ok()) + .flatten() + }); let (message_id, message) = chat_tree .send_message_logic( @@ -45,6 +47,7 @@ pub async fn handler( request.overrides, request.in_reply_to, request.metadata, + request.actions, ) .await?; @@ -55,7 +58,7 @@ pub async fn handler( .await; svc.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::SentMessage(stream_event::MessageSent { echo_id, guild_id, @@ -63,12 +66,7 @@ pub async fn handler( message_id, message: Some(message), }), - Some(PermCheck::new( - guild_id, - Some(channel_id), - "messages.view", - false, - )), + PermCheck::maybe_new(guild_id, channel_id, "messages.view"), EventContext::empty(), ); @@ -78,7 +76,7 @@ pub async fn handler( .send_with_system(guild_id, channel_id, content) .await?; svc.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::SentMessage(stream_event::MessageSent { echo_id, guild_id, @@ -86,12 +84,7 @@ pub async fn handler( message_id, message: Some(message), }), - Some(PermCheck::new( - guild_id, - Some(channel_id), - "messages.view", - false, - )), + PermCheck::maybe_new(guild_id, channel_id, "messages.view"), EventContext::empty(), ); } diff --git a/src/impls/chat/messages/unpin_message.rs b/src/impls/chat/messages/unpin_message.rs index fceeea6..6675ccf 100644 --- a/src/impls/chat/messages/unpin_message.rs +++ b/src/impls/chat/messages/unpin_message.rs @@ -15,7 +15,7 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree - .check_guild_user_channel(guild_id, user_id, channel_id) + .check_channel_user(guild_id, user_id, channel_id) .await?; chat_tree @@ -40,18 +40,13 @@ pub async fn handler( .await?; svc.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::MessageUnpinned(stream_event::MessageUnpinned { guild_id, channel_id, message_id, }), - Some(PermCheck::new( - guild_id, - Some(channel_id), - all_permissions::MESSAGES_VIEW, - false, - )), + PermCheck::maybe_new(guild_id, channel_id, all_permissions::MESSAGES_VIEW), EventContext::empty(), ); diff --git a/src/impls/chat/messages/update_message_content.rs b/src/impls/chat/messages/update_message_content.rs index 2ae7871..993fd9a 100644 --- a/src/impls/chat/messages/update_message_content.rs +++ b/src/impls/chat/messages/update_message_content.rs @@ -20,7 +20,7 @@ pub async fn handler( let chat_tree = &svc.deps.chat_tree; chat_tree - .check_guild_user_channel(guild_id, user_id, channel_id) + .check_channel_user(guild_id, user_id, channel_id) .await?; chat_tree .check_perms(guild_id, Some(channel_id), user_id, "messages.send", false) @@ -31,7 +31,7 @@ pub async fn handler( .await?; let key = make_msg_key(guild_id, channel_id, message_id); - let Some(message_raw) = chat_tree.get(key).await? else { + let Some(message_raw) = chat_tree.get(&key).await? else { bail!(ServerError::NoSuchMessage { guild_id, channel_id, message_id }); }; let message_archived = rkyv_arch::(&message_raw); @@ -55,7 +55,7 @@ pub async fn handler( chat_tree.insert(key, buf).await?; svc.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::EditedMessage(stream_event::MessageUpdated { guild_id, channel_id, @@ -63,12 +63,7 @@ pub async fn handler( edited_at, new_content: Some(new_content), }), - Some(PermCheck::new( - guild_id, - Some(channel_id), - "messages.view", - false, - )), + PermCheck::maybe_new(guild_id, channel_id, "messages.view"), EventContext::empty(), ); diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 96a8c7f..2ff8942 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -56,6 +56,7 @@ pub const DEFAULT_ROLE_ID: u64 = 0; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum EventSub { + PrivateChannel(u64), Guild(u64), Homeserver, Actions, @@ -70,19 +71,23 @@ pub struct PermCheck<'a> { } impl<'a> PermCheck<'a> { - pub const fn new( - guild_id: u64, - channel_id: Option, - check_for: &'a str, - must_be_guild_owner: bool, - ) -> Self { + pub const fn new(guild_id: u64, channel_id: Option, check_for: &'a str) -> Self { Self { guild_id, channel_id, check_for, - must_be_guild_owner, + must_be_guild_owner: false, } } + + pub fn maybe_new(guild_id: Option, channel_id: u64, check_for: &'a str) -> Option { + guild_id.map(|guild_id| Self::new(guild_id, Some(channel_id), check_for)) + } + + pub fn must_be_guild_owner(mut self) -> Self { + self.must_be_guild_owner = true; + self + } } #[derive(Debug)] @@ -167,11 +172,9 @@ impl ChatServer { let user_guilds = chat_tree.get_user_guilds(user_id).await?; let initial_subs = user_guilds .into_iter() - .filter(|g| g.server_id.is_empty()) - .map(|g| EventSub::Guild(g.guild_id)); - let initial_subs = initial_subs - .chain(iter::once(EventSub::Actions)) - .chain(iter::once(EventSub::Homeserver)); + .filter_map(|g| g.server_id.is_empty().then(|| EventSub::Guild(g.guild_id))); + let initial_subs = + initial_subs.chain([EventSub::Actions, EventSub::Homeserver].into_iter()); subs.extend(initial_subs); // keep track of failed writes and reads to decide if closing the socket is worth it @@ -208,6 +211,7 @@ impl ChatServer { tracing::debug!("got new stream events request"); let sub = match req { + Request::SubscribeToPrivateChannel(_) => todo!("private channels"), Request::SubscribeToGuild(SubscribeToGuild { guild_id }) => { match chat_tree.check_guild_user(guild_id, user_id).await { Ok(_) => EventSub::Guild(guild_id), @@ -358,7 +362,7 @@ impl ChatServer { EventSub::Homeserver, stream_event::Event::GuildRemovedFromList(stream_event::GuildRemovedFromList { guild_id, - homeserver: String::new(), + server_id: String::new(), }), None, EventContext::new(vec![user_id]), @@ -386,7 +390,7 @@ impl ChatServer { EventSub::Homeserver, stream_event::Event::GuildAddedToList(stream_event::GuildAddedToList { guild_id, - homeserver: String::new(), + server_id: String::new(), }), None, EventContext::new(vec![user_id]), @@ -398,75 +402,60 @@ impl ChatServer { fn send_new_reaction_event( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, reaction: Reaction, ) { self.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::NewReactionAdded(stream_event::NewReactionAdded { guild_id, channel_id, message_id, reaction: Some(reaction), }), - Some(PermCheck { - guild_id, - channel_id: Some(channel_id), - check_for: all_permissions::MESSAGES_VIEW, - must_be_guild_owner: false, - }), + PermCheck::maybe_new(guild_id, channel_id, all_permissions::MESSAGES_VIEW), EventContext::empty(), ); } fn send_added_reaction_event( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, data: String, ) { self.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::ReactionAdded(stream_event::ReactionAdded { guild_id, channel_id, message_id, reaction_data: data, }), - Some(PermCheck { - guild_id, - channel_id: Some(channel_id), - check_for: all_permissions::MESSAGES_VIEW, - must_be_guild_owner: false, - }), + PermCheck::maybe_new(guild_id, channel_id, all_permissions::MESSAGES_VIEW), EventContext::empty(), ); } fn send_removed_reaction_event( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, data: String, ) { self.broadcast( - EventSub::Guild(guild_id), + guild_id.map_or(EventSub::PrivateChannel(channel_id), EventSub::Guild), stream_event::Event::ReactionRemoved(stream_event::ReactionRemoved { guild_id, channel_id, message_id, reaction_data: data, }), - Some(PermCheck { - guild_id, - channel_id: Some(channel_id), - check_for: all_permissions::MESSAGES_VIEW, - must_be_guild_owner: false, - }), + PermCheck::maybe_new(guild_id, channel_id, all_permissions::MESSAGES_VIEW), EventContext::empty(), ); } @@ -552,8 +541,11 @@ impl chat_service_server::ChatService for ChatServer { kick_user, KickUserRequest, KickUserResponse; #[rate(4, 5)] unban_user, UnbanUserRequest, UnbanUserResponse; + #[rate(4, 5)] get_pinned_messages, GetPinnedMessagesRequest, GetPinnedMessagesResponse; + #[rate(4, 10)] pin_message, PinMessageRequest, PinMessageResponse; + #[rate(4, 10)] unpin_message, UnpinMessageRequest, UnpinMessageResponse; #[rate(5, 7)] add_reaction, AddReactionRequest, AddReactionResponse; @@ -563,9 +555,7 @@ impl chat_service_server::ChatService for ChatServer { grant_ownership, GrantOwnershipRequest, GrantOwnershipResponse; #[rate(2, 60)] give_up_ownership, GiveUpOwnershipRequest, GiveUpOwnershipResponse; - create_room, CreateRoomRequest, CreateRoomResponse; - create_direct_message, CreateDirectMessageRequest, CreateDirectMessageResponse; - upgrade_room_to_guild, UpgradeRoomToGuildRequest, UpgradeRoomToGuildResponse; + create_private_channel, CreatePrivateChannelRequest, CreatePrivateChannelResponse; invite_user_to_guild, InviteUserToGuildRequest, InviteUserToGuildResponse; get_pending_invites, GetPendingInvitesRequest, GetPendingInvitesResponse; reject_pending_invite, RejectPendingInviteRequest, RejectPendingInviteResponse; @@ -617,6 +607,45 @@ impl ChatTree { }) } + pub async fn check_channel_user( + &self, + guild_id: Option, + channel_id: u64, + user_id: u64, + ) -> ServerResult<()> { + if let Some(guild_id) = guild_id { + self.check_guild_user_channel(guild_id, user_id, channel_id) + .await + } else { + self.check_private_channel_user(channel_id, user_id).await + } + } + + pub async fn is_user_in_private_channel( + &self, + channel_id: u64, + user_id: u64, + ) -> ServerResult { + self.contains_key(&make_member_key_pc(channel_id, user_id)) + .await + .map_err(Into::into) + } + + pub async fn check_user_in_private_channel( + &self, + channel_id: u64, + user_id: u64, + ) -> ServerResult<()> { + self.is_user_in_private_channel(channel_id, user_id) + .await? + .then(|| Ok(())) + .unwrap_or(Err(ServerError::UserNotInPrivateChannel { + channel_id, + user_id, + })) + .map_err(Into::into) + } + pub async fn is_user_in_guild(&self, guild_id: u64, user_id: u64) -> ServerResult { self.contains_key(&make_member_key(guild_id, user_id)) .await @@ -631,6 +660,20 @@ impl ChatTree { .map_err(Into::into) } + pub async fn does_private_channel_exist(&self, channel_id: u64) -> ServerResult { + self.contains_key(&make_pc_key(channel_id)) + .await + .map_err(Into::into) + } + + pub async fn check_private_channel_exist(&self, channel_id: u64) -> ServerResult<()> { + self.does_private_channel_exist(channel_id) + .await? + .then(|| Ok(())) + .unwrap_or(Err(ServerError::NoSuchPrivateChannel(channel_id))) + .map_err(Into::into) + } + pub async fn does_guild_exist(&self, guild_id: u64) -> ServerResult<()> { self.contains_key(&guild_id.to_be_bytes()) .await? @@ -714,12 +757,23 @@ impl ChatTree { self.does_guild_exist(guild_id).await } + pub async fn check_private_channel_user( + &self, + channel_id: u64, + user_id: u64, + ) -> ServerResult<()> { + self.check_private_channel_exist(channel_id).await?; + self.check_user_in_private_channel(channel_id, user_id) + .await?; + Ok(()) + } + pub async fn get_message_logic( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, - ) -> ServerResult<(HarmonyMessage, [u8; 26])> { + ) -> ServerResult<(HarmonyMessage, Vec)> { let key = make_msg_key(guild_id, channel_id, message_id); let message = if let Some(msg) = self.get(&key).await? { @@ -975,7 +1029,7 @@ impl ChatTree { pub async fn get_channel_messages_logic( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: Option, direction: Option, @@ -1026,8 +1080,11 @@ impl ChatTree { .try_fold(Vec::new(), |mut all, res| { let (key, value) = res.map_err(ServerError::from)?; // Safety: this is safe since the only keys we get are message keys, which after stripping prefix are message IDs - let message_id = - deser_id(key.split_at(make_msg_prefix(guild_id, channel_id).len()).1); + let prefix_len = guild_id.map_or_else( + || make_msg_prefix_pc(channel_id).len(), + |guild_id| make_msg_prefix(guild_id, channel_id).len(), + ); + let message_id = deser_id(key.split_at(prefix_len).1); let message = db::deser_message(value); all.push(MessageWithId { message_id, @@ -1099,12 +1156,16 @@ impl ChatTree { // from actual permission error pub async fn check_perms( &self, - guild_id: u64, + guild_id: impl Into>, channel_id: Option, user_id: u64, check_for: &str, must_be_guild_owner: bool, ) -> Result<(), ServerError> { + let guild_id = guild_id.into(); + let Some(guild_id) = guild_id else { + return Ok(()); + }; let is_owner = self.is_user_guild_owner(guild_id, user_id).await?; if must_be_guild_owner { if is_owner { @@ -1246,7 +1307,7 @@ impl ChatTree { let mut batch = Batch::default(); batch.insert(key, buf); batch.insert( - make_next_msg_id_key(guild_id, channel_id), + make_next_msg_id_key_guild(guild_id, channel_id), 1_u64.to_be_bytes(), ); self.chat_tree.apply_batch(batch).await?; @@ -1264,7 +1325,6 @@ impl ChatTree { name: String, picture: Option, metadata: Option, - kind: guild::Kind, ) -> ServerResult { let guild_id = { let mut rng = rand::rngs::SmallRng::from_entropy(); @@ -1280,7 +1340,6 @@ impl ChatTree { picture, owner_ids: vec![user_id], metadata, - kind: kind.into(), }; let buf = rkyv_ser(&guild); @@ -1515,7 +1574,7 @@ impl ChatTree { pub async fn get_next_message_id( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, ) -> Result { let next_id_key = make_next_msg_id_key(guild_id, channel_id); @@ -1528,7 +1587,7 @@ impl ChatTree { pub async fn get_last_message_id( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, ) -> Result { let next_id_key = make_next_msg_id_key(guild_id, channel_id); @@ -1544,13 +1603,14 @@ impl ChatTree { #[allow(clippy::too_many_arguments)] pub async fn send_message_logic( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, user_id: u64, content: Content, overrides: Option, in_reply_to: Option, metadata: Option, + actions: Vec, ) -> ServerResult<(u64, HarmonyMessage)> { let message_id = self.get_next_message_id(guild_id, channel_id).await?; let key = make_msg_key(guild_id, channel_id, message_id); // [tag:msg_key_u64] @@ -1566,6 +1626,7 @@ impl ChatTree { content: Some(content), in_reply_to, overrides, + actions, reactions: Vec::new(), }; @@ -1824,7 +1885,7 @@ impl ChatTree { pub async fn send_with_system( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, content: Content, ) -> ServerResult<(u64, HarmonyMessage)> { @@ -1841,6 +1902,7 @@ impl ChatTree { Some(overrides), None, None, + Vec::new(), ) .await } @@ -1852,15 +1914,15 @@ impl ChatTree { pub async fn remove_reaction( &self, user_id: u64, - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, data: &str, ) -> ServerResult { - self.check_guild_user_channel(guild_id, user_id, channel_id) - .await?; - - let react_key = make_user_reacted_msg_key(guild_id, channel_id, message_id, user_id, data); + let react_key = guild_id.map_or_else( + || make_user_reacted_msg_key_pc(channel_id, message_id, user_id, data), + |guild_id| make_user_reacted_msg_key(guild_id, channel_id, message_id, user_id, data), + ); let reacted = self .chat_tree @@ -1904,17 +1966,17 @@ impl ChatTree { pub async fn add_reaction( &self, user_id: u64, - guild_id: u64, + guild_id: Option, channel_id: u64, message_id: u64, data: String, name: String, kind: ReactionKind, ) -> ServerResult { - self.check_guild_user_channel(guild_id, user_id, channel_id) - .await?; - - let react_key = make_user_reacted_msg_key(guild_id, channel_id, message_id, user_id, &data); + let react_key = guild_id.map_or_else( + || make_user_reacted_msg_key_pc(channel_id, message_id, user_id, &data), + |guild_id| make_user_reacted_msg_key(guild_id, channel_id, message_id, user_id, &data), + ); let reacted = self .chat_tree @@ -1957,7 +2019,7 @@ impl ChatTree { pub async fn get_pinned_messages_logic( &self, - guild_id: u64, + guild_id: Option, channel_id: u64, ) -> Result, ServerError> { let pinned_msgs_raw = self.get(make_pinned_msgs_key(guild_id, channel_id)).await?; diff --git a/src/impls/chat/permissions/add_guild_role.rs b/src/impls/chat/permissions/add_guild_role.rs index 66b8ddd..9062abd 100644 --- a/src/impls/chat/permissions/add_guild_role.rs +++ b/src/impls/chat/permissions/add_guild_role.rs @@ -39,12 +39,7 @@ pub async fn handler( hoist, pingable, }), - Some(PermCheck::new( - guild_id, - None, - all_permissions::ROLES_GET, - false, - )), + Some(PermCheck::new(guild_id, None, all_permissions::ROLES_GET)), EventContext::empty(), ); diff --git a/src/impls/chat/permissions/delete_guild_role.rs b/src/impls/chat/permissions/delete_guild_role.rs index c2db6c4..a1ec711 100644 --- a/src/impls/chat/permissions/delete_guild_role.rs +++ b/src/impls/chat/permissions/delete_guild_role.rs @@ -25,12 +25,7 @@ pub async fn handler( svc.broadcast( EventSub::Guild(guild_id), stream_event::Event::RoleDeleted(stream_event::RoleDeleted { guild_id, role_id }), - Some(PermCheck::new( - guild_id, - None, - all_permissions::ROLES_GET, - false, - )), + Some(PermCheck::new(guild_id, None, all_permissions::ROLES_GET)), EventContext::empty(), ); diff --git a/src/impls/chat/permissions/manage_user_roles.rs b/src/impls/chat/permissions/manage_user_roles.rs index 4532fc8..1599d9a 100644 --- a/src/impls/chat/permissions/manage_user_roles.rs +++ b/src/impls/chat/permissions/manage_user_roles.rs @@ -39,7 +39,7 @@ pub async fn handler( user_id: user_to_manage, new_role_ids, }), - Some(PermCheck::new(guild_id, None, "roles.user.get", false)), + Some(PermCheck::new(guild_id, None, "roles.user.get")), EventContext::empty(), ); diff --git a/src/impls/chat/permissions/modify_guild_role.rs b/src/impls/chat/permissions/modify_guild_role.rs index cdf8358..55fb608 100644 --- a/src/impls/chat/permissions/modify_guild_role.rs +++ b/src/impls/chat/permissions/modify_guild_role.rs @@ -55,12 +55,7 @@ pub async fn handler( new_hoist, new_pingable, }), - Some(PermCheck::new( - guild_id, - None, - all_permissions::ROLES_GET, - false, - )), + Some(PermCheck::new(guild_id, None, all_permissions::ROLES_GET)), EventContext::empty(), ); diff --git a/src/impls/chat/permissions/move_role.rs b/src/impls/chat/permissions/move_role.rs index 8a2efd9..b4feb4e 100644 --- a/src/impls/chat/permissions/move_role.rs +++ b/src/impls/chat/permissions/move_role.rs @@ -31,12 +31,7 @@ pub async fn handler( role_id, new_position: Some(pos), }), - Some(PermCheck::new( - guild_id, - None, - all_permissions::ROLES_GET, - false, - )), + Some(PermCheck::new(guild_id, None, all_permissions::ROLES_GET)), EventContext::empty(), ); } diff --git a/src/impls/chat/permissions/set_permissions.rs b/src/impls/chat/permissions/set_permissions.rs index 320efcf..f842718 100644 --- a/src/impls/chat/permissions/set_permissions.rs +++ b/src/impls/chat/permissions/set_permissions.rs @@ -71,7 +71,6 @@ pub async fn handler( guild_id, None, all_permissions::ROLES_MANAGE, - false, )), EventContext::empty(), ); diff --git a/src/impls/mod.rs b/src/impls/mod.rs index a6c3313..6444b38 100644 --- a/src/impls/mod.rs +++ b/src/impls/mod.rs @@ -8,8 +8,8 @@ pub mod mediaproxy; pub mod profile; pub mod rest; pub mod sync; -#[cfg(feature = "voice")] -pub mod voice; +#[cfg(feature = "webrtc")] +pub mod webrtc; use prelude::*; @@ -176,8 +176,8 @@ pub fn setup_server( let chat_server = ChatServer::new(deps.clone()); let mediaproxy_server = MediaproxyServer::new(deps.clone()); let sync_server = SyncServer::new(deps.clone(), fed_event_receiver); - #[cfg(feature = "voice")] - let voice_server = self::voice::VoiceServer::new(deps.clone(), log_level); + #[cfg(feature = "webrtc")] + let webrtc_server = self::webrtc::WebRtcServer::new(deps.clone(), log_level); let profile = ProfileServiceServer::new(profile_server); let emote = EmoteServiceServer::new(emote_server); @@ -185,8 +185,9 @@ pub fn setup_server( let chat = ChatServiceServer::new(chat_server); let mediaproxy = MediaProxyServiceServer::new(mediaproxy_server); let sync = PostboxServiceServer::new(sync_server); - #[cfg(feature = "voice")] - let voice = crate::api::voice::voice_service_server::VoiceServiceServer::new(voice_server); + #[cfg(feature = "webrtc")] + let webrtc = + crate::api::webrtc::web_rtc_service_server::WebRtcServiceServer::new(webrtc_server); let rest = RestServiceLayer::new(deps); @@ -197,8 +198,8 @@ pub fn setup_server( chat, mediaproxy, sync, - #[cfg(feature = "voice")] - voice + #[cfg(feature = "webrtc")] + webrtc ); (server, rest) diff --git a/src/impls/voice/mod.rs b/src/impls/webrtc/mod.rs similarity index 96% rename from src/impls/voice/mod.rs rename to src/impls/webrtc/mod.rs index 631814b..0278f82 100644 --- a/src/impls/voice/mod.rs +++ b/src/impls/webrtc/mod.rs @@ -7,15 +7,7 @@ use super::prelude::*; use crate::api::{ exports::hrpc::bail_result, - voice::{ - stream_message_request::{Initialize, Message as RequestMessage}, - stream_message_response::{ - Initialized, JoinedChannel, Message as ResponseMessage, PreparedForJoinChannel, - UserJoined, UserLeft, - }, - voice_service_server::VoiceService, - *, - }, + webrtc::{web_rtc_service_server::WebRtcService, *}, }; use ahash::RandomState; use dashmap::DashMap; @@ -51,14 +43,14 @@ enum Event { } #[derive(Clone)] -pub struct VoiceServer { +pub struct WebRtcServer { worker_pool: WorkerPool, channels: Channels, disable_ratelimits: bool, deps: Arc, } -impl VoiceServer { +impl WebRtcServer { pub fn new(deps: Arc, log_level: Level) -> Self { Self { worker_pool: WorkerPool::new(log_level), @@ -69,7 +61,7 @@ impl VoiceServer { } } -impl VoiceService for VoiceServer { +impl WebRtcService for WebRtcServer { impl_ws_handlers! { #[rate(1, 10)] stream_message, StreamMessageRequest, StreamMessageResponse; diff --git a/src/impls/voice/stream_message.rs b/src/impls/webrtc/stream_message.rs similarity index 100% rename from src/impls/voice/stream_message.rs rename to src/impls/webrtc/stream_message.rs diff --git a/src/lib.rs b/src/lib.rs index 629282f..45fc2f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ once_cell, let_else, const_intrinsic_copy, - const_ptr_offset, const_mut_refs, type_alias_impl_trait )] From 111f7f59c94b8660a9f013b00b70eabffa2ab59c Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 4 Apr 2022 10:58:53 +0000 Subject: [PATCH 41/62] feat: partially implement private_channel create / delete / get_list --- src/db/mod.rs | 20 +- .../chat/guilds/create_private_channel.rs | 8 - src/impls/chat/guilds/get_guild_list.rs | 26 +- src/impls/chat/guilds/mod.rs | 1 - src/impls/chat/mod.rs | 251 +++++++++++++++--- .../create_private_channel.rs | 52 ++++ .../delete_private_channel.rs | 53 ++++ .../get_private_channel_list.rs | 16 ++ src/impls/chat/private_channels/mod.rs | 6 + .../update_private_channel_members.rs | 8 + src/impls/sync/mod.rs | 46 ++-- src/main.rs | 12 +- 12 files changed, 398 insertions(+), 101 deletions(-) delete mode 100644 src/impls/chat/guilds/create_private_channel.rs create mode 100644 src/impls/chat/private_channels/create_private_channel.rs create mode 100644 src/impls/chat/private_channels/delete_private_channel.rs create mode 100644 src/impls/chat/private_channels/get_private_channel_list.rs create mode 100644 src/impls/chat/private_channels/mod.rs create mode 100644 src/impls/chat/private_channels/update_private_channel_members.rs diff --git a/src/db/mod.rs b/src/db/mod.rs index 315bcc4..688f905 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -36,7 +36,7 @@ use std::{ use crate::{config::DbConfig, utils::evec::EVec, ServerError, ServerResult}; use crate::api::{ - chat::{Channel, Guild, Invite, Message as HarmonyMessage, Role}, + chat::{Channel, Guild, Invite, Message as HarmonyMessage, PrivateChannel, Role}, emote::{Emote, EmotePack}, profile::Profile, }; @@ -205,6 +205,10 @@ pub mod chat { concat_static(&[PRIV_CHANNEL_PREFIX, &channel_id.to_be_bytes()]) } + pub const fn make_pc_creator_key(channel_id: u64) -> [u8; 14] { + concat_static(&[&make_pc_key(channel_id), &[5]]) + } + pub fn make_guild_perm_key(guild_id: u64, role_id: u64, matches: &str) -> Vec { [ &make_role_guild_perms_prefix(guild_id, role_id), @@ -395,6 +399,10 @@ pub mod chat { concat_static(&[&guild_id.to_be_bytes(), &[4]]) } + pub const fn make_pc_list_key_prefix(user_id: u64) -> [u8; 10] { + concat_static(&[&user_id.to_be_bytes(), &[1, 4]]) + } + pub const fn make_guild_role_ordering_key(guild_id: u64) -> [u8; 10] { concat_static(&[&guild_id.to_be_bytes(), &[1, 3]]) } @@ -416,6 +424,15 @@ pub mod chat { .concat() } + pub fn make_pc_list_key(user_id: u64, channel_id: u64, host: &str) -> Vec { + [ + make_pc_list_key_prefix(user_id).as_ref(), + channel_id.to_be_bytes().as_ref(), + host.as_bytes(), + ] + .concat() + } + // guild pub const fn make_chan_key(guild_id: u64, channel_id: u64) -> [u8; 17] { @@ -486,6 +503,7 @@ crate::impl_deser! { role, Role; emote, Emote; emote_pack, EmotePack; + private_channel, PrivateChannel; } pub fn deser_invite_entry_guild_id(data: &[u8]) -> u64 { diff --git a/src/impls/chat/guilds/create_private_channel.rs b/src/impls/chat/guilds/create_private_channel.rs deleted file mode 100644 index c6a7c68..0000000 --- a/src/impls/chat/guilds/create_private_channel.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::*; - -pub async fn handler( - _svc: &ChatServer, - _request: Request, -) -> ServerResult> { - Err(ServerError::NotImplemented.into()) -} diff --git a/src/impls/chat/guilds/get_guild_list.rs b/src/impls/chat/guilds/get_guild_list.rs index 393e424..da3cb63 100644 --- a/src/impls/chat/guilds/get_guild_list.rs +++ b/src/impls/chat/guilds/get_guild_list.rs @@ -6,31 +6,7 @@ pub async fn handler( ) -> ServerResult> { let user_id = svc.deps.auth(&request).await?; - let prefix = make_guild_list_key_prefix(user_id); - let guilds = - svc.deps - .chat_tree - .scan_prefix(&prefix) - .await - .try_fold(Vec::new(), |mut all, res| { - let (guild_id_raw, _) = res?; - let (id_raw, host_raw) = guild_id_raw - .split_at(prefix.len()) - .1 - .split_at(size_of::()); - - // Safety: this unwrap can never cause UB since we split at u64 boundary - let guild_id = deser_id(id_raw); - // Safety: we never store non UTF-8 hosts, so this can't cause UB - let host = unsafe { std::str::from_utf8_unchecked(host_raw) }; - - all.push(GuildListEntry { - guild_id, - server_id: host.to_string(), - }); - - ServerResult::Ok(all) - })?; + let guilds = svc.deps.chat_tree.get_user_guilds(user_id).await?; Ok((GetGuildListResponse { guilds }).into_response()) } diff --git a/src/impls/chat/guilds/mod.rs b/src/impls/chat/guilds/mod.rs index 0647504..11232c5 100644 --- a/src/impls/chat/guilds/mod.rs +++ b/src/impls/chat/guilds/mod.rs @@ -1,7 +1,6 @@ use super::*; pub mod create_guild; -pub mod create_private_channel; pub mod delete_guild; pub mod get_guild; pub mod get_guild_list; diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 2ff8942..97a9c4a 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -1,6 +1,5 @@ use std::{ - collections::HashSet, io::BufReader, iter, lazy::SyncOnceCell, mem::size_of, ops::Not, - path::Path, + collections::HashSet, io::BufReader, lazy::SyncOnceCell, mem::size_of, ops::Not, path::Path, }; use crate::api::{ @@ -13,7 +12,9 @@ use crate::api::{ harmonytypes::{item_position, Empty, ItemPosition, Metadata}, sync::{ event::{ - Kind as DispatchKind, UserAddedToGuild as SyncUserAddedToGuild, + Kind as DispatchKind, UserAddedToChannel as SyncUserAddedToChannel, + UserAddedToGuild as SyncUserAddedToGuild, + UserRemovedFromChannel as SyncUserRemovedFromChannel, UserRemovedFromGuild as SyncUserRemovedFromGuild, }, Event as DispatchEvent, @@ -40,6 +41,7 @@ use invites::*; use messages::*; use moderation::*; use permissions::*; +use private_channels::*; use super::media::FileHandle; @@ -49,6 +51,7 @@ pub mod invites; pub mod messages; pub mod moderation; pub mod permissions; +pub mod private_channels; pub mod stream_events; pub mod trigger_action; @@ -168,11 +171,14 @@ impl ChatServer { let mut subs = HashSet::with_hasher(ahash::RandomState::new()); // add initial subs - // TODO: optimize local guild fetching - let user_guilds = chat_tree.get_user_guilds(user_id).await?; - let initial_subs = user_guilds - .into_iter() - .filter_map(|g| g.server_id.is_empty().then(|| EventSub::Guild(g.guild_id))); + let user_guilds = chat_tree.get_user_local_guilds(user_id).await?; + let user_pcs = chat_tree.get_user_local_private_channels(user_id).await?; + let initial_subs = user_guilds.into_iter().map(|e| EventSub::Guild(e.guild_id)); + let initial_subs = initial_subs.chain( + user_pcs + .into_iter() + .map(|e| EventSub::PrivateChannel(e.channel_id)), + ); let initial_subs = initial_subs.chain([EventSub::Actions, EventSub::Homeserver].into_iter()); subs.extend(initial_subs); @@ -211,7 +217,15 @@ impl ChatServer { tracing::debug!("got new stream events request"); let sub = match req { - Request::SubscribeToPrivateChannel(_) => todo!("private channels"), + Request::SubscribeToPrivateChannel(SubscribeToPrivateChannel { channel_id }) => { + match chat_tree.check_private_channel_user(channel_id, user_id).await { + Ok(_) => EventSub::PrivateChannel(channel_id), + Err(err) => { + tracing::error!("{}", err); + continue; + } + } + }, Request::SubscribeToGuild(SubscribeToGuild { guild_id }) => { match chat_tree.check_guild_user(guild_id, user_id).await { Ok(_) => EventSub::Guild(guild_id), @@ -239,9 +253,16 @@ impl ChatServer { // handle automatic sub handling BEFORE all the other logic because otherwise // `subs.contains()` will just return if manual_sub_handling.not() { + // TODO: i think we need to check whether the server_id is empty here before inserting? match &broadcast.event { - Event::Chat(stream_event::Event::GuildAddedToList(guild)) => subs.insert(EventSub::Guild(guild.guild_id)), - Event::Chat(stream_event::Event::GuildRemovedFromList(guild)) => subs.remove(&EventSub::Guild(guild.guild_id)), + Event::Chat(stream_event::Event::GuildAddedToList(guild)) + => subs.insert(EventSub::Guild(guild.guild_id)), + Event::Chat(stream_event::Event::GuildRemovedFromList(guild)) + => subs.remove(&EventSub::Guild(guild.guild_id)), + Event::Chat(stream_event::Event::PrivateChannelAddedToList(channel)) + => subs.insert(EventSub::PrivateChannel(channel.channel_id)), + Event::Chat(stream_event::Event::PrivateChannelRemovedFromList(channel)) + => subs.remove(&EventSub::PrivateChannel(channel.channel_id)), _ => false, }; } @@ -400,6 +421,74 @@ impl ChatServer { Ok(()) } + async fn dispatch_private_channel_leave( + &self, + channel_id: u64, + user_id: u64, + ) -> ServerResult<()> { + match self.deps.profile_tree.local_to_foreign_id(user_id).await? { + Some((foreign_id, target)) => self.dispatch_event( + target, + DispatchKind::UserRemovedFromChannel(SyncUserRemovedFromChannel { + user_id: foreign_id, + channel_id, + }), + ), + None => { + self.deps + .chat_tree + .remove_pc_from_pc_list(user_id, channel_id, "") + .await?; + self.broadcast( + EventSub::Homeserver, + stream_event::Event::PrivateChannelRemovedFromList( + stream_event::PrivateChannelRemovedFromList { + channel_id, + server_id: String::new(), + }, + ), + None, + EventContext::new(vec![user_id]), + ); + } + } + Ok(()) + } + + async fn dispatch_private_channel_join( + &self, + channel_id: u64, + user_id: u64, + ) -> ServerResult<()> { + match self.deps.profile_tree.local_to_foreign_id(user_id).await? { + Some((foreign_id, target)) => self.dispatch_event( + target, + DispatchKind::UserAddedToChannel(SyncUserAddedToChannel { + user_id: foreign_id, + channel_id, + }), + ), + None => { + self.deps + .chat_tree + .add_pc_to_pc_list(user_id, channel_id, "") + .await?; + self.broadcast( + EventSub::Homeserver, + stream_event::Event::PrivateChannelAddedToList( + stream_event::PrivateChannelAddedToList { + channel_id, + server_id: String::new(), + }, + ), + None, + EventContext::new(vec![user_id]), + ); + } + } + Ok(()) + } + fn send_new_reaction_event( &self, guild_id: Option, @@ -556,6 +645,9 @@ impl chat_service_server::ChatService for ChatServer { #[rate(2, 60)] give_up_ownership, GiveUpOwnershipRequest, GiveUpOwnershipResponse; create_private_channel, CreatePrivateChannelRequest, CreatePrivateChannelResponse; + delete_private_channel, DeletePrivateChannelRequest, DeletePrivateChannelResponse; + get_private_channel_list, GetPrivateChannelListRequest, GetPrivateChannelListResponse; + update_private_channel_members, UpdatePrivateChannelMembersRequest, UpdatePrivateChannelMembersResponse; invite_user_to_guild, InviteUserToGuildRequest, InviteUserToGuildResponse; get_pending_invites, GetPendingInvitesRequest, GetPendingInvitesResponse; reject_pending_invite, RejectPendingInviteRequest, RejectPendingInviteResponse; @@ -790,31 +882,76 @@ impl ChatTree { Ok((message, key)) } + pub async fn get_user_local_private_channels( + &self, + user_id: u64, + ) -> ServerResult> { + let prefix = make_pc_list_key_prefix(user_id); + self.get_user_pc_guilds(prefix, |channel_id, host| { + host.is_empty().then(|| PrivateChannelListEntry { + channel_id, + server_id: String::new(), + }) + }) + .await + } + + pub async fn get_user_private_channels( + &self, + user_id: u64, + ) -> ServerResult> { + let prefix = make_pc_list_key_prefix(user_id); + self.get_user_pc_guilds(prefix, |channel_id, host| { + Some(PrivateChannelListEntry { + channel_id, + server_id: host.to_string(), + }) + }) + .await + } + + pub async fn get_user_local_guilds(&self, user_id: u64) -> ServerResult> { + let prefix = make_guild_list_key_prefix(user_id); + self.get_user_pc_guilds(prefix, |guild_id, host| { + host.is_empty().then(|| GuildListEntry { + guild_id, + server_id: String::new(), + }) + }) + .await + } + pub async fn get_user_guilds(&self, user_id: u64) -> ServerResult> { let prefix = make_guild_list_key_prefix(user_id); - let guild_list = self + self.get_user_pc_guilds(prefix, |guild_id, host| { + Some(GuildListEntry { + guild_id, + server_id: host.to_string(), + }) + }) + .await + } + + pub async fn get_user_pc_guilds( + &self, + prefix: impl AsRef<[u8]>, + f: impl Fn(u64, &str) -> Option, + ) -> ServerResult> { + let prefix = prefix.as_ref(); + let list = self .scan_prefix(&prefix) .await .try_fold(Vec::new(), |mut all, res| { - let (guild_id_raw, _) = res?; - let (id_raw, host_raw) = guild_id_raw - .split_at(prefix.len()) - .1 - .split_at(size_of::()); - - // Safety: this unwrap can never cause UB since we split at u64 boundary - let guild_id = u64::from_be_bytes(unsafe { id_raw.try_into().unwrap_unchecked() }); - // Safety: we never store non UTF-8 hosts, so this can't cause UB - let host = unsafe { std::str::from_utf8_unchecked(host_raw) }; - - all.push(GuildListEntry { - guild_id, - server_id: host.to_string(), - }); + let (id_raw, _) = res?; + let (id, host) = deserialize_id_host(&id_raw, prefix.len()); + + if let Some(item) = f(id, host) { + all.push(item); + } ServerResult::Ok(all) })?; - Ok(guild_list) + Ok(list) } pub async fn get_guild_logic(&self, guild_id: u64) -> ServerResult { @@ -1441,23 +1578,42 @@ impl ChatTree { Ok(all) } + /// Adds a private channel to a user's private channel list + pub async fn add_pc_to_pc_list( + &self, + user_id: u64, + channel_id: u64, + server_id: &str, + ) -> ServerResult<()> { + self.insert(make_pc_list_key(user_id, channel_id, server_id), []) + .await?; + Ok(()) + } + + /// Removes a private channel from a user's private channel list + pub async fn remove_pc_from_pc_list( + &self, + user_id: u64, + channel_id: u64, + server_id: &str, + ) -> ServerResult<()> { + self.chat_tree + .remove(&make_pc_list_key(user_id, channel_id, server_id)) + .await + .map(|_| ()) + .map_err(ServerError::from) + .map_err(Into::into) + } + /// Adds a guild to a user's guild list pub async fn add_guild_to_guild_list( &self, user_id: u64, guild_id: u64, - homeserver: &str, + server_id: &str, ) -> ServerResult<()> { - self.insert( - [ - make_guild_list_key_prefix(user_id).as_ref(), - guild_id.to_be_bytes().as_ref(), - homeserver.as_bytes(), - ] - .concat(), - [], - ) - .await?; + self.insert(make_guild_list_key(user_id, guild_id, server_id), []) + .await?; Ok(()) } @@ -1466,10 +1622,10 @@ impl ChatTree { &self, user_id: u64, guild_id: u64, - homeserver: &str, + server_id: &str, ) -> ServerResult<()> { self.chat_tree - .remove(&make_guild_list_key(user_id, guild_id, homeserver)) + .remove(&make_guild_list_key(user_id, guild_id, server_id)) .await .map(|_| ()) .map_err(ServerError::from) @@ -2035,3 +2191,16 @@ impl ChatTree { Ok(()) } } + +// used for deserializing private channel or guild entries from the db +// this function assumes that the passed id_raw is of structure `prefix + u64 + utf-8 string` +fn deserialize_id_host(id_raw: &[u8], prefix_len: usize) -> (u64, &str) { + let (id_raw, host_raw) = id_raw.split_at(prefix_len).1.split_at(size_of::()); + + // Safety: this unwrap can never cause UB since we split at u64 boundary + let guild_id = u64::from_be_bytes(unsafe { id_raw.try_into().unwrap_unchecked() }); + // Safety: we never store non UTF-8 hosts, so this can't cause UB + let host = unsafe { std::str::from_utf8_unchecked(host_raw) }; + + (guild_id, host) +} diff --git a/src/impls/chat/private_channels/create_private_channel.rs b/src/impls/chat/private_channels/create_private_channel.rs new file mode 100644 index 0000000..adff977 --- /dev/null +++ b/src/impls/chat/private_channels/create_private_channel.rs @@ -0,0 +1,52 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let CreatePrivateChannelRequest { members, is_locked } = request.into_message().await?; + + let channel_id = logic(svc.deps.as_ref(), user_id, members, is_locked).await?; + + svc.dispatch_private_channel_join(channel_id, user_id) + .await?; + + // TODO: create invite, send invite to all other members specified + + Ok(CreatePrivateChannelResponse::new(channel_id).into_response()) +} + +pub async fn logic( + deps: &Dependencies, + creator_id: u64, + mut members: Vec, + is_locked: bool, +) -> ServerResult { + let chat_tree = &deps.chat_tree; + + let channel_id = { + let mut rng = rand::rngs::SmallRng::from_entropy(); + let mut channel_id = rng.gen_range(1..u64::MAX); + while chat_tree.contains_key(&make_pc_key(channel_id)).await? { + channel_id = rng.gen_range(1..u64::MAX); + } + channel_id + }; + + // add creator to members since it might not be in the members list + members.push(creator_id); + // deduplicate user ids + members.dedup(); + + let private_channel = PrivateChannel { members, is_locked }; + let serialized = rkyv_ser(&private_channel); + + let mut batch = Batch::default(); + batch.insert(make_pc_creator_key(channel_id), creator_id.to_be_bytes()); + batch.insert(make_pc_key(channel_id), serialized); + chat_tree.apply_batch(batch).await?; + + Ok(channel_id) +} diff --git a/src/impls/chat/private_channels/delete_private_channel.rs b/src/impls/chat/private_channels/delete_private_channel.rs new file mode 100644 index 0000000..b7ef7c3 --- /dev/null +++ b/src/impls/chat/private_channels/delete_private_channel.rs @@ -0,0 +1,53 @@ +use crate::db::{batch_delete_prefix, deser_private_channel}; + +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let DeletePrivateChannelRequest { channel_id } = request.into_message().await?; + + let deleted_channel = logic(svc.deps.as_ref(), user_id, channel_id).await?; + + for member in deleted_channel.members { + svc.dispatch_private_channel_leave(channel_id, member) + .await?; + } + + Ok(DeletePrivateChannelResponse::new().into_response()) +} + +pub async fn logic( + deps: &Dependencies, + user_id: u64, + channel_id: u64, +) -> ServerResult { + let chat_tree = &deps.chat_tree; + + let creator_id_raw = chat_tree + .get(make_pc_creator_key(channel_id)) + .await? + .ok_or(ServerError::NoSuchPrivateChannel(channel_id))?; + let creator_id = deser_id(creator_id_raw); + + if user_id != creator_id { + bail!(( + "h.user-not-private-channel-creator", + "you must be the creator of the private channel to delete it" + )); + } + + let key = make_pc_key(channel_id); + let private_channel_raw = chat_tree + .get(&key) + .await? + .ok_or(ServerError::NoSuchPrivateChannel(channel_id))?; + let private_channel = deser_private_channel(private_channel_raw); + + batch_delete_prefix(&chat_tree.chat_tree, make_pc_key(channel_id)).await?; + + Ok(private_channel) +} diff --git a/src/impls/chat/private_channels/get_private_channel_list.rs b/src/impls/chat/private_channels/get_private_channel_list.rs new file mode 100644 index 0000000..035f78d --- /dev/null +++ b/src/impls/chat/private_channels/get_private_channel_list.rs @@ -0,0 +1,16 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let channels = svc + .deps + .chat_tree + .get_user_private_channels(user_id) + .await?; + + Ok(GetPrivateChannelListResponse::new(channels).into_response()) +} diff --git a/src/impls/chat/private_channels/mod.rs b/src/impls/chat/private_channels/mod.rs new file mode 100644 index 0000000..0cb21b5 --- /dev/null +++ b/src/impls/chat/private_channels/mod.rs @@ -0,0 +1,6 @@ +use super::*; + +pub mod create_private_channel; +pub mod delete_private_channel; +pub mod get_private_channel_list; +pub mod update_private_channel_members; diff --git a/src/impls/chat/private_channels/update_private_channel_members.rs b/src/impls/chat/private_channels/update_private_channel_members.rs new file mode 100644 index 0000000..aaf464b --- /dev/null +++ b/src/impls/chat/private_channels/update_private_channel_members.rs @@ -0,0 +1,8 @@ +use super::*; + +pub async fn handler( + _svc: &ChatServer, + _request: Request, +) -> ServerResult> { + Err(ServerError::NotImplemented.into()) +} diff --git a/src/impls/sync/mod.rs b/src/impls/sync/mod.rs index 43ea4d7..5d44d53 100644 --- a/src/impls/sync/mod.rs +++ b/src/impls/sync/mod.rs @@ -281,22 +281,36 @@ impl SyncServer { } async fn push_logic(&self, host: &str, event: Event) -> ServerResult<()> { - if let Some(kind) = event.kind { - match kind { - Kind::UserRemovedFromGuild(UserRemovedFromGuild { user_id, guild_id }) => { - self.deps - .chat_tree - .remove_guild_from_guild_list(user_id, guild_id, host) - .await?; - } - Kind::UserAddedToGuild(UserAddedToGuild { user_id, guild_id }) => { - self.deps - .chat_tree - .add_guild_to_guild_list(user_id, guild_id, host) - .await?; - } - Kind::UserInvited(_) => todo!(), - Kind::UserRejectedInvite(_) => todo!(), + let chat_tree = &self.deps.chat_tree; + let Some(kind) = event.kind else { return Ok(()) }; + match kind { + Kind::UserRemovedFromGuild(UserRemovedFromGuild { user_id, guild_id }) => { + chat_tree + .remove_guild_from_guild_list(user_id, guild_id, host) + .await?; + } + Kind::UserAddedToGuild(UserAddedToGuild { user_id, guild_id }) => { + chat_tree + .add_guild_to_guild_list(user_id, guild_id, host) + .await?; + } + Kind::UserInvited(_) => todo!("invites"), + Kind::UserRejectedInvite(_) => todo!("invites"), + Kind::UserRemovedFromChannel(UserRemovedFromChannel { + user_id, + channel_id, + }) => { + chat_tree + .remove_pc_from_pc_list(user_id, channel_id, host) + .await?; + } + Kind::UserAddedToChannel(UserAddedToChannel { + user_id, + channel_id, + }) => { + chat_tree + .add_pc_to_pc_list(user_id, channel_id, host) + .await?; } } Ok(()) diff --git a/src/main.rs b/src/main.rs index 952f71a..6cdb56c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use std::{ }; use harmony_rust_sdk::api::{ - chat::{guild, ChannelKind, Permission}, + chat::{ChannelKind, Permission}, exports::hrpc::server::transport::{http::Hyper, Transport}, }; use hrpc::{ @@ -361,13 +361,7 @@ fn setup_tracing(console: bool, jaeger: bool, level_filter: Level) { async fn setup_admin_guild(deps: &Dependencies) { let guild_id = deps .chat_tree - .create_guild_logic( - 0, - "Admin".to_string(), - None, - None, - guild::Kind::NormalUnspecified, - ) + .create_guild_logic(0, "Admin".to_string(), None, None) .await .unwrap(); deps.chat_tree @@ -401,7 +395,7 @@ async fn setup_admin_guild(deps: &Dependencies) { .unwrap(); deps.chat_tree .send_with_system( - guild_id, + Some(guild_id), cmd_id, Content::default().with_text(admin_action::HELP_TEXT), ) From 228496a95ed4b7a785c78d2f74799c38e9728494 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 6 Apr 2022 17:36:30 +0000 Subject: [PATCH 42/62] feat: implement most invites and private channel endpoints --- Cargo.lock | 22 +- src/db/migration/proto_v2.rs | 1 + src/db/mod.rs | 37 ++ src/impls/chat/guilds/delete_guild.rs | 2 +- .../chat/invites/delete_outgoing_invite.rs | 23 ++ .../chat/invites/get_outgoing_invites.rs | 17 + src/impls/chat/invites/get_pending_invites.rs | 17 +- .../chat/invites/ignore_pending_invite.rs | 22 +- src/impls/chat/invites/mod.rs | 2 + .../chat/invites/reject_pending_invite.rs | 30 +- src/impls/chat/mod.rs | 338 ++++++++++++++++-- .../create_private_channel.rs | 36 +- .../delete_private_channel.rs | 7 + src/impls/mod.rs | 29 +- src/impls/sync/mod.rs | 121 ++++++- 15 files changed, 635 insertions(+), 69 deletions(-) create mode 100644 src/impls/chat/invites/delete_outgoing_invite.rs create mode 100644 src/impls/chat/invites/get_outgoing_invites.rs diff --git a/Cargo.lock b/Cargo.lock index 5dae350..ed383b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -549,9 +549,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ "cfg-if", ] @@ -897,7 +897,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#a4de99a9aa35a9c22c20204379cf4feca11275a9" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#2890eb29974dfa96dad796e1742c9f39dc5b100f" dependencies = [ "hrpc-build", "prost-build 0.10.0", @@ -908,7 +908,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#a4de99a9aa35a9c22c20204379cf4feca11275a9" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#2890eb29974dfa96dad796e1742c9f39dc5b100f" dependencies = [ "proc-macro2", "quote", @@ -918,7 +918,7 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#a4de99a9aa35a9c22c20204379cf4feca11275a9" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#2890eb29974dfa96dad796e1742c9f39dc5b100f" dependencies = [ "bytecheck", "harmony_build", @@ -1388,9 +1388,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb87f3080f6d1d69e8c564c0fcfde1d7aa8cc451ce40cae89479111f03bc0eb" +checksum = "32613e41de4c47ab04970c348ca7ae7382cf116625755af070b008a15516a889" [[package]] name = "mac" @@ -1944,9 +1944,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ "unicode-xid", ] @@ -2763,9 +2763,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.90" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" dependencies = [ "proc-macro2", "quote", diff --git a/src/db/migration/proto_v2.rs b/src/db/migration/proto_v2.rs index 4ecb640..62d4f4e 100644 --- a/src/db/migration/proto_v2.rs +++ b/src/db/migration/proto_v2.rs @@ -372,6 +372,7 @@ impl From for Option { // TODO: actually get the emote name using the pack_id from old name: String::new(), }), + pack_id: Some(old.pack_id), }), chat::format::Format::Color(old) => NewFormatData::Color(Color { kind: old.kind }), _ => return None, diff --git a/src/db/mod.rs b/src/db/mod.rs index 688f905..bbfe404 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -46,6 +46,8 @@ use rkyv::{ }; use tracing::Instrument; +use self::chat::{UserOutgoingInvites, UserPendingInvites}; + pub mod migration; #[cfg(feature = "sled")] pub mod sled; @@ -188,9 +190,14 @@ pub mod emote { } pub mod chat { + use harmony_rust_sdk::api::chat::{OutgoingInvite, PendingInvite}; + use super::concat_static; + pub const OUTGOING_INVITES_PREFIX: &[u8] = b"outgoing_invites_"; + pub const PENDING_INVITES_PREFIX: &[u8] = b"pending_invites_"; pub const INVITE_PREFIX: &[u8] = b"invite_"; + pub const PRIV_INVITE_PREFIX: &[u8] = b"priv_invite_"; pub const PRIV_CHANNEL_PREFIX: &[u8] = b"priv_"; pub const ADMIN_GUILD_KEY: &[u8] = b"admin_guild_key_data"; @@ -442,6 +449,34 @@ pub mod chat { pub fn make_invite_key(name: &str) -> Vec { [INVITE_PREFIX, name.as_bytes()].concat() } + + pub fn make_priv_invite_key(name: &str) -> Vec { + [PRIV_INVITE_PREFIX, name.as_bytes()].concat() + } + + pub fn make_pc_invite_allowed_key(name: &str) -> Vec { + [&make_priv_invite_key(name), "_allowed_users".as_bytes()].concat() + } + + #[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Default, Debug)] + #[archive_attr(derive(bytecheck::CheckBytes))] + pub struct UserPendingInvites { + pub invites: Vec, + } + + pub const fn make_user_pending_invites_key(user_id: u64) -> [u8; 24] { + concat_static(&[PENDING_INVITES_PREFIX, &user_id.to_be_bytes()]) + } + + #[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Default, Debug)] + #[archive_attr(derive(bytecheck::CheckBytes))] + pub struct UserOutgoingInvites { + pub invites: Vec, + } + + pub const fn make_user_outgoing_invites_key(user_id: u64) -> [u8; 25] { + concat_static(&[OUTGOING_INVITES_PREFIX, &user_id.to_be_bytes()]) + } } pub mod auth { @@ -504,6 +539,8 @@ crate::impl_deser! { emote, Emote; emote_pack, EmotePack; private_channel, PrivateChannel; + pending_invites, UserPendingInvites; + outgoing_invites, UserOutgoingInvites; } pub fn deser_invite_entry_guild_id(data: &[u8]) -> u64 { diff --git a/src/impls/chat/guilds/delete_guild.rs b/src/impls/chat/guilds/delete_guild.rs index 2722c29..635bd8b 100644 --- a/src/impls/chat/guilds/delete_guild.rs +++ b/src/impls/chat/guilds/delete_guild.rs @@ -64,7 +64,7 @@ pub async fn handler( EventSub::Homeserver, stream_event::Event::GuildRemovedFromList(stream_event::GuildRemovedFromList { guild_id, - server_id: String::new(), + server_id: None, }), None, EventContext::new(local_ids), diff --git a/src/impls/chat/invites/delete_outgoing_invite.rs b/src/impls/chat/invites/delete_outgoing_invite.rs new file mode 100644 index 0000000..eb0c0d7 --- /dev/null +++ b/src/impls/chat/invites/delete_outgoing_invite.rs @@ -0,0 +1,23 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let DeleteOutgoingInviteRequest { invite } = request.into_message().await?; + + let invite = invite.ok_or(("h.no-such-outgoing-invite", "no such outgoing invite found"))?; + + logic(svc.deps.as_ref(), user_id, &invite).await?; + + Ok(DeleteOutgoingInviteResponse::new().into_response()) +} + +pub async fn logic(deps: &Dependencies, user_id: u64, invite: &OutgoingInvite) -> ServerResult<()> { + deps.chat_tree + .remove_user_outgoing_invite(user_id, invite) + .await?; + Ok(()) +} diff --git a/src/impls/chat/invites/get_outgoing_invites.rs b/src/impls/chat/invites/get_outgoing_invites.rs new file mode 100644 index 0000000..d3f1fc4 --- /dev/null +++ b/src/impls/chat/invites/get_outgoing_invites.rs @@ -0,0 +1,17 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let outgoing = svc + .deps + .chat_tree + .get(make_user_outgoing_invites_key(user_id)) + .await? + .map_or_else(UserOutgoingInvites::default, db::deser_outgoing_invites); + + Ok(GetOutgoingInvitesResponse::new(outgoing.invites).into_response()) +} diff --git a/src/impls/chat/invites/get_pending_invites.rs b/src/impls/chat/invites/get_pending_invites.rs index b1ad171..ee4d70c 100644 --- a/src/impls/chat/invites/get_pending_invites.rs +++ b/src/impls/chat/invites/get_pending_invites.rs @@ -1,8 +1,17 @@ use super::*; pub async fn handler( - _svc: &ChatServer, - _request: Request, -) -> ServerResult> { - Err(ServerError::NotImplemented.into()) + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let pending = svc + .deps + .chat_tree + .get(make_user_pending_invites_key(user_id)) + .await? + .map_or_else(UserPendingInvites::default, db::deser_pending_invites); + + Ok(GetPendingInvitesResponse::new(pending.invites).into_response()) } diff --git a/src/impls/chat/invites/ignore_pending_invite.rs b/src/impls/chat/invites/ignore_pending_invite.rs index 73b3251..0c2d0cf 100644 --- a/src/impls/chat/invites/ignore_pending_invite.rs +++ b/src/impls/chat/invites/ignore_pending_invite.rs @@ -1,8 +1,22 @@ use super::*; pub async fn handler( - _svc: &ChatServer, - _request: Request, -) -> ServerResult> { - Err(ServerError::NotImplemented.into()) + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let IgnorePendingInviteRequest { invite } = request.into_message().await?; + + let invite = invite.ok_or(( + "h.invite-expected", + "no invite specified while one was expected", + ))?; + + svc.deps + .chat_tree + .remove_user_pending_invite(user_id, &invite) + .await?; + + Ok(IgnorePendingInviteResponse::new().into_response()) } diff --git a/src/impls/chat/invites/mod.rs b/src/impls/chat/invites/mod.rs index bae4689..edab908 100644 --- a/src/impls/chat/invites/mod.rs +++ b/src/impls/chat/invites/mod.rs @@ -2,7 +2,9 @@ use super::*; pub mod create_invite; pub mod delete_invite; +pub mod delete_outgoing_invite; pub mod get_guild_invites; +pub mod get_outgoing_invites; pub mod get_pending_invites; pub mod ignore_pending_invite; pub mod invite_user_to_guild; diff --git a/src/impls/chat/invites/reject_pending_invite.rs b/src/impls/chat/invites/reject_pending_invite.rs index 437a7d5..5cb16db 100644 --- a/src/impls/chat/invites/reject_pending_invite.rs +++ b/src/impls/chat/invites/reject_pending_invite.rs @@ -1,8 +1,30 @@ use super::*; pub async fn handler( - _svc: &ChatServer, - _request: Request, -) -> ServerResult> { - Err(ServerError::NotImplemented.into()) + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let RejectPendingInviteRequest { invite } = request.into_message().await?; + + let invite = invite.ok_or(("h.no-invite", "expected pending invite to be specified"))?; + + svc.deps + .chat_tree + .remove_user_pending_invite(user_id, &invite) + .await?; + + let location = match invite.location.ok_or("expected location")? { + pending_invite::Location::ChannelId(channel_id) => { + outgoing_invite::Location::ChannelId(channel_id) + } + pending_invite::Location::GuildInviteId(invite_id) => { + outgoing_invite::Location::GuildInviteId(invite_id) + } + }; + svc.dispatch_user_invite_rejected(invite.inviter_id, user_id, location) + .await?; + + Ok(RejectPendingInviteResponse::new().into_response()) } diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 97a9c4a..ec28610 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -2,23 +2,29 @@ use std::{ collections::HashSet, io::BufReader, lazy::SyncOnceCell, mem::size_of, ops::Not, path::Path, }; -use crate::api::{ - chat::{ - attachment::ImageInfo, get_channel_messages_request::Direction, overrides::Reason, - permission::has_permission, send_message_request::attachment::ImageInfo as SendImageInfo, - stream_event, Message as HarmonyMessage, *, - }, - exports::hrpc::{server::socket::Socket, Request}, - harmonytypes::{item_position, Empty, ItemPosition, Metadata}, - sync::{ - event::{ - Kind as DispatchKind, UserAddedToChannel as SyncUserAddedToChannel, - UserAddedToGuild as SyncUserAddedToGuild, - UserRemovedFromChannel as SyncUserRemovedFromChannel, - UserRemovedFromGuild as SyncUserRemovedFromGuild, +use crate::{ + api::{ + chat::{ + attachment::ImageInfo, get_channel_messages_request::Direction, overrides::Reason, + permission::has_permission, + send_message_request::attachment::ImageInfo as SendImageInfo, stream_event, + Message as HarmonyMessage, *, + }, + exports::hrpc::{server::socket::Socket, Request}, + harmonytypes::{item_position, Empty, ItemPosition, Metadata}, + sync::{ + event::{ + user_invited, user_rejected_invite, Kind as DispatchKind, + UserAddedToChannel as SyncUserAddedToChannel, + UserAddedToGuild as SyncUserAddedToGuild, UserInvited as SyncUserInvited, + UserRejectedInvite as SyncUserRejectedInvite, + UserRemovedFromChannel as SyncUserRemovedFromChannel, + UserRemovedFromGuild as SyncUserRemovedFromGuild, + }, + Event as DispatchEvent, }, - Event as DispatchEvent, }, + db::deser_invite_entry, }; use image::{GenericImageView, ImageFormat}; use rand::{Rng, SeedableRng}; @@ -334,26 +340,14 @@ impl ChatServer { } #[inline(always)] - fn broadcast( + pub fn broadcast( &self, sub: EventSub, event: stream_event::Event, perm_check: Option>, context: EventContext, ) { - let broadcast = EventBroadcast { - sub, - event: Event::Chat(event), - perm_check, - context, - }; - - tracing::debug!( - "broadcasting events to {} receivers", - self.deps.chat_event_sender.receiver_count() - ); - - drop(self.deps.chat_event_sender.send(Arc::new(broadcast))); + self.deps.broadcast_chat(sub, event, perm_check, context) } #[inline(always)] @@ -383,7 +377,7 @@ impl ChatServer { EventSub::Homeserver, stream_event::Event::GuildRemovedFromList(stream_event::GuildRemovedFromList { guild_id, - server_id: String::new(), + server_id: None, }), None, EventContext::new(vec![user_id]), @@ -411,7 +405,7 @@ impl ChatServer { EventSub::Homeserver, stream_event::Event::GuildAddedToList(stream_event::GuildAddedToList { guild_id, - server_id: String::new(), + server_id: None, }), None, EventContext::new(vec![user_id]), @@ -444,7 +438,7 @@ impl ChatServer { stream_event::Event::PrivateChannelRemovedFromList( stream_event::PrivateChannelRemovedFromList { channel_id, - server_id: String::new(), + server_id: None, }, ), None, @@ -478,7 +472,7 @@ impl ChatServer { stream_event::Event::PrivateChannelAddedToList( stream_event::PrivateChannelAddedToList { channel_id, - server_id: String::new(), + server_id: None, }, ), None, @@ -489,6 +483,106 @@ impl ChatServer { Ok(()) } + async fn dispatch_user_invite_rejected( + &self, + inviter_id: u64, + invitee_id: u64, + location: outgoing_invite::Location, + ) -> ServerResult<()> { + match self + .deps + .profile_tree + .local_to_foreign_id(inviter_id) + .await? + { + Some((foreign_id, target)) => self.dispatch_event( + target, + DispatchKind::UserRejectedInvite(SyncUserRejectedInvite { + user_id: invitee_id, + inviter_id: foreign_id, + location: Some(match location { + outgoing_invite::Location::ChannelId(channel_id) => { + user_rejected_invite::Location::ChannelId(channel_id) + } + outgoing_invite::Location::GuildInviteId(invite_id) => { + user_rejected_invite::Location::GuildInviteId(invite_id) + } + }), + }), + ), + None => { + let invite = OutgoingInvite { + invitee_id, + location: Some(location), + server_id: None, + }; + self.deps + .chat_tree + .remove_user_outgoing_invite(inviter_id, &invite) + .await?; + self.broadcast( + EventSub::Homeserver, + stream_event::Event::InviteRejected(stream_event::InviteRejected { + invite: Some(invite), + }), + None, + EventContext::new(vec![inviter_id]), + ); + } + } + Ok(()) + } + + async fn dispatch_user_invite_received( + &self, + inviter_id: u64, + invitee_id: u64, + location: pending_invite::Location, + ) -> ServerResult<()> { + match self + .deps + .profile_tree + .local_to_foreign_id(invitee_id) + .await? + { + Some((foreign_id, target)) => self.dispatch_event( + target, + DispatchKind::UserInvited(SyncUserInvited { + user_id: foreign_id, + inviter_id, + location: Some(match location { + pending_invite::Location::ChannelId(channel_id) => { + user_invited::Location::ChannelId(channel_id) + } + pending_invite::Location::GuildInviteId(invite_id) => { + user_invited::Location::GuildInviteId(invite_id) + } + }), + }), + ), + None => { + let invite = PendingInvite { + inviter_id, + location: Some(location), + server_id: None, + }; + self.deps + .chat_tree + .add_user_pending_invite(invitee_id, invite.clone()) + .await?; + self.broadcast( + EventSub::Homeserver, + stream_event::Event::InviteReceived(stream_event::InviteReceived { + invite: Some(invite), + }), + None, + EventContext::new(vec![invitee_id]), + ); + } + } + Ok(()) + } + fn send_new_reaction_event( &self, guild_id: Option, @@ -552,11 +646,11 @@ impl ChatServer { impl chat_service_server::ChatService for ChatServer { impl_unary_handlers! { - #[rate(1, 5)] + #[rate(1, 20)] create_guild, CreateGuildRequest, CreateGuildResponse; - #[rate(3, 5)] + #[rate(3, 10)] create_invite, CreateInviteRequest, CreateInviteResponse; - #[rate(4, 5)] + #[rate(4, 8)] create_channel, CreateChannelRequest, CreateChannelResponse; #[rate(5, 5)] get_guild_list, GetGuildListRequest, GetGuildListResponse; @@ -590,7 +684,7 @@ impl chat_service_server::ChatService for ChatServer { delete_channel, DeleteChannelRequest, DeleteChannelResponse; #[rate(7, 5)] delete_message, DeleteMessageRequest, DeleteMessageResponse; - #[rate(3, 5)] + #[rate(3, 8)] join_guild, JoinGuildRequest, JoinGuildResponse; #[rate(3, 5)] leave_guild, LeaveGuildRequest, LeaveGuildResponse; @@ -644,14 +738,26 @@ impl chat_service_server::ChatService for ChatServer { grant_ownership, GrantOwnershipRequest, GrantOwnershipResponse; #[rate(2, 60)] give_up_ownership, GiveUpOwnershipRequest, GiveUpOwnershipResponse; + #[rate(1, 20)] create_private_channel, CreatePrivateChannelRequest, CreatePrivateChannelResponse; + #[rate(3, 8)] delete_private_channel, DeletePrivateChannelRequest, DeletePrivateChannelResponse; + #[rate(5, 5)] get_private_channel_list, GetPrivateChannelListRequest, GetPrivateChannelListResponse; + #[rate(3, 8)] update_private_channel_members, UpdatePrivateChannelMembersRequest, UpdatePrivateChannelMembersResponse; + #[rate(4, 8)] invite_user_to_guild, InviteUserToGuildRequest, InviteUserToGuildResponse; + #[rate(5 ,5)] get_pending_invites, GetPendingInvitesRequest, GetPendingInvitesResponse; + #[rate(3, 5)] reject_pending_invite, RejectPendingInviteRequest, RejectPendingInviteResponse; + #[rate(3, 5)] ignore_pending_invite, IgnorePendingInviteRequest, IgnorePendingInviteResponse; + #[rate(5, 5)] + get_outgoing_invites, GetOutgoingInvitesRequest, GetOutgoingInvitesResponse; + #[rate(3, 5)] + delete_outgoing_invite, DeleteOutgoingInviteRequest, DeleteOutgoingInviteResponse; } impl_ws_handlers! { @@ -1531,6 +1637,164 @@ impl ChatTree { Ok(guild_id) } + #[inline] + pub async fn remove_user_outgoing_invite( + &self, + user_id: u64, + invite: &OutgoingInvite, + ) -> ServerResult { + self.modify_user_outgoing_invites(user_id, |invites| { + if let Some(pos) = invites.iter().position(|inv| inv == invite) { + Ok(invites.remove(pos)) + } else { + Err(("h.no-such-outgoing-invite", "no such outgoing invite found").into()) + } + }) + .await + } + + #[inline] + pub async fn add_user_outgoing_invite( + &self, + user_id: u64, + invite: OutgoingInvite, + ) -> ServerResult<()> { + self.modify_user_outgoing_invites(user_id, |invites| Ok(invites.push(invite))) + .await + } + + pub async fn modify_user_outgoing_invites( + &self, + user_id: u64, + f: impl FnOnce(&mut Vec) -> ServerResult, + ) -> ServerResult { + let key = make_user_outgoing_invites_key(user_id); + + let mut outgoing = self + .get(key) + .await? + .map_or_else(UserOutgoingInvites::default, db::deser_outgoing_invites); + + let result = f(&mut outgoing.invites)?; + + let outgoing_ser = rkyv_ser(&outgoing); + self.insert(key, outgoing_ser).await?; + + Ok(result) + } + + #[inline] + pub async fn remove_user_pending_invite( + &self, + user_id: u64, + invite: &PendingInvite, + ) -> ServerResult { + self.modify_user_pending_invites(user_id, |invites| { + if let Some(pos) = invites.iter().position(|inv| inv == invite) { + Ok(invites.remove(pos)) + } else { + Err(("h.no-such-pending-invite", "no such pending invite found").into()) + } + }) + .await + } + + #[inline] + pub async fn add_user_pending_invite( + &self, + user_id: u64, + invite: PendingInvite, + ) -> ServerResult<()> { + self.modify_user_pending_invites(user_id, |invites| Ok(invites.push(invite))) + .await + } + + pub async fn modify_user_pending_invites( + &self, + user_id: u64, + f: impl FnOnce(&mut Vec) -> ServerResult, + ) -> ServerResult { + let key = make_user_pending_invites_key(user_id); + + let mut pending = self + .get(key) + .await? + .map_or_else(UserPendingInvites::default, db::deser_pending_invites); + + let result = f(&mut pending.invites)?; + + let pending_ser = rkyv_ser(&pending); + self.insert(key, pending_ser).await?; + + Ok(result) + } + + pub async fn use_priv_invite_logic(&self, user_id: u64, invite_id: &str) -> ServerResult { + let allowed_users_key = make_pc_invite_allowed_key(&invite_id); + let mut allowed_users = self.get_list_u64_logic(&allowed_users_key).await?; + + if let Some(pos) = allowed_users.iter().position(|id| user_id.eq(id)) { + allowed_users.remove(pos); + } else { + bail!(( + "h.not-invited", + "you can't use this invite because you aren't invited" + )); + } + + let Some(invite_raw) = self.get(make_priv_invite_key(&invite_id)).await? else { + bail!(ServerError::NoSuchInvite(invite_id.into())); + }; + + let (id, mut invite) = deser_invite_entry(invite_raw); + invite.use_count += 1; + + let invite_buf = rkyv_ser(&invite); + + let mut batch = Batch::default(); + batch.insert( + make_priv_invite_key(&invite_id), + [id.to_be_bytes().as_ref(), invite_buf.as_ref()].concat(), + ); + batch.insert( + allowed_users_key, + self.serialize_list_u64_logic(allowed_users), + ); + self.apply_batch(batch).await?; + + Ok(id) + } + + pub async fn create_priv_invite_logic( + &self, + id: u64, + users_allowed: Vec, + use_id_as_invite_id: bool, + ) -> ServerResult { + let invite_id = use_id_as_invite_id + .then(|| id.to_string()) + .unwrap_or_else(|| gen_rand_inline_str().to_string()); + + let invite = Invite { + possible_uses: users_allowed.len() as u32, + use_count: 0, + }; + let buf = rkyv_ser(&invite); + + let mut batch = Batch::default(); + batch.insert( + make_priv_invite_key(&invite_id), + [id.to_be_bytes().as_ref(), buf.as_ref()].concat(), + ); + batch.insert( + make_pc_invite_allowed_key(&invite_id), + self.serialize_list_u64_logic(users_allowed), + ); + self.apply_batch(batch).await?; + + Ok(invite_id) + } + pub async fn create_invite_logic( &self, guild_id: u64, diff --git a/src/impls/chat/private_channels/create_private_channel.rs b/src/impls/chat/private_channels/create_private_channel.rs index adff977..626da94 100644 --- a/src/impls/chat/private_channels/create_private_channel.rs +++ b/src/impls/chat/private_channels/create_private_channel.rs @@ -8,12 +8,44 @@ pub async fn handler( let CreatePrivateChannelRequest { members, is_locked } = request.into_message().await?; - let channel_id = logic(svc.deps.as_ref(), user_id, members, is_locked).await?; + let channel_id = logic(svc.deps.as_ref(), user_id, members.clone(), is_locked).await?; + let users_allowed = members; svc.dispatch_private_channel_join(channel_id, user_id) .await?; - // TODO: create invite, send invite to all other members specified + // create invite, using channel_id as invite_id + svc.deps + .chat_tree + .create_priv_invite_logic(channel_id, users_allowed.clone(), true) + .await?; + + // insert outgoing invites for user + let user_outgoing_invites = UserOutgoingInvites { + invites: users_allowed + .iter() + .map(|invitee_id| OutgoingInvite { + invitee_id: *invitee_id, + location: Some(outgoing_invite::Location::ChannelId(channel_id)), + server_id: None, + }) + .collect(), + }; + let serialized = rkyv_ser(&user_outgoing_invites); + svc.deps + .chat_tree + .insert(make_user_outgoing_invites_key(user_id), serialized) + .await?; + + // dispatch invites to users + for invitee_id in users_allowed { + svc.dispatch_user_invite_received( + user_id, + invitee_id, + pending_invite::Location::ChannelId(channel_id), + ) + .await?; + } Ok(CreatePrivateChannelResponse::new(channel_id).into_response()) } diff --git a/src/impls/chat/private_channels/delete_private_channel.rs b/src/impls/chat/private_channels/delete_private_channel.rs index b7ef7c3..88ca563 100644 --- a/src/impls/chat/private_channels/delete_private_channel.rs +++ b/src/impls/chat/private_channels/delete_private_channel.rs @@ -49,5 +49,12 @@ pub async fn logic( batch_delete_prefix(&chat_tree.chat_tree, make_pc_key(channel_id)).await?; + // also delete invite, if any + batch_delete_prefix( + &chat_tree.chat_tree, + make_priv_invite_key(&channel_id.to_string()), + ) + .await?; + Ok(private_channel) } diff --git a/src/impls/mod.rs b/src/impls/mod.rs index 6444b38..a6951f1 100644 --- a/src/impls/mod.rs +++ b/src/impls/mod.rs @@ -11,11 +11,12 @@ pub mod sync; #[cfg(feature = "webrtc")] pub mod webrtc; +use harmony_rust_sdk::api::chat::{stream_event, Event}; use prelude::*; use std::str::FromStr; -use crate::api::HomeserverIdentifier; +use crate::{api::HomeserverIdentifier, impls::chat::EventBroadcast}; use hyper::{http, Uri}; use lettre::{ message::{header, Mailbox, MultiPart, SinglePart}, @@ -29,8 +30,13 @@ use tokio::sync::{broadcast, mpsc}; use crate::{config::Config, key, SharedConfig, SharedConfigData}; use self::{ - auth::AuthTree, chat::ChatTree, emote::EmoteTree, media::MediaStore, profile::ProfileTree, - rest::RestServiceLayer, sync::EventDispatch, + auth::AuthTree, + chat::{ChatTree, EventContext, EventSub, PermCheck}, + emote::EmoteTree, + media::MediaStore, + profile::ProfileTree, + rest::RestServiceLayer, + sync::EventDispatch, }; pub mod prelude { @@ -150,6 +156,23 @@ impl Dependencies { Ok((Arc::new(this), fed_event_receiver)) } + + pub fn broadcast_chat( + &self, + sub: EventSub, + event: stream_event::Event, + perm_check: Option>, + context: EventContext, + ) { + let broadcast = EventBroadcast::new(sub, Event::Chat(event), perm_check, context); + + tracing::trace!( + "broadcasting events to {} receivers", + self.chat_event_sender.receiver_count() + ); + + drop(self.chat_event_sender.send(Arc::new(broadcast))); + } } pub fn setup_server( diff --git a/src/impls/sync/mod.rs b/src/impls/sync/mod.rs index 5d44d53..7f2c6bf 100644 --- a/src/impls/sync/mod.rs +++ b/src/impls/sync/mod.rs @@ -8,6 +8,10 @@ use crate::api::{ }; use ahash::RandomState; use dashmap::{mapref::one::RefMut, DashMap}; +use harmony_rust_sdk::api::chat::{ + outgoing_invite, pending_invite, stream_event as chat_stream_event, + stream_event::Event as ChatEvent, OutgoingInvite, PendingInvite, +}; use hrpc::exports::futures_util::TryFutureExt; use hrpc::{client::transport::http::Hyper, encode::encode_protobuf_message}; use hyper::{http::HeaderValue, Uri}; @@ -16,7 +20,11 @@ use tracing::{error, Instrument}; use crate::key::{self, Manager as KeyManager}; -use super::{http, prelude::*}; +use super::{ + chat::{EventContext, EventSub}, + http, + prelude::*, +}; use db::sync::*; pub mod notify_new_id; @@ -288,21 +296,117 @@ impl SyncServer { chat_tree .remove_guild_from_guild_list(user_id, guild_id, host) .await?; + self.deps.broadcast_chat( + EventSub::Homeserver, + ChatEvent::GuildRemovedFromList(chat_stream_event::GuildRemovedFromList { + guild_id, + server_id: Some(host.to_string()), + }), + None, + EventContext::new(vec![user_id]), + ); } Kind::UserAddedToGuild(UserAddedToGuild { user_id, guild_id }) => { chat_tree .add_guild_to_guild_list(user_id, guild_id, host) .await?; + self.deps.broadcast_chat( + EventSub::Homeserver, + ChatEvent::GuildAddedToList(chat_stream_event::GuildAddedToList { + guild_id, + server_id: Some(host.to_string()), + }), + None, + EventContext::new(vec![user_id]), + ); + } + Kind::UserInvited(UserInvited { + inviter_id, + location, + user_id, + }) => { + // TODO: add checks for location, user_id and inviter + let location = match location.ok_or("location can't be empty")? { + user_invited::Location::GuildInviteId(invite) => { + pending_invite::Location::GuildInviteId(invite) + } + user_invited::Location::ChannelId(channel_id) => { + pending_invite::Location::ChannelId(channel_id) + } + }; + + let invite = PendingInvite { + inviter_id, + location: Some(location), + server_id: Some(host.to_string()), + }; + + chat_tree + .add_user_pending_invite(user_id, invite.clone()) + .await?; + + self.deps.broadcast_chat( + EventSub::Homeserver, + ChatEvent::InviteReceived(chat_stream_event::InviteReceived { + invite: Some(invite), + }), + None, + EventContext::new(vec![user_id]), + ); + } + Kind::UserRejectedInvite(UserRejectedInvite { + location, + user_id, + inviter_id, + }) => { + // TODO: add checks for location, user_id and inviter + let location = match location.ok_or("location can't be empty")? { + user_rejected_invite::Location::GuildInviteId(invite) => { + outgoing_invite::Location::GuildInviteId(invite) + } + user_rejected_invite::Location::ChannelId(channel_id) => { + outgoing_invite::Location::ChannelId(channel_id) + } + }; + + let invite = OutgoingInvite { + invitee_id: user_id, + location: Some(location), + server_id: Some(host.to_string()), + }; + + chat_tree + .remove_user_outgoing_invite(inviter_id, &invite) + .await?; + + self.deps.broadcast_chat( + EventSub::Homeserver, + ChatEvent::InviteRejected(chat_stream_event::InviteRejected { + invite: Some(invite), + }), + None, + EventContext::new(vec![inviter_id]), + ); } - Kind::UserInvited(_) => todo!("invites"), - Kind::UserRejectedInvite(_) => todo!("invites"), Kind::UserRemovedFromChannel(UserRemovedFromChannel { user_id, channel_id, }) => { + // TODO: do we need to send events here? probably? is the user_id foreign or not??? chat_tree .remove_pc_from_pc_list(user_id, channel_id, host) .await?; + self.deps.broadcast_chat( + EventSub::Homeserver, + ChatEvent::PrivateChannelRemovedFromList( + chat_stream_event::PrivateChannelRemovedFromList { + channel_id, + server_id: Some(host.to_string()), + }, + ), + None, + EventContext::new(vec![user_id]), + ); } Kind::UserAddedToChannel(UserAddedToChannel { user_id, @@ -311,6 +415,17 @@ impl SyncServer { chat_tree .add_pc_to_pc_list(user_id, channel_id, host) .await?; + self.deps.broadcast_chat( + EventSub::Homeserver, + ChatEvent::PrivateChannelAddedToList( + chat_stream_event::PrivateChannelAddedToList { + channel_id, + server_id: Some(host.to_string()), + }, + ), + None, + EventContext::new(vec![user_id]), + ); } } Ok(()) From 2b9fc283ac470ed1add809a07489917695cd8bfe Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Thu, 7 Apr 2022 03:39:11 +0000 Subject: [PATCH 43/62] feat: implement update_private_channel_members --- src/db/mod.rs | 2 +- .../chat/invites/delete_outgoing_invite.rs | 14 +-- src/impls/chat/mod.rs | 72 ++++++++++-- .../create_private_channel.rs | 32 +++-- .../delete_private_channel.rs | 18 ++- .../update_private_channel_members.rs | 109 +++++++++++++++++- src/lib.rs | 3 +- 7 files changed, 207 insertions(+), 43 deletions(-) diff --git a/src/db/mod.rs b/src/db/mod.rs index bbfe404..519a462 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -454,7 +454,7 @@ pub mod chat { [PRIV_INVITE_PREFIX, name.as_bytes()].concat() } - pub fn make_pc_invite_allowed_key(name: &str) -> Vec { + pub fn make_priv_invite_allowed_key(name: &str) -> Vec { [&make_priv_invite_key(name), "_allowed_users".as_bytes()].concat() } diff --git a/src/impls/chat/invites/delete_outgoing_invite.rs b/src/impls/chat/invites/delete_outgoing_invite.rs index eb0c0d7..37a473c 100644 --- a/src/impls/chat/invites/delete_outgoing_invite.rs +++ b/src/impls/chat/invites/delete_outgoing_invite.rs @@ -8,16 +8,12 @@ pub async fn handler( let DeleteOutgoingInviteRequest { invite } = request.into_message().await?; - let invite = invite.ok_or(("h.no-such-outgoing-invite", "no such outgoing invite found"))?; + let invite = invite.ok_or(("h.invite-expected", "an outgoing invite must be specified"))?; - logic(svc.deps.as_ref(), user_id, &invite).await?; + svc.deps + .chat_tree + .remove_user_outgoing_invite(user_id, &invite) + .await?; Ok(DeleteOutgoingInviteResponse::new().into_response()) } - -pub async fn logic(deps: &Dependencies, user_id: u64, invite: &OutgoingInvite) -> ServerResult<()> { - deps.chat_tree - .remove_user_outgoing_invite(user_id, invite) - .await?; - Ok(()) -} diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index ec28610..8da382f 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -921,10 +921,6 @@ impl ChatTree { guild_id: u64, user_id: u64, ) -> Result { - if user_id == 0 { - return Ok(true); - } - let is_owner = self .get_guild_owners(guild_id) .await? @@ -934,6 +930,39 @@ impl ChatTree { Ok(is_owner) } + pub async fn get_private_channel_creator(&self, channel_id: u64) -> ServerResult { + let raw = self + .get(make_pc_creator_key(channel_id)) + .await? + .ok_or("private channels must have a creator")?; + Ok(db::deser_id(raw)) + } + + pub async fn is_user_private_channel_creator( + &self, + channel_id: u64, + user_id: u64, + ) -> ServerResult { + self.get_private_channel_creator(channel_id) + .await + .map(|creator_id| creator_id == user_id) + } + + pub async fn check_private_channel_creator( + &self, + channel_id: u64, + user_id: u64, + ) -> ServerResult<()> { + self.is_user_private_channel_creator(channel_id, user_id) + .await? + .then(|| Ok(())) + .unwrap_or(Err(( + "h.not-channel-creator", + "you are not the private channel creator", + ))) + .map_err(Into::into) + } + pub async fn check_guild_user_channel( &self, guild_id: u64, @@ -1060,6 +1089,15 @@ impl ChatTree { Ok(list) } + pub async fn get_private_channel_logic(&self, channel_id: u64) -> ServerResult { + let key = make_pc_key(channel_id); + let private_channel_raw = self + .get(&key) + .await? + .ok_or(ServerError::NoSuchPrivateChannel(channel_id))?; + Ok(db::deser_private_channel(private_channel_raw)) + } + pub async fn get_guild_logic(&self, guild_id: u64) -> ServerResult { let guild = if let Some(guild_raw) = self.get(guild_id.to_be_bytes().as_ref()).await? { db::deser_guild(guild_raw) @@ -1730,7 +1768,7 @@ impl ChatTree { } pub async fn use_priv_invite_logic(&self, user_id: u64, invite_id: &str) -> ServerResult { - let allowed_users_key = make_pc_invite_allowed_key(&invite_id); + let allowed_users_key = make_priv_invite_allowed_key(&invite_id); let mut allowed_users = self.get_list_u64_logic(&allowed_users_key).await?; if let Some(pos) = allowed_users.iter().position(|id| user_id.eq(id)) { @@ -1765,12 +1803,32 @@ impl ChatTree { Ok(id) } + // returns new allowed users + pub async fn update_priv_invite_allowed_users( + &self, + invite_id: String, + f: impl FnOnce(&mut Vec), + ) -> ServerResult> { + let key = make_priv_invite_allowed_key(&invite_id); + + let mut allowed_users = self.get_list_u64_logic(&key).await?; + f(&mut allowed_users); + + let serialized = self.serialize_list_u64_logic(allowed_users.clone()); + self.insert(key, serialized).await?; + + Ok(allowed_users) + } + + // returns invite id pub async fn create_priv_invite_logic( &self, id: u64, - users_allowed: Vec, + mut users_allowed: Vec, use_id_as_invite_id: bool, ) -> ServerResult { + users_allowed.dedup(); + let invite_id = use_id_as_invite_id .then(|| id.to_string()) .unwrap_or_else(|| gen_rand_inline_str().to_string()); @@ -1787,7 +1845,7 @@ impl ChatTree { [id.to_be_bytes().as_ref(), buf.as_ref()].concat(), ); batch.insert( - make_pc_invite_allowed_key(&invite_id), + make_priv_invite_allowed_key(&invite_id), self.serialize_list_u64_logic(users_allowed), ); self.apply_batch(batch).await?; diff --git a/src/impls/chat/private_channels/create_private_channel.rs b/src/impls/chat/private_channels/create_private_channel.rs index 626da94..5c8eed4 100644 --- a/src/impls/chat/private_channels/create_private_channel.rs +++ b/src/impls/chat/private_channels/create_private_channel.rs @@ -21,20 +21,28 @@ pub async fn handler( .await?; // insert outgoing invites for user - let user_outgoing_invites = UserOutgoingInvites { - invites: users_allowed - .iter() - .map(|invitee_id| OutgoingInvite { - invitee_id: *invitee_id, - location: Some(outgoing_invite::Location::ChannelId(channel_id)), - server_id: None, - }) - .collect(), - }; - let serialized = rkyv_ser(&user_outgoing_invites); + let mut user_outgoing_invites = Vec::with_capacity(users_allowed.len()); + for invitee_id in users_allowed.iter().copied() { + let (invitee_id, server_id) = svc + .deps + .profile_tree + .local_to_foreign_id(invitee_id) + .await? + .map_or((invitee_id, None), |(id, server_id)| { + (id, Some(server_id.to_string())) + }); + + let invite = OutgoingInvite { + invitee_id, + server_id, + location: Some(outgoing_invite::Location::ChannelId(channel_id)), + }; + + user_outgoing_invites.push(invite); + } svc.deps .chat_tree - .insert(make_user_outgoing_invites_key(user_id), serialized) + .modify_user_outgoing_invites(user_id, |invites| Ok(invites.extend(user_outgoing_invites))) .await?; // dispatch invites to users diff --git a/src/impls/chat/private_channels/delete_private_channel.rs b/src/impls/chat/private_channels/delete_private_channel.rs index 88ca563..1292882 100644 --- a/src/impls/chat/private_channels/delete_private_channel.rs +++ b/src/impls/chat/private_channels/delete_private_channel.rs @@ -1,5 +1,3 @@ -use crate::db::{batch_delete_prefix, deser_private_channel}; - use super::*; pub async fn handler( @@ -10,6 +8,11 @@ pub async fn handler( let DeletePrivateChannelRequest { channel_id } = request.into_message().await?; + svc.deps + .chat_tree + .check_private_channel_creator(channel_id, user_id) + .await?; + let deleted_channel = logic(svc.deps.as_ref(), user_id, channel_id).await?; for member in deleted_channel.members { @@ -40,17 +43,12 @@ pub async fn logic( )); } - let key = make_pc_key(channel_id); - let private_channel_raw = chat_tree - .get(&key) - .await? - .ok_or(ServerError::NoSuchPrivateChannel(channel_id))?; - let private_channel = deser_private_channel(private_channel_raw); + let private_channel = chat_tree.get_private_channel_logic(channel_id).await?; - batch_delete_prefix(&chat_tree.chat_tree, make_pc_key(channel_id)).await?; + db::batch_delete_prefix(&chat_tree.chat_tree, make_pc_key(channel_id)).await?; // also delete invite, if any - batch_delete_prefix( + db::batch_delete_prefix( &chat_tree.chat_tree, make_priv_invite_key(&channel_id.to_string()), ) diff --git a/src/impls/chat/private_channels/update_private_channel_members.rs b/src/impls/chat/private_channels/update_private_channel_members.rs index aaf464b..03d2109 100644 --- a/src/impls/chat/private_channels/update_private_channel_members.rs +++ b/src/impls/chat/private_channels/update_private_channel_members.rs @@ -1,8 +1,111 @@ use super::*; pub async fn handler( - _svc: &ChatServer, - _request: Request, + svc: &ChatServer, + request: Request, ) -> ServerResult> { - Err(ServerError::NotImplemented.into()) + let user_id = svc.deps.auth(&request).await?; + + let UpdatePrivateChannelMembersRequest { + channel_id, + added_members, + removed_members, + } = request.into_message().await?; + + svc.deps + .chat_tree + .check_private_channel_user(channel_id, user_id) + .await?; + + let (added, removed) = logic(svc, channel_id, added_members, removed_members).await?; + + // update invite allowed users + svc.deps + .chat_tree + .update_priv_invite_allowed_users(channel_id.to_string(), |allowed_users| { + allowed_users.retain(|id| removed.contains(id).not()); + allowed_users.extend(added.iter().copied()); + }) + .await?; + + // insert new outgoing invites for user + let mut user_outgoing_invites = Vec::with_capacity(added.len()); + for invitee_id in added.iter().copied() { + let (invitee_id, server_id) = svc + .deps + .profile_tree + .local_to_foreign_id(invitee_id) + .await? + .map_or((invitee_id, None), |(id, server_id)| { + (id, Some(server_id.to_string())) + }); + + let invite = OutgoingInvite { + invitee_id, + server_id, + location: Some(outgoing_invite::Location::ChannelId(channel_id)), + }; + + user_outgoing_invites.push(invite); + } + svc.deps + .chat_tree + .modify_user_outgoing_invites(user_id, |invites| Ok(invites.extend(user_outgoing_invites))) + .await?; + + // dispatch invites to new members + for invitee_id in added { + svc.dispatch_user_invite_received( + user_id, + invitee_id, + pending_invite::Location::ChannelId(channel_id), + ) + .await?; + } + + // dispatch left events to removed users + for member in removed { + svc.dispatch_private_channel_leave(channel_id, member) + .await?; + } + + Ok(UpdatePrivateChannelMembersResponse::new().into_response()) +} + +pub async fn logic( + svc: &ChatServer, + channel_id: u64, + added: Vec, + removed: Vec, +) -> ServerResult<(Vec, Vec)> { + let chat_tree = &svc.deps.chat_tree; + + let mut private_channel = chat_tree.get_private_channel_logic(channel_id).await?; + + let members_before = private_channel.members.clone(); + + private_channel + .members + .retain(|id| removed.contains(id).not()); + private_channel.members.extend(added); + private_channel.members.dedup(); + + // members_before: [1, 2] + // private_channel.members: [1, 2, 3] + // members_added: [3] + let members_added = private_channel + .members + .iter() + .filter_map(|id| members_before.contains(id).not().then(|| *id)) + .collect::>(); + + // members_before: [1, 2, 3, 4] + // private_channel.members: [2, 3, 4] + // members_removed: [1] + let members_removed = members_before + .iter() + .filter_map(|id| private_channel.members.contains(id).not().then(|| *id)) + .collect::>(); + + Ok((members_added, members_removed)) } diff --git a/src/lib.rs b/src/lib.rs index 45fc2f9..ef8c902 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,8 @@ let_else, const_intrinsic_copy, const_mut_refs, - type_alias_impl_trait + type_alias_impl_trait, + drain_filter )] #![allow(clippy::unit_arg, clippy::blocks_in_if_conditions)] From 3406d2f9c70d9a028cfa6b3fc8f5dfe36fa347e3 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Thu, 7 Apr 2022 20:19:25 +0000 Subject: [PATCH 44/62] feat: implement join and leave for private channel --- Cargo.lock | 16 +-- src/db/mod.rs | 16 +-- .../chat/invites/delete_outgoing_invite.rs | 19 --- .../chat/invites/get_outgoing_invites.rs | 17 --- .../chat/invites/ignore_pending_invite.rs | 21 +++- src/impls/chat/invites/mod.rs | 2 - .../chat/invites/reject_pending_invite.rs | 29 +++-- src/impls/chat/mod.rs | 119 ++++++------------ .../create_private_channel.rs | 54 +++----- .../delete_private_channel.rs | 9 ++ .../private_channels/join_private_channel.rs | 50 ++++++++ .../private_channels/leave_private_channel.rs | 62 +++++++++ src/impls/chat/private_channels/mod.rs | 2 + .../update_private_channel_members.rs | 62 +++++---- src/impls/sync/mod.rs | 53 +++++--- src/lib.rs | 3 +- 16 files changed, 289 insertions(+), 245 deletions(-) delete mode 100644 src/impls/chat/invites/delete_outgoing_invite.rs delete mode 100644 src/impls/chat/invites/get_outgoing_invites.rs create mode 100644 src/impls/chat/private_channels/join_private_channel.rs create mode 100644 src/impls/chat/private_channels/leave_private_channel.rs diff --git a/Cargo.lock b/Cargo.lock index ed383b8..f44606e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -897,7 +897,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#2890eb29974dfa96dad796e1742c9f39dc5b100f" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#e2044a4d9a0151b4b06b782c5c28873da1e5384b" dependencies = [ "hrpc-build", "prost-build 0.10.0", @@ -908,7 +908,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#2890eb29974dfa96dad796e1742c9f39dc5b100f" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#e2044a4d9a0151b4b06b782c5c28873da1e5384b" dependencies = [ "proc-macro2", "quote", @@ -918,7 +918,7 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#2890eb29974dfa96dad796e1742c9f39dc5b100f" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#e2044a4d9a0151b4b06b782c5c28873da1e5384b" dependencies = [ "bytecheck", "harmony_build", @@ -1337,14 +1337,14 @@ dependencies = [ "rustls-pemfile 0.3.0", "tokio", "tokio-rustls 0.23.3", - "webpki-roots 0.22.2", + "webpki-roots 0.22.3", ] [[package]] name = "libc" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" [[package]] name = "libsqlite3-sys" @@ -3505,9 +3505,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +checksum = "44d8de8415c823c8abd270ad483c6feeac771fad964890779f9a8cb24fbbc1bf" dependencies = [ "webpki 0.22.0", ] diff --git a/src/db/mod.rs b/src/db/mod.rs index 519a462..89fecbd 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -46,7 +46,7 @@ use rkyv::{ }; use tracing::Instrument; -use self::chat::{UserOutgoingInvites, UserPendingInvites}; +use self::chat::UserPendingInvites; pub mod migration; #[cfg(feature = "sled")] @@ -190,11 +190,10 @@ pub mod emote { } pub mod chat { - use harmony_rust_sdk::api::chat::{OutgoingInvite, PendingInvite}; + use harmony_rust_sdk::api::chat::PendingInvite; use super::concat_static; - pub const OUTGOING_INVITES_PREFIX: &[u8] = b"outgoing_invites_"; pub const PENDING_INVITES_PREFIX: &[u8] = b"pending_invites_"; pub const INVITE_PREFIX: &[u8] = b"invite_"; pub const PRIV_INVITE_PREFIX: &[u8] = b"priv_invite_"; @@ -467,16 +466,6 @@ pub mod chat { pub const fn make_user_pending_invites_key(user_id: u64) -> [u8; 24] { concat_static(&[PENDING_INVITES_PREFIX, &user_id.to_be_bytes()]) } - - #[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Default, Debug)] - #[archive_attr(derive(bytecheck::CheckBytes))] - pub struct UserOutgoingInvites { - pub invites: Vec, - } - - pub const fn make_user_outgoing_invites_key(user_id: u64) -> [u8; 25] { - concat_static(&[OUTGOING_INVITES_PREFIX, &user_id.to_be_bytes()]) - } } pub mod auth { @@ -540,7 +529,6 @@ crate::impl_deser! { emote_pack, EmotePack; private_channel, PrivateChannel; pending_invites, UserPendingInvites; - outgoing_invites, UserOutgoingInvites; } pub fn deser_invite_entry_guild_id(data: &[u8]) -> u64 { diff --git a/src/impls/chat/invites/delete_outgoing_invite.rs b/src/impls/chat/invites/delete_outgoing_invite.rs deleted file mode 100644 index 37a473c..0000000 --- a/src/impls/chat/invites/delete_outgoing_invite.rs +++ /dev/null @@ -1,19 +0,0 @@ -use super::*; - -pub async fn handler( - svc: &ChatServer, - request: Request, -) -> ServerResult> { - let user_id = svc.deps.auth(&request).await?; - - let DeleteOutgoingInviteRequest { invite } = request.into_message().await?; - - let invite = invite.ok_or(("h.invite-expected", "an outgoing invite must be specified"))?; - - svc.deps - .chat_tree - .remove_user_outgoing_invite(user_id, &invite) - .await?; - - Ok(DeleteOutgoingInviteResponse::new().into_response()) -} diff --git a/src/impls/chat/invites/get_outgoing_invites.rs b/src/impls/chat/invites/get_outgoing_invites.rs deleted file mode 100644 index d3f1fc4..0000000 --- a/src/impls/chat/invites/get_outgoing_invites.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::*; - -pub async fn handler( - svc: &ChatServer, - request: Request, -) -> ServerResult> { - let user_id = svc.deps.auth(&request).await?; - - let outgoing = svc - .deps - .chat_tree - .get(make_user_outgoing_invites_key(user_id)) - .await? - .map_or_else(UserOutgoingInvites::default, db::deser_outgoing_invites); - - Ok(GetOutgoingInvitesResponse::new(outgoing.invites).into_response()) -} diff --git a/src/impls/chat/invites/ignore_pending_invite.rs b/src/impls/chat/invites/ignore_pending_invite.rs index 0c2d0cf..3447d82 100644 --- a/src/impls/chat/invites/ignore_pending_invite.rs +++ b/src/impls/chat/invites/ignore_pending_invite.rs @@ -6,16 +6,27 @@ pub async fn handler( ) -> ServerResult> { let user_id = svc.deps.auth(&request).await?; - let IgnorePendingInviteRequest { invite } = request.into_message().await?; + let IgnorePendingInviteRequest { + server_id, + location, + } = request.into_message().await?; - let invite = invite.ok_or(( - "h.invite-expected", - "no invite specified while one was expected", + let location = location.ok_or(( + "h.location-expected", + "location not specified while it was expected", ))?; + let location = match location { + ignore_pending_invite_request::Location::ChannelId(channel_id) => { + pending_invite::Location::ChannelId(channel_id) + } + ignore_pending_invite_request::Location::GuildInviteId(invite_id) => { + pending_invite::Location::GuildInviteId(invite_id) + } + }; svc.deps .chat_tree - .remove_user_pending_invite(user_id, &invite) + .remove_user_pending_invite(user_id, server_id.as_deref(), &location) .await?; Ok(IgnorePendingInviteResponse::new().into_response()) diff --git a/src/impls/chat/invites/mod.rs b/src/impls/chat/invites/mod.rs index edab908..bae4689 100644 --- a/src/impls/chat/invites/mod.rs +++ b/src/impls/chat/invites/mod.rs @@ -2,9 +2,7 @@ use super::*; pub mod create_invite; pub mod delete_invite; -pub mod delete_outgoing_invite; pub mod get_guild_invites; -pub mod get_outgoing_invites; pub mod get_pending_invites; pub mod ignore_pending_invite; pub mod invite_user_to_guild; diff --git a/src/impls/chat/invites/reject_pending_invite.rs b/src/impls/chat/invites/reject_pending_invite.rs index 5cb16db..0826459 100644 --- a/src/impls/chat/invites/reject_pending_invite.rs +++ b/src/impls/chat/invites/reject_pending_invite.rs @@ -6,21 +6,36 @@ pub async fn handler( ) -> ServerResult> { let user_id = svc.deps.auth(&request).await?; - let RejectPendingInviteRequest { invite } = request.into_message().await?; + let RejectPendingInviteRequest { + server_id, + location, + } = request.into_message().await?; - let invite = invite.ok_or(("h.no-invite", "expected pending invite to be specified"))?; + let location = location.ok_or(( + "h.location-expected", + "location not specified while it was expected", + ))?; + let location = match location { + reject_pending_invite_request::Location::ChannelId(channel_id) => { + pending_invite::Location::ChannelId(channel_id) + } + reject_pending_invite_request::Location::GuildInviteId(invite_id) => { + pending_invite::Location::GuildInviteId(invite_id) + } + }; - svc.deps + let invite = svc + .deps .chat_tree - .remove_user_pending_invite(user_id, &invite) + .remove_user_pending_invite(user_id, server_id.as_deref(), &location) .await?; - let location = match invite.location.ok_or("expected location")? { + let location = match location { pending_invite::Location::ChannelId(channel_id) => { - outgoing_invite::Location::ChannelId(channel_id) + user_rejected_invite::Location::ChannelId(channel_id) } pending_invite::Location::GuildInviteId(invite_id) => { - outgoing_invite::Location::GuildInviteId(invite_id) + user_rejected_invite::Location::GuildInviteId(invite_id) } }; svc.dispatch_user_invite_rejected(invite.inviter_id, user_id, location) diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 8da382f..d23b4df 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -487,7 +487,7 @@ impl ChatServer { &self, inviter_id: u64, invitee_id: u64, - location: outgoing_invite::Location, + location: user_rejected_invite::Location, ) -> ServerResult<()> { match self .deps @@ -500,30 +500,24 @@ impl ChatServer { DispatchKind::UserRejectedInvite(SyncUserRejectedInvite { user_id: invitee_id, inviter_id: foreign_id, - location: Some(match location { - outgoing_invite::Location::ChannelId(channel_id) => { - user_rejected_invite::Location::ChannelId(channel_id) - } - outgoing_invite::Location::GuildInviteId(invite_id) => { - user_rejected_invite::Location::GuildInviteId(invite_id) - } - }), + location: Some(location), }), ), None => { - let invite = OutgoingInvite { - invitee_id, - location: Some(location), - server_id: None, + let location = match location { + user_rejected_invite::Location::ChannelId(channel_id) => { + stream_event::invite_rejected::Location::ChannelId(channel_id) + } + user_rejected_invite::Location::GuildInviteId(invite_id) => { + stream_event::invite_rejected::Location::GuildInviteId(invite_id) + } }; - self.deps - .chat_tree - .remove_user_outgoing_invite(inviter_id, &invite) - .await?; self.broadcast( EventSub::Homeserver, stream_event::Event::InviteRejected(stream_event::InviteRejected { - invite: Some(invite), + invitee_id, + location: Some(location), + server_id: None, }), None, EventContext::new(vec![inviter_id]), @@ -561,19 +555,31 @@ impl ChatServer { }), ), None => { - let invite = PendingInvite { - inviter_id, - location: Some(location), - server_id: None, - }; self.deps .chat_tree - .add_user_pending_invite(invitee_id, invite.clone()) + .add_user_pending_invite( + invitee_id, + PendingInvite { + inviter_id, + location: Some(location.clone()), + server_id: None, + }, + ) .await?; + let location = match location { + pending_invite::Location::ChannelId(channel_id) => { + stream_event::invite_received::Location::ChannelId(channel_id) + } + pending_invite::Location::GuildInviteId(invite_id) => { + stream_event::invite_received::Location::GuildInviteId(invite_id) + } + }; self.broadcast( EventSub::Homeserver, stream_event::Event::InviteReceived(stream_event::InviteReceived { - invite: Some(invite), + inviter_id, + location: Some(location), + server_id: None, }), None, EventContext::new(vec![invitee_id]), @@ -684,7 +690,7 @@ impl chat_service_server::ChatService for ChatServer { delete_channel, DeleteChannelRequest, DeleteChannelResponse; #[rate(7, 5)] delete_message, DeleteMessageRequest, DeleteMessageResponse; - #[rate(3, 8)] + #[rate(3, 15)] join_guild, JoinGuildRequest, JoinGuildResponse; #[rate(3, 5)] leave_guild, LeaveGuildRequest, LeaveGuildResponse; @@ -742,6 +748,10 @@ impl chat_service_server::ChatService for ChatServer { create_private_channel, CreatePrivateChannelRequest, CreatePrivateChannelResponse; #[rate(3, 8)] delete_private_channel, DeletePrivateChannelRequest, DeletePrivateChannelResponse; + #[rate(3, 15)] + join_private_channel, JoinPrivateChannelRequest, JoinPrivateChannelResponse; + #[rate(3, 5)] + leave_private_channel, LeavePrivateChannelRequest, LeavePrivateChannelResponse; #[rate(5, 5)] get_private_channel_list, GetPrivateChannelListRequest, GetPrivateChannelListResponse; #[rate(3, 8)] @@ -754,10 +764,6 @@ impl chat_service_server::ChatService for ChatServer { reject_pending_invite, RejectPendingInviteRequest, RejectPendingInviteResponse; #[rate(3, 5)] ignore_pending_invite, IgnorePendingInviteRequest, IgnorePendingInviteResponse; - #[rate(5, 5)] - get_outgoing_invites, GetOutgoingInvitesRequest, GetOutgoingInvitesResponse; - #[rate(3, 5)] - delete_outgoing_invite, DeleteOutgoingInviteRequest, DeleteOutgoingInviteResponse; } impl_ws_handlers! { @@ -1675,60 +1681,17 @@ impl ChatTree { Ok(guild_id) } - #[inline] - pub async fn remove_user_outgoing_invite( - &self, - user_id: u64, - invite: &OutgoingInvite, - ) -> ServerResult { - self.modify_user_outgoing_invites(user_id, |invites| { - if let Some(pos) = invites.iter().position(|inv| inv == invite) { - Ok(invites.remove(pos)) - } else { - Err(("h.no-such-outgoing-invite", "no such outgoing invite found").into()) - } - }) - .await - } - - #[inline] - pub async fn add_user_outgoing_invite( - &self, - user_id: u64, - invite: OutgoingInvite, - ) -> ServerResult<()> { - self.modify_user_outgoing_invites(user_id, |invites| Ok(invites.push(invite))) - .await - } - - pub async fn modify_user_outgoing_invites( - &self, - user_id: u64, - f: impl FnOnce(&mut Vec) -> ServerResult, - ) -> ServerResult { - let key = make_user_outgoing_invites_key(user_id); - - let mut outgoing = self - .get(key) - .await? - .map_or_else(UserOutgoingInvites::default, db::deser_outgoing_invites); - - let result = f(&mut outgoing.invites)?; - - let outgoing_ser = rkyv_ser(&outgoing); - self.insert(key, outgoing_ser).await?; - - Ok(result) - } - #[inline] pub async fn remove_user_pending_invite( &self, user_id: u64, - invite: &PendingInvite, + server_id: Option<&str>, + location: &pending_invite::Location, ) -> ServerResult { self.modify_user_pending_invites(user_id, |invites| { - if let Some(pos) = invites.iter().position(|inv| inv == invite) { + if let Some(pos) = invites.iter().position(|inv| { + inv.server_id.as_deref() == server_id && inv.location.as_ref() == Some(location) + }) { Ok(invites.remove(pos)) } else { Err(("h.no-such-pending-invite", "no such pending invite found").into()) diff --git a/src/impls/chat/private_channels/create_private_channel.rs b/src/impls/chat/private_channels/create_private_channel.rs index 5c8eed4..87193ad 100644 --- a/src/impls/chat/private_channels/create_private_channel.rs +++ b/src/impls/chat/private_channels/create_private_channel.rs @@ -6,10 +6,16 @@ pub async fn handler( ) -> ServerResult> { let user_id = svc.deps.auth(&request).await?; - let CreatePrivateChannelRequest { members, is_locked } = request.into_message().await?; + let CreatePrivateChannelRequest { + members: mut users_allowed, + is_dm, + } = request.into_message().await?; - let channel_id = logic(svc.deps.as_ref(), user_id, members.clone(), is_locked).await?; - let users_allowed = members; + let channel_id = logic(svc.deps.as_ref(), user_id, is_dm).await?; + + // TODO: add logic for detecting an already existing dm for user with the other user + + users_allowed.dedup(); svc.dispatch_private_channel_join(channel_id, user_id) .await?; @@ -20,31 +26,6 @@ pub async fn handler( .create_priv_invite_logic(channel_id, users_allowed.clone(), true) .await?; - // insert outgoing invites for user - let mut user_outgoing_invites = Vec::with_capacity(users_allowed.len()); - for invitee_id in users_allowed.iter().copied() { - let (invitee_id, server_id) = svc - .deps - .profile_tree - .local_to_foreign_id(invitee_id) - .await? - .map_or((invitee_id, None), |(id, server_id)| { - (id, Some(server_id.to_string())) - }); - - let invite = OutgoingInvite { - invitee_id, - server_id, - location: Some(outgoing_invite::Location::ChannelId(channel_id)), - }; - - user_outgoing_invites.push(invite); - } - svc.deps - .chat_tree - .modify_user_outgoing_invites(user_id, |invites| Ok(invites.extend(user_outgoing_invites))) - .await?; - // dispatch invites to users for invitee_id in users_allowed { svc.dispatch_user_invite_received( @@ -58,12 +39,7 @@ pub async fn handler( Ok(CreatePrivateChannelResponse::new(channel_id).into_response()) } -pub async fn logic( - deps: &Dependencies, - creator_id: u64, - mut members: Vec, - is_locked: bool, -) -> ServerResult { +pub async fn logic(deps: &Dependencies, creator_id: u64, is_dm: bool) -> ServerResult { let chat_tree = &deps.chat_tree; let channel_id = { @@ -75,12 +51,10 @@ pub async fn logic( channel_id }; - // add creator to members since it might not be in the members list - members.push(creator_id); - // deduplicate user ids - members.dedup(); - - let private_channel = PrivateChannel { members, is_locked }; + let private_channel = PrivateChannel { + members: vec![creator_id], + is_dm, + }; let serialized = rkyv_ser(&private_channel); let mut batch = Batch::default(); diff --git a/src/impls/chat/private_channels/delete_private_channel.rs b/src/impls/chat/private_channels/delete_private_channel.rs index 1292882..9f2c586 100644 --- a/src/impls/chat/private_channels/delete_private_channel.rs +++ b/src/impls/chat/private_channels/delete_private_channel.rs @@ -15,6 +15,15 @@ pub async fn handler( let deleted_channel = logic(svc.deps.as_ref(), user_id, channel_id).await?; + svc.broadcast( + EventSub::PrivateChannel(channel_id), + stream_event::Event::PrivateChannelDeleted(stream_event::PrivateChannelDeleted { + channel_id, + }), + None, + EventContext::empty(), + ); + for member in deleted_channel.members { svc.dispatch_private_channel_leave(channel_id, member) .await?; diff --git a/src/impls/chat/private_channels/join_private_channel.rs b/src/impls/chat/private_channels/join_private_channel.rs new file mode 100644 index 0000000..60e4755 --- /dev/null +++ b/src/impls/chat/private_channels/join_private_channel.rs @@ -0,0 +1,50 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let JoinPrivateChannelRequest { channel_id } = request.into_message().await?; + + let channel_id = logic(svc.deps.as_ref(), user_id, channel_id).await?; + + svc.broadcast( + EventSub::PrivateChannel(channel_id), + stream_event::Event::UserJoinedPrivateChannel(stream_event::UserJoinedPrivateChannel { + channel_id, + user_id, + }), + None, + EventContext::empty(), + ); + + svc.dispatch_private_channel_join(channel_id, user_id) + .await?; + + Ok(JoinPrivateChannelResponse::new().into_response()) +} + +pub async fn logic(deps: &Dependencies, user_id: u64, channel_id: u64) -> ServerResult { + let invite_id = channel_id.to_string(); + let channel_id = deps + .chat_tree + .use_priv_invite_logic(user_id, &invite_id) + .await?; + + let mut private_channel = deps.chat_tree.get_private_channel_logic(channel_id).await?; + + if private_channel.members.contains(&user_id) { + bail!(("h.already-joined", "you are already in the private channel")); + } + + private_channel.members.push(user_id); + + let serialized = rkyv_ser(&private_channel); + deps.chat_tree + .insert(make_pc_key(channel_id), serialized) + .await?; + + Ok(channel_id) +} diff --git a/src/impls/chat/private_channels/leave_private_channel.rs b/src/impls/chat/private_channels/leave_private_channel.rs new file mode 100644 index 0000000..2ed9c95 --- /dev/null +++ b/src/impls/chat/private_channels/leave_private_channel.rs @@ -0,0 +1,62 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let LeavePrivateChannelRequest { channel_id } = request.into_message().await?; + + svc.deps + .chat_tree + .check_private_channel_user(channel_id, user_id) + .await?; + + logic(svc.deps.as_ref(), user_id, channel_id).await?; + + svc.broadcast( + EventSub::PrivateChannel(channel_id), + stream_event::Event::UserLeftPrivateChannel(stream_event::UserLeftPrivateChannel { + channel_id, + user_id, + }), + None, + EventContext::empty(), + ); + + svc.dispatch_private_channel_leave(channel_id, user_id) + .await?; + + Ok(LeavePrivateChannelResponse::new().into_response()) +} + +pub async fn logic(deps: &Dependencies, user_id: u64, channel_id: u64) -> ServerResult<()> { + if deps + .chat_tree + .is_user_private_channel_creator(channel_id, user_id) + .await? + { + bail!(( + "h.cant-leave", + "private channel creators cant leave the channel, they must delete it" + )); + } + + let mut private_channel = deps.chat_tree.get_private_channel_logic(channel_id).await?; + + if let Some(pos) = private_channel.members.iter().position(|id| user_id.eq(id)) { + private_channel.members.remove(pos); + } else { + bail!(ServerError::UserNotInPrivateChannel { + channel_id, + user_id + }); + } + + deps.chat_tree + .insert(make_pc_key(channel_id), rkyv_ser(&private_channel)) + .await?; + + Ok(()) +} diff --git a/src/impls/chat/private_channels/mod.rs b/src/impls/chat/private_channels/mod.rs index 0cb21b5..4d7cfe5 100644 --- a/src/impls/chat/private_channels/mod.rs +++ b/src/impls/chat/private_channels/mod.rs @@ -3,4 +3,6 @@ use super::*; pub mod create_private_channel; pub mod delete_private_channel; pub mod get_private_channel_list; +pub mod join_private_channel; +pub mod leave_private_channel; pub mod update_private_channel_members; diff --git a/src/impls/chat/private_channels/update_private_channel_members.rs b/src/impls/chat/private_channels/update_private_channel_members.rs index 03d2109..f362534 100644 --- a/src/impls/chat/private_channels/update_private_channel_members.rs +++ b/src/impls/chat/private_channels/update_private_channel_members.rs @@ -19,40 +19,6 @@ pub async fn handler( let (added, removed) = logic(svc, channel_id, added_members, removed_members).await?; - // update invite allowed users - svc.deps - .chat_tree - .update_priv_invite_allowed_users(channel_id.to_string(), |allowed_users| { - allowed_users.retain(|id| removed.contains(id).not()); - allowed_users.extend(added.iter().copied()); - }) - .await?; - - // insert new outgoing invites for user - let mut user_outgoing_invites = Vec::with_capacity(added.len()); - for invitee_id in added.iter().copied() { - let (invitee_id, server_id) = svc - .deps - .profile_tree - .local_to_foreign_id(invitee_id) - .await? - .map_or((invitee_id, None), |(id, server_id)| { - (id, Some(server_id.to_string())) - }); - - let invite = OutgoingInvite { - invitee_id, - server_id, - location: Some(outgoing_invite::Location::ChannelId(channel_id)), - }; - - user_outgoing_invites.push(invite); - } - svc.deps - .chat_tree - .modify_user_outgoing_invites(user_id, |invites| Ok(invites.extend(user_outgoing_invites))) - .await?; - // dispatch invites to new members for invitee_id in added { svc.dispatch_user_invite_received( @@ -82,6 +48,13 @@ pub async fn logic( let mut private_channel = chat_tree.get_private_channel_logic(channel_id).await?; + if private_channel.is_dm { + bail!(( + "h.cant-update-members", + "private channel is a direct message channel, cant change members" + )); + } + let members_before = private_channel.members.clone(); private_channel @@ -107,5 +80,26 @@ pub async fn logic( .filter_map(|id| private_channel.members.contains(id).not().then(|| *id)) .collect::>(); + // remove added members, they didnt join yet + private_channel + .members + .retain(|id| members_added.contains(id).not()); + + // insert new channel + let serialized = rkyv_ser(&private_channel); + svc.deps + .chat_tree + .insert(make_pc_key(channel_id), serialized) + .await?; + + // update invite allowed users + svc.deps + .chat_tree + .update_priv_invite_allowed_users(channel_id.to_string(), |allowed_users| { + allowed_users.retain(|id| members_removed.contains(id).not()); + allowed_users.extend(members_added.iter().copied()); + }) + .await?; + Ok((members_added, members_removed)) } diff --git a/src/impls/sync/mod.rs b/src/impls/sync/mod.rs index 7f2c6bf..a601582 100644 --- a/src/impls/sync/mod.rs +++ b/src/impls/sync/mod.rs @@ -9,8 +9,8 @@ use crate::api::{ use ahash::RandomState; use dashmap::{mapref::one::RefMut, DashMap}; use harmony_rust_sdk::api::chat::{ - outgoing_invite, pending_invite, stream_event as chat_stream_event, - stream_event::Event as ChatEvent, OutgoingInvite, PendingInvite, + pending_invite, stream_event as chat_stream_event, stream_event::Event as ChatEvent, + PendingInvite, }; use hrpc::exports::futures_util::TryFutureExt; use hrpc::{client::transport::http::Hyper, encode::encode_protobuf_message}; @@ -310,6 +310,9 @@ impl SyncServer { chat_tree .add_guild_to_guild_list(user_id, guild_id, host) .await?; + + // TODO: figure out how to remove pending invites for guilds + self.deps.broadcast_chat( EventSub::Homeserver, ChatEvent::GuildAddedToList(chat_stream_event::GuildAddedToList { @@ -337,18 +340,27 @@ impl SyncServer { let invite = PendingInvite { inviter_id, - location: Some(location), + location: Some(location.clone()), server_id: Some(host.to_string()), }; - chat_tree - .add_user_pending_invite(user_id, invite.clone()) - .await?; + chat_tree.add_user_pending_invite(user_id, invite).await?; + + let location = match location { + pending_invite::Location::ChannelId(channel_id) => { + chat_stream_event::invite_received::Location::ChannelId(channel_id) + } + pending_invite::Location::GuildInviteId(invite_id) => { + chat_stream_event::invite_received::Location::GuildInviteId(invite_id) + } + }; self.deps.broadcast_chat( EventSub::Homeserver, ChatEvent::InviteReceived(chat_stream_event::InviteReceived { - invite: Some(invite), + inviter_id, + location: Some(location), + server_id: Some(host.to_string()), }), None, EventContext::new(vec![user_id]), @@ -362,27 +374,19 @@ impl SyncServer { // TODO: add checks for location, user_id and inviter let location = match location.ok_or("location can't be empty")? { user_rejected_invite::Location::GuildInviteId(invite) => { - outgoing_invite::Location::GuildInviteId(invite) + chat_stream_event::invite_rejected::Location::GuildInviteId(invite) } user_rejected_invite::Location::ChannelId(channel_id) => { - outgoing_invite::Location::ChannelId(channel_id) + chat_stream_event::invite_rejected::Location::ChannelId(channel_id) } }; - let invite = OutgoingInvite { - invitee_id: user_id, - location: Some(location), - server_id: Some(host.to_string()), - }; - - chat_tree - .remove_user_outgoing_invite(inviter_id, &invite) - .await?; - self.deps.broadcast_chat( EventSub::Homeserver, ChatEvent::InviteRejected(chat_stream_event::InviteRejected { - invite: Some(invite), + invitee_id: user_id, + location: Some(location), + server_id: Some(host.to_string()), }), None, EventContext::new(vec![inviter_id]), @@ -415,6 +419,15 @@ impl SyncServer { chat_tree .add_pc_to_pc_list(user_id, channel_id, host) .await?; + + let location = pending_invite::Location::ChannelId(channel_id); + let res = chat_tree + .remove_user_pending_invite(user_id, Some(host), &location) + .await; + if res.is_err_and(|err| err.identifier == "h.no-such-pending-invite") { + res?; + } + self.deps.broadcast_chat( EventSub::Homeserver, ChatEvent::PrivateChannelAddedToList( diff --git a/src/lib.rs b/src/lib.rs index ef8c902..eca3cc1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,8 @@ const_intrinsic_copy, const_mut_refs, type_alias_impl_trait, - drain_filter + drain_filter, + is_some_with )] #![allow(clippy::unit_arg, clippy::blocks_in_if_conditions)] From 43ab631bdd29c7ac0c27395dc02b9469aaa66956 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Thu, 7 Apr 2022 22:35:42 +0000 Subject: [PATCH 45/62] feat: implement join on create_private_channel if already has dm --- src/db/mod.rs | 38 +++++++++--- .../create_private_channel.rs | 60 +++++++++++++++++-- .../delete_private_channel.rs | 28 +++++++-- .../private_channels/join_private_channel.rs | 33 ++++++---- 4 files changed, 128 insertions(+), 31 deletions(-) diff --git a/src/db/mod.rs b/src/db/mod.rs index 89fecbd..48777c0 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -94,6 +94,11 @@ impl Batch { pub fn remove(&mut self, key: impl Into) { self.inserts.push((key.into(), None)); } + + pub fn merge(mut self, other: Batch) -> Self { + self.inserts.extend(other.inserts); + self + } } #[derive(Debug)] @@ -194,6 +199,7 @@ pub mod chat { use super::concat_static; + pub const DM_WITH_USER_PREFIX: &[u8] = b"dm_with_"; pub const PENDING_INVITES_PREFIX: &[u8] = b"pending_invites_"; pub const INVITE_PREFIX: &[u8] = b"invite_"; pub const PRIV_INVITE_PREFIX: &[u8] = b"priv_invite_"; @@ -457,6 +463,15 @@ pub mod chat { [&make_priv_invite_key(name), "_allowed_users".as_bytes()].concat() } + pub const fn make_dm_with_user_key(user_id: u64, other_user_id: u64) -> [u8; 25] { + concat_static(&[ + DM_WITH_USER_PREFIX, + &user_id.to_be_bytes(), + &[b'_'], + &other_user_id.to_be_bytes(), + ]) + } + #[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Default, Debug)] #[archive_attr(derive(bytecheck::CheckBytes))] pub struct UserPendingInvites { @@ -501,15 +516,22 @@ pub mod sync { } } +pub async fn create_batch_delete_prefix( + tree: &Tree, + prefix: impl AsRef<[u8]>, +) -> ServerResult { + tree.scan_prefix(prefix.as_ref()) + .await + .try_fold(Batch::default(), |mut batch, res| { + let (key, _) = res.map_err(ServerError::from)?; + batch.remove(key); + ServerResult::Ok(batch) + }) + .map_err(Into::into) +} + pub async fn batch_delete_prefix(tree: &Tree, prefix: impl AsRef<[u8]>) -> ServerResult<()> { - let batch = - tree.scan_prefix(prefix.as_ref()) - .await - .try_fold(Batch::default(), |mut batch, res| { - let (key, _) = res.map_err(ServerError::from)?; - batch.remove(key); - ServerResult::Ok(batch) - })?; + let batch = create_batch_delete_prefix(tree, prefix).await?; tree.apply_batch(batch).await?; Ok(()) } diff --git a/src/impls/chat/private_channels/create_private_channel.rs b/src/impls/chat/private_channels/create_private_channel.rs index 87193ad..b4f1543 100644 --- a/src/impls/chat/private_channels/create_private_channel.rs +++ b/src/impls/chat/private_channels/create_private_channel.rs @@ -11,11 +11,52 @@ pub async fn handler( is_dm, } = request.into_message().await?; - let channel_id = logic(svc.deps.as_ref(), user_id, is_dm).await?; + users_allowed.dedup(); - // TODO: add logic for detecting an already existing dm for user with the other user + if users_allowed.contains(&user_id) { + bail!(( + "h.cant-allow-self", + "you cant add yourself to members for private channel, it is implied" + )); + } - users_allowed.dedup(); + if is_dm && users_allowed.len() != 1 { + bail!(( + "h.must-have-one-member", + "private channels must have one member if they are direct message channels" + )); + } + + let maybe_dm_channel = if is_dm { + svc.deps + .chat_tree + .get(make_dm_with_user_key(user_id, users_allowed[0])) + .await? + .map(db::deser_id) + } else { + None + }; + + if let Some(channel_id) = maybe_dm_channel { + join_private_channel::logic(svc.deps.as_ref(), user_id, channel_id).await?; + + svc.broadcast( + EventSub::PrivateChannel(channel_id), + stream_event::Event::UserJoinedPrivateChannel(stream_event::UserJoinedPrivateChannel { + channel_id, + user_id, + }), + None, + EventContext::empty(), + ); + + svc.dispatch_private_channel_join(channel_id, user_id) + .await?; + + return Ok(CreatePrivateChannelResponse::new(channel_id).into_response()); + } + + let channel_id = logic(svc.deps.as_ref(), &users_allowed, user_id, is_dm).await?; svc.dispatch_private_channel_join(channel_id, user_id) .await?; @@ -39,7 +80,12 @@ pub async fn handler( Ok(CreatePrivateChannelResponse::new(channel_id).into_response()) } -pub async fn logic(deps: &Dependencies, creator_id: u64, is_dm: bool) -> ServerResult { +pub async fn logic( + deps: &Dependencies, + users_allowed: &[u64], + creator_id: u64, + is_dm: bool, +) -> ServerResult { let chat_tree = &deps.chat_tree; let channel_id = { @@ -60,6 +106,12 @@ pub async fn logic(deps: &Dependencies, creator_id: u64, is_dm: bool) -> ServerR let mut batch = Batch::default(); batch.insert(make_pc_creator_key(channel_id), creator_id.to_be_bytes()); batch.insert(make_pc_key(channel_id), serialized); + if is_dm { + batch.insert( + make_dm_with_user_key(creator_id, users_allowed[0]), + channel_id.to_be_bytes(), + ); + } chat_tree.apply_batch(batch).await?; Ok(channel_id) diff --git a/src/impls/chat/private_channels/delete_private_channel.rs b/src/impls/chat/private_channels/delete_private_channel.rs index 9f2c586..e57593d 100644 --- a/src/impls/chat/private_channels/delete_private_channel.rs +++ b/src/impls/chat/private_channels/delete_private_channel.rs @@ -54,14 +54,30 @@ pub async fn logic( let private_channel = chat_tree.get_private_channel_logic(channel_id).await?; - db::batch_delete_prefix(&chat_tree.chat_tree, make_pc_key(channel_id)).await?; + let batch = + db::create_batch_delete_prefix(&chat_tree.chat_tree, make_pc_key(channel_id)).await?; // also delete invite, if any - db::batch_delete_prefix( - &chat_tree.chat_tree, - make_priv_invite_key(&channel_id.to_string()), - ) - .await?; + let mut batch = batch.merge( + db::create_batch_delete_prefix( + &chat_tree.chat_tree, + make_priv_invite_key(&channel_id.to_string()), + ) + .await?, + ); + + if private_channel.is_dm { + batch.remove(make_dm_with_user_key( + private_channel.members[0], + private_channel.members[1], + )); + batch.remove(make_dm_with_user_key( + private_channel.members[1], + private_channel.members[0], + )); + } + + chat_tree.apply_batch(batch).await?; Ok(private_channel) } diff --git a/src/impls/chat/private_channels/join_private_channel.rs b/src/impls/chat/private_channels/join_private_channel.rs index 60e4755..e57965c 100644 --- a/src/impls/chat/private_channels/join_private_channel.rs +++ b/src/impls/chat/private_channels/join_private_channel.rs @@ -8,7 +8,14 @@ pub async fn handler( let JoinPrivateChannelRequest { channel_id } = request.into_message().await?; - let channel_id = logic(svc.deps.as_ref(), user_id, channel_id).await?; + let invite_id = channel_id.to_string(); + let channel_id = svc + .deps + .chat_tree + .use_priv_invite_logic(user_id, &invite_id) + .await?; + + logic(svc.deps.as_ref(), user_id, channel_id).await?; svc.broadcast( EventSub::PrivateChannel(channel_id), @@ -26,25 +33,25 @@ pub async fn handler( Ok(JoinPrivateChannelResponse::new().into_response()) } -pub async fn logic(deps: &Dependencies, user_id: u64, channel_id: u64) -> ServerResult { - let invite_id = channel_id.to_string(); - let channel_id = deps - .chat_tree - .use_priv_invite_logic(user_id, &invite_id) - .await?; - +pub async fn logic(deps: &Dependencies, user_id: u64, channel_id: u64) -> ServerResult<()> { let mut private_channel = deps.chat_tree.get_private_channel_logic(channel_id).await?; if private_channel.members.contains(&user_id) { bail!(("h.already-joined", "you are already in the private channel")); } + let other_user_id = private_channel.members[0]; private_channel.members.push(user_id); - let serialized = rkyv_ser(&private_channel); - deps.chat_tree - .insert(make_pc_key(channel_id), serialized) - .await?; + let mut batch = Batch::default(); + batch.insert(make_pc_key(channel_id), rkyv_ser(&private_channel)); + if private_channel.is_dm { + batch.insert( + make_dm_with_user_key(user_id, other_user_id), + channel_id.to_be_bytes(), + ); + } + deps.chat_tree.apply_batch(batch).await?; - Ok(channel_id) + Ok(()) } From 9ffc547e9f1a9c3e23edd6636aba2f445d084a8d Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Thu, 7 Apr 2022 23:27:12 +0000 Subject: [PATCH 46/62] feat: update sdk --- Cargo.lock | 38 +++++++++++++++++++------------------- src/impls/chat/mod.rs | 4 ++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f44606e..1d6518f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -897,7 +897,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#e2044a4d9a0151b4b06b782c5c28873da1e5384b" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f0d72f12ac935aaebc534f6156dd0956c14b3a0a" dependencies = [ "hrpc-build", "prost-build 0.10.0", @@ -908,7 +908,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#e2044a4d9a0151b4b06b782c5c28873da1e5384b" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f0d72f12ac935aaebc534f6156dd0956c14b3a0a" dependencies = [ "proc-macro2", "quote", @@ -918,7 +918,7 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#e2044a4d9a0151b4b06b782c5c28873da1e5384b" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f0d72f12ac935aaebc534f6156dd0956c14b3a0a" dependencies = [ "bytecheck", "harmony_build", @@ -1294,9 +1294,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] @@ -3380,9 +3380,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3390,9 +3390,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static", @@ -3405,9 +3405,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" dependencies = [ "cfg-if", "js-sys", @@ -3417,9 +3417,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3427,9 +3427,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", @@ -3440,15 +3440,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" [[package]] name = "web-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index d23b4df..d7213f4 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -1056,7 +1056,7 @@ impl ChatTree { self.get_user_pc_guilds(prefix, |guild_id, host| { host.is_empty().then(|| GuildListEntry { guild_id, - server_id: String::new(), + server_id: None, }) }) .await @@ -1067,7 +1067,7 @@ impl ChatTree { self.get_user_pc_guilds(prefix, |guild_id, host| { Some(GuildListEntry { guild_id, - server_id: host.to_string(), + server_id: host.is_empty().not().then(|| host.to_string()), }) }) .await From 73e23b1c2222fbe86b72c00ff127a175daf69091 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Fri, 8 Apr 2022 23:16:19 +0000 Subject: [PATCH 47/62] fix: does_username_exist panic, reorder check_channel_user arguments so its correct order --- src/impls/chat/mod.rs | 6 +++--- src/impls/profile/mod.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index d7213f4..251bb5b 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -814,8 +814,8 @@ impl ChatTree { pub async fn check_channel_user( &self, guild_id: Option, - channel_id: u64, user_id: u64, + channel_id: u64, ) -> ServerResult<()> { if let Some(guild_id) = guild_id { self.check_guild_user_channel(guild_id, user_id, channel_id) @@ -1449,8 +1449,8 @@ impl ChatTree { check_for: &str, must_be_guild_owner: bool, ) -> Result<(), ServerError> { - let guild_id = guild_id.into(); - let Some(guild_id) = guild_id else { + let Some(guild_id) = guild_id.into() else { + // For private channels, everyone in the channel can do anything return Ok(()); }; let is_owner = self.is_user_guild_owner(guild_id, user_id).await?; diff --git a/src/impls/profile/mod.rs b/src/impls/profile/mod.rs index 702a9c9..6c87ff0 100644 --- a/src/impls/profile/mod.rs +++ b/src/impls/profile/mod.rs @@ -125,8 +125,8 @@ impl ProfileTree { pub async fn does_username_exist(&self, username: &str) -> ServerResult { for res in self.scan_prefix(USER_PREFIX).await { let (_, value) = res?; - let profile = db::rkyv_arch::(&value); - if profile.user_name == username { + let maybe_profile = rkyv::check_archived_root::(&value); + if maybe_profile.map_or(false, |profile| profile.user_name == username) { return Ok(true); } } From 5c86e11a86d379988eb717ddce5cca678f087688 Mon Sep 17 00:00:00 2001 From: Blusk Date: Sun, 10 Apr 2022 18:19:06 -0400 Subject: [PATCH 48/62] partially implement new protocol changes; doesn't compile --- Cargo.lock | 177 ++++++++---------- src/impls/chat/mod.rs | 10 +- .../create_private_channel.rs | 5 +- .../get_private_channel_data.rs | 20 ++ 4 files changed, 113 insertions(+), 99 deletions(-) create mode 100644 src/impls/chat/private_channels/get_private_channel_data.rs diff --git a/Cargo.lock b/Cargo.lock index 1d6518f..5131aec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -181,6 +181,49 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47594e438a243791dba58124b6669561f5baa14cb12046641d8008bf035e5a25" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "sync_wrapper", + "tokio", + "tower", + "tower-http", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a671c9ae99531afdd5d3ee8340b8da547779430689947144c140fc74a740244" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", +] + [[package]] name = "axum-server" version = "0.3.3" @@ -356,20 +399,19 @@ dependencies = [ [[package]] name = "console-api" -version = "0.1.2" -source = "git+https://github.com/tokio-rs/console.git?branch=main#9178ecf02f094f8b23dc26f02faaba4ec09fd8f5" +version = "0.2.0" +source = "git+https://github.com/tokio-rs/console.git?branch=main#d79390303590a534a8224efbe96c6023c336a32f" dependencies = [ - "prost 0.9.0", - "prost-types 0.9.0", + "prost", + "prost-types", "tonic", - "tonic-build", "tracing-core", ] [[package]] name = "console-subscriber" version = "0.1.3" -source = "git+https://github.com/tokio-rs/console.git?branch=main#9178ecf02f094f8b23dc26f02faaba4ec09fd8f5" +source = "git+https://github.com/tokio-rs/console.git?branch=main#d79390303590a534a8224efbe96c6023c336a32f" dependencies = [ "console-api", "crossbeam-channel", @@ -377,7 +419,7 @@ dependencies = [ "futures", "hdrhistogram", "humantime", - "prost-types 0.9.0", + "prost-types", "serde", "serde_json", "thread_local", @@ -897,10 +939,10 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f0d72f12ac935aaebc534f6156dd0956c14b3a0a" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#dc9d4c4d22b7303c2215400a7dbb6389ce8a6b14" dependencies = [ "hrpc-build", - "prost-build 0.10.0", + "prost-build", "regex", "walkdir", ] @@ -908,7 +950,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f0d72f12ac935aaebc534f6156dd0956c14b3a0a" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#dc9d4c4d22b7303c2215400a7dbb6389ce8a6b14" dependencies = [ "proc-macro2", "quote", @@ -918,14 +960,14 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#f0d72f12ac935aaebc534f6156dd0956c14b3a0a" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#dc9d4c4d22b7303c2215400a7dbb6389ce8a6b14" dependencies = [ "bytecheck", "harmony_build", "harmony_derive", "hrpc", "http", - "prost 0.10.0", + "prost", "rkyv", "serde", "urlencoding", @@ -1036,8 +1078,8 @@ dependencies = [ "hyper-rustls", "matchit", "pin-project-lite", - "prost 0.10.0", - "prost-build 0.10.0", + "prost", + "prost-build", "sha-1", "tokio", "tokio-tungstenite", @@ -1052,7 +1094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace803952c7504e41d30016a4e2573cc3f97bdd32479f951eb3e68c2b48d6a24" dependencies = [ "proc-macro2", - "prost-build 0.10.0", + "prost-build", "quote", "syn", ] @@ -1951,16 +1993,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "prost" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" -dependencies = [ - "bytes", - "prost-derive 0.9.0", -] - [[package]] name = "prost" version = "0.10.0" @@ -1968,27 +2000,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd5316aa8f5c82add416dfbc25116b84b748a21153f512917e8143640a71bbd" dependencies = [ "bytes", - "prost-derive 0.10.0", -] - -[[package]] -name = "prost-build" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" -dependencies = [ - "bytes", - "heck 0.3.3", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prost 0.9.0", - "prost-types 0.9.0", - "regex", - "tempfile", - "which", + "prost-derive", ] [[package]] @@ -2006,26 +2018,13 @@ dependencies = [ "log", "multimap", "petgraph", - "prost 0.10.0", - "prost-types 0.10.0", + "prost", + "prost-types", "regex", "tempfile", "which", ] -[[package]] -name = "prost-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "prost-derive" version = "0.10.0" @@ -2039,16 +2038,6 @@ dependencies = [ "syn", ] -[[package]] -name = "prost-types" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" -dependencies = [ - "bytes", - "prost 0.9.0", -] - [[package]] name = "prost-types" version = "0.10.0" @@ -2056,7 +2045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "926681c118ae6e512a3ccefd4abbe5521a14f4cc1e207356d4d00c0b7f2006fd" dependencies = [ "bytes", - "prost 0.10.0", + "prost", ] [[package]] @@ -2383,7 +2372,7 @@ dependencies = [ "parking_lot 0.12.0", "paste 1.0.7", "pin-project", - "prost 0.10.0", + "prost", "rand", "reqwest", "rkyv", @@ -2598,9 +2587,9 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "smol_str" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61d15c83e300cce35b7c8cd39ff567c1ef42dde6d4a1a38dbdbf9a59902261bd" +checksum = "167ee181c12079444893cec9c8f21b13d6b314af789c9fdb041a0645f11ed9d2" dependencies = [ "serde", ] @@ -2772,6 +2761,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "sync_wrapper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + [[package]] name = "tempfile" version = "3.3.0" @@ -3032,12 +3027,13 @@ dependencies = [ [[package]] name = "tonic" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" +checksum = "30fb54bf1e446f44d870d260d99957e7d11fb9d0a0f5bd1a662ad1411cc103f9" dependencies = [ "async-stream", "async-trait", + "axum", "base64", "bytes", "futures-core", @@ -3049,11 +3045,11 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost 0.9.0", - "prost-derive 0.9.0", + "prost", + "prost-derive", "tokio", "tokio-stream", - "tokio-util 0.6.9", + "tokio-util 0.7.1", "tower", "tower-layer", "tower-service", @@ -3061,18 +3057,6 @@ dependencies = [ "tracing-futures", ] -[[package]] -name = "tonic-build" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757" -dependencies = [ - "proc-macro2", - "prost-build 0.9.0", - "quote", - "syn", -] - [[package]] name = "tower" version = "0.4.12" @@ -3107,6 +3091,7 @@ dependencies = [ "http-body", "http-range-header", "pin-project-lite", + "tower", "tower-layer", "tower-service", "tracing", @@ -3126,9 +3111,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +checksum = "80b9fa4360528139bc96100c160b7ae879f5567f49f1782b0b02035b0358ebf3" dependencies = [ "cfg-if", "log", @@ -3194,9 +3179,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9df98b037d039d03400d9dd06b0f8ce05486b5f25e9a2d7d36196e142ebbc52" +checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" dependencies = [ "ansi_term", "sharded-slab", diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 251bb5b..b76d9da 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -1023,6 +1023,12 @@ impl ChatTree { Ok((message, key)) } + pub async fn get_user_local_private_channel_data( + &self, + user_id: u64, + ) -> ServerResult> { + } + pub async fn get_user_local_private_channels( &self, user_id: u64, @@ -1031,7 +1037,7 @@ impl ChatTree { self.get_user_pc_guilds(prefix, |channel_id, host| { host.is_empty().then(|| PrivateChannelListEntry { channel_id, - server_id: String::new(), + server_id: None, }) }) .await @@ -1045,7 +1051,7 @@ impl ChatTree { self.get_user_pc_guilds(prefix, |channel_id, host| { Some(PrivateChannelListEntry { channel_id, - server_id: host.to_string(), + server_id: Some(host.to_string()), }) }) .await diff --git a/src/impls/chat/private_channels/create_private_channel.rs b/src/impls/chat/private_channels/create_private_channel.rs index b4f1543..cbb8d6e 100644 --- a/src/impls/chat/private_channels/create_private_channel.rs +++ b/src/impls/chat/private_channels/create_private_channel.rs @@ -9,6 +9,7 @@ pub async fn handler( let CreatePrivateChannelRequest { members: mut users_allowed, is_dm, + name, } = request.into_message().await?; users_allowed.dedup(); @@ -56,7 +57,7 @@ pub async fn handler( return Ok(CreatePrivateChannelResponse::new(channel_id).into_response()); } - let channel_id = logic(svc.deps.as_ref(), &users_allowed, user_id, is_dm).await?; + let channel_id = logic(svc.deps.as_ref(), &users_allowed, user_id, is_dm, name).await?; svc.dispatch_private_channel_join(channel_id, user_id) .await?; @@ -85,6 +86,7 @@ pub async fn logic( users_allowed: &[u64], creator_id: u64, is_dm: bool, + name: Option, ) -> ServerResult { let chat_tree = &deps.chat_tree; @@ -100,6 +102,7 @@ pub async fn logic( let private_channel = PrivateChannel { members: vec![creator_id], is_dm, + name, }; let serialized = rkyv_ser(&private_channel); diff --git a/src/impls/chat/private_channels/get_private_channel_data.rs b/src/impls/chat/private_channels/get_private_channel_data.rs new file mode 100644 index 0000000..099a842 --- /dev/null +++ b/src/impls/chat/private_channels/get_private_channel_data.rs @@ -0,0 +1,20 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let GetPrivateChannelListRequest { + channel_ids, + } = request.into_message().await?; + + let channels = svc + .deps + .chat_tree + .get_user_private_channels(user_id) + .await?; + + Ok(GetPrivateChannelListResponse::new(channels).into_response()) +} From c00708d71c53f0cd6585f6a617191dbbf91670f9 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Fri, 8 Apr 2022 23:28:40 +0000 Subject: [PATCH 49/62] fix: check if in_reply_to message actually exists --- src/impls/chat/messages/send_message.rs | 19 ++++++++++++++++++- src/impls/chat/mod.rs | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/impls/chat/messages/send_message.rs b/src/impls/chat/messages/send_message.rs index 2cc5d41..c6e3828 100644 --- a/src/impls/chat/messages/send_message.rs +++ b/src/impls/chat/messages/send_message.rs @@ -24,7 +24,24 @@ pub async fn handler( .check_perms(guild_id, Some(channel_id), user_id, "messages.send", false) .await?; - chat_tree.process_message_overrides(request.overrides.as_ref())?; + // check if the in reply to message actually exists + if let Some(in_reply_to) = request.in_reply_to { + let has_msg = chat_tree + .contains_key(make_msg_key(guild_id, channel_id, in_reply_to)) + .await?; + if has_msg.not() { + bail!(ServerError::NoSuchMessage { + guild_id, + channel_id, + message_id: in_reply_to + }); + } + } + + // check overrides + chat_tree.check_message_overrides(request.overrides.as_ref())?; + + // process content (attachments etc) let content = chat_tree .process_message_content(svc.deps.as_ref(), request.content.take()) .await?; diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index b76d9da..51240ac 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -2083,7 +2083,7 @@ impl ChatTree { Ok((message_id, message)) } - pub fn process_message_overrides(&self, overrides: Option<&Overrides>) -> ServerResult<()> { + pub fn check_message_overrides(&self, overrides: Option<&Overrides>) -> ServerResult<()> { if let Some(ov) = overrides { if ov.username.as_ref().map_or(false, String::is_empty) { bail!(( From 3607903d0eea86d8605337790bf9b35c714b4644 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 10 Apr 2022 23:13:50 +0000 Subject: [PATCH 50/62] feat: implement update_private_channel_name and get_private_channel --- Cargo.lock | 6 ++-- src/impls/chat/mod.rs | 19 +++-------- .../delete_private_channel.rs | 2 +- .../private_channels/get_private_channel.rs | 34 +++++++++++++++++++ .../get_private_channel_data.rs | 20 ----------- .../private_channels/join_private_channel.rs | 2 +- .../private_channels/leave_private_channel.rs | 2 +- src/impls/chat/private_channels/mod.rs | 2 ++ .../update_private_channel_members.rs | 4 +-- .../update_private_channel_name.rs | 33 ++++++++++++++++++ 10 files changed, 80 insertions(+), 44 deletions(-) create mode 100644 src/impls/chat/private_channels/get_private_channel.rs delete mode 100644 src/impls/chat/private_channels/get_private_channel_data.rs create mode 100644 src/impls/chat/private_channels/update_private_channel_name.rs diff --git a/Cargo.lock b/Cargo.lock index 5131aec..84c4e6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -939,7 +939,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#dc9d4c4d22b7303c2215400a7dbb6389ce8a6b14" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9e777d5121997ea360c6fabb26cdd7848a81a1ee" dependencies = [ "hrpc-build", "prost-build", @@ -950,7 +950,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#dc9d4c4d22b7303c2215400a7dbb6389ce8a6b14" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9e777d5121997ea360c6fabb26cdd7848a81a1ee" dependencies = [ "proc-macro2", "quote", @@ -960,7 +960,7 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#dc9d4c4d22b7303c2215400a7dbb6389ce8a6b14" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9e777d5121997ea360c6fabb26cdd7848a81a1ee" dependencies = [ "bytecheck", "harmony_build", diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 51240ac..25e495f 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -744,6 +744,8 @@ impl chat_service_server::ChatService for ChatServer { grant_ownership, GrantOwnershipRequest, GrantOwnershipResponse; #[rate(2, 60)] give_up_ownership, GiveUpOwnershipRequest, GiveUpOwnershipResponse; + #[rate(5, 5)] + get_private_channel, GetPrivateChannelRequest, GetPrivateChannelResponse; #[rate(1, 20)] create_private_channel, CreatePrivateChannelRequest, CreatePrivateChannelResponse; #[rate(3, 8)] @@ -756,6 +758,8 @@ impl chat_service_server::ChatService for ChatServer { get_private_channel_list, GetPrivateChannelListRequest, GetPrivateChannelListResponse; #[rate(3, 8)] update_private_channel_members, UpdatePrivateChannelMembersRequest, UpdatePrivateChannelMembersResponse; + #[rate(3, 8)] + update_private_channel_name, UpdatePrivateChannelNameRequest, UpdatePrivateChannelNameResponse; #[rate(4, 8)] invite_user_to_guild, InviteUserToGuildRequest, InviteUserToGuildResponse; #[rate(5 ,5)] @@ -1023,12 +1027,6 @@ impl ChatTree { Ok((message, key)) } - pub async fn get_user_local_private_channel_data( - &self, - user_id: u64, - ) -> ServerResult> { - } - pub async fn get_user_local_private_channels( &self, user_id: u64, @@ -1101,15 +1099,6 @@ impl ChatTree { Ok(list) } - pub async fn get_private_channel_logic(&self, channel_id: u64) -> ServerResult { - let key = make_pc_key(channel_id); - let private_channel_raw = self - .get(&key) - .await? - .ok_or(ServerError::NoSuchPrivateChannel(channel_id))?; - Ok(db::deser_private_channel(private_channel_raw)) - } - pub async fn get_guild_logic(&self, guild_id: u64) -> ServerResult { let guild = if let Some(guild_raw) = self.get(guild_id.to_be_bytes().as_ref()).await? { db::deser_guild(guild_raw) diff --git a/src/impls/chat/private_channels/delete_private_channel.rs b/src/impls/chat/private_channels/delete_private_channel.rs index e57593d..92c1851 100644 --- a/src/impls/chat/private_channels/delete_private_channel.rs +++ b/src/impls/chat/private_channels/delete_private_channel.rs @@ -52,7 +52,7 @@ pub async fn logic( )); } - let private_channel = chat_tree.get_private_channel_logic(channel_id).await?; + let private_channel = get_private_channel::logic(deps, channel_id).await?; let batch = db::create_batch_delete_prefix(&chat_tree.chat_tree, make_pc_key(channel_id)).await?; diff --git a/src/impls/chat/private_channels/get_private_channel.rs b/src/impls/chat/private_channels/get_private_channel.rs new file mode 100644 index 0000000..dbda552 --- /dev/null +++ b/src/impls/chat/private_channels/get_private_channel.rs @@ -0,0 +1,34 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let GetPrivateChannelRequest { channel_ids } = request.into_message().await?; + + for channel_id in channel_ids.iter().copied() { + svc.deps + .chat_tree + .check_private_channel_user(channel_id, user_id) + .await?; + } + + let mut channels = HashMap::with_capacity(channel_ids.len()); + for channel_id in channel_ids { + let channel = logic(svc.deps.as_ref(), channel_id).await?; + channels.insert(channel_id, channel); + } + + Ok(GetPrivateChannelResponse::new(channels).into_response()) +} + +pub async fn logic(deps: &Dependencies, channel_id: u64) -> ServerResult { + deps.chat_tree + .get(make_pc_key(channel_id)) + .await? + .ok_or(ServerError::NoSuchPrivateChannel(channel_id)) + .map(db::deser_private_channel) + .map_err(Into::into) +} diff --git a/src/impls/chat/private_channels/get_private_channel_data.rs b/src/impls/chat/private_channels/get_private_channel_data.rs deleted file mode 100644 index 099a842..0000000 --- a/src/impls/chat/private_channels/get_private_channel_data.rs +++ /dev/null @@ -1,20 +0,0 @@ -use super::*; - -pub async fn handler( - svc: &ChatServer, - request: Request, -) -> ServerResult> { - let user_id = svc.deps.auth(&request).await?; - - let GetPrivateChannelListRequest { - channel_ids, - } = request.into_message().await?; - - let channels = svc - .deps - .chat_tree - .get_user_private_channels(user_id) - .await?; - - Ok(GetPrivateChannelListResponse::new(channels).into_response()) -} diff --git a/src/impls/chat/private_channels/join_private_channel.rs b/src/impls/chat/private_channels/join_private_channel.rs index e57965c..3ec4f81 100644 --- a/src/impls/chat/private_channels/join_private_channel.rs +++ b/src/impls/chat/private_channels/join_private_channel.rs @@ -34,7 +34,7 @@ pub async fn handler( } pub async fn logic(deps: &Dependencies, user_id: u64, channel_id: u64) -> ServerResult<()> { - let mut private_channel = deps.chat_tree.get_private_channel_logic(channel_id).await?; + let mut private_channel = get_private_channel::logic(deps, channel_id).await?; if private_channel.members.contains(&user_id) { bail!(("h.already-joined", "you are already in the private channel")); diff --git a/src/impls/chat/private_channels/leave_private_channel.rs b/src/impls/chat/private_channels/leave_private_channel.rs index 2ed9c95..40db3f5 100644 --- a/src/impls/chat/private_channels/leave_private_channel.rs +++ b/src/impls/chat/private_channels/leave_private_channel.rs @@ -43,7 +43,7 @@ pub async fn logic(deps: &Dependencies, user_id: u64, channel_id: u64) -> Server )); } - let mut private_channel = deps.chat_tree.get_private_channel_logic(channel_id).await?; + let mut private_channel = get_private_channel::logic(deps, channel_id).await?; if let Some(pos) = private_channel.members.iter().position(|id| user_id.eq(id)) { private_channel.members.remove(pos); diff --git a/src/impls/chat/private_channels/mod.rs b/src/impls/chat/private_channels/mod.rs index 4d7cfe5..9c44730 100644 --- a/src/impls/chat/private_channels/mod.rs +++ b/src/impls/chat/private_channels/mod.rs @@ -2,7 +2,9 @@ use super::*; pub mod create_private_channel; pub mod delete_private_channel; +pub mod get_private_channel; pub mod get_private_channel_list; pub mod join_private_channel; pub mod leave_private_channel; pub mod update_private_channel_members; +pub mod update_private_channel_name; diff --git a/src/impls/chat/private_channels/update_private_channel_members.rs b/src/impls/chat/private_channels/update_private_channel_members.rs index f362534..4176c6a 100644 --- a/src/impls/chat/private_channels/update_private_channel_members.rs +++ b/src/impls/chat/private_channels/update_private_channel_members.rs @@ -44,9 +44,7 @@ pub async fn logic( added: Vec, removed: Vec, ) -> ServerResult<(Vec, Vec)> { - let chat_tree = &svc.deps.chat_tree; - - let mut private_channel = chat_tree.get_private_channel_logic(channel_id).await?; + let mut private_channel = get_private_channel::logic(svc.deps.as_ref(), channel_id).await?; if private_channel.is_dm { bail!(( diff --git a/src/impls/chat/private_channels/update_private_channel_name.rs b/src/impls/chat/private_channels/update_private_channel_name.rs new file mode 100644 index 0000000..72a1092 --- /dev/null +++ b/src/impls/chat/private_channels/update_private_channel_name.rs @@ -0,0 +1,33 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let UpdatePrivateChannelNameRequest { + channel_id, + name: new_name, + } = request.into_message().await?; + + svc.deps + .chat_tree + .check_private_channel_user(channel_id, user_id) + .await?; + + logic(svc.deps.as_ref(), channel_id, new_name).await?; + + Ok(UpdatePrivateChannelNameResponse::new().into_response()) +} + +pub async fn logic(deps: &Dependencies, channel_id: u64, new_name: String) -> ServerResult<()> { + let mut private_channel = get_private_channel::logic(deps, channel_id).await?; + private_channel.name = new_name.is_empty().not().then(|| new_name); + + deps.chat_tree + .insert(make_pc_key(channel_id), rkyv_ser(&private_channel)) + .await?; + + Ok(()) +} From 80c448471103877f33675409f27c7fcdbf821652 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 12 Apr 2022 02:17:36 +0000 Subject: [PATCH 51/62] feat: don't compile array length checks for release --- src/db/mod.rs | 89 ++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/src/db/mod.rs b/src/db/mod.rs index 48777c0..f8fa561 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -131,13 +131,13 @@ pub fn make_u64_iter_logic(raw: &[u8]) -> impl Iterator + '_ { } pub mod profile { - use super::concat_static; + use super::concat_arrs; pub const USER_PREFIX: &[u8] = b"user_"; pub const FOREIGN_PREFIX: &[u8] = b"fuser_"; pub const fn make_local_to_foreign_user_key(local_id: u64) -> [u8; 15] { - concat_static(&[FOREIGN_PREFIX, &local_id.to_be_bytes(), &[2]]) + concat_arrs(&[FOREIGN_PREFIX, &local_id.to_be_bytes(), &[2]]) } pub fn make_foreign_to_local_user_key(foreign_id: u64, host: &str) -> Vec { @@ -151,11 +151,11 @@ pub mod profile { } pub const fn make_user_profile_key(user_id: u64) -> [u8; 13] { - concat_static(&[USER_PREFIX, &user_id.to_be_bytes()]) + concat_arrs(&[USER_PREFIX, &user_id.to_be_bytes()]) } pub fn make_user_metadata_prefix(user_id: u64) -> [u8; 14] { - concat_static(&[make_user_profile_key(user_id).as_ref(), [1].as_ref()]) + concat_arrs(&[make_user_profile_key(user_id).as_ref(), [1].as_ref()]) } pub fn make_user_metadata_key(user_id: u64, app_id: &str) -> Vec { @@ -168,12 +168,12 @@ pub mod profile { } pub mod emote { - use super::{concat_static, profile::USER_PREFIX}; + use super::{concat_arrs, profile::USER_PREFIX}; pub const EMOTEPACK_PREFIX: &[u8] = b"emotep_"; pub const fn make_emote_pack_key(pack_id: u64) -> [u8; 15] { - concat_static(&[EMOTEPACK_PREFIX, &pack_id.to_be_bytes()]) + concat_arrs(&[EMOTEPACK_PREFIX, &pack_id.to_be_bytes()]) } pub fn make_emote_pack_emote_key(pack_id: u64, image_id: &str) -> Vec { @@ -186,18 +186,18 @@ pub mod emote { } pub const fn make_equipped_emote_prefix(user_id: u64) -> [u8; 14] { - concat_static(&[USER_PREFIX, &user_id.to_be_bytes(), &[9]]) + concat_arrs(&[USER_PREFIX, &user_id.to_be_bytes(), &[9]]) } pub const fn make_equipped_emote_key(user_id: u64, pack_id: u64) -> [u8; 22] { - concat_static(&[&make_equipped_emote_prefix(user_id), &pack_id.to_be_bytes()]) + concat_arrs(&[&make_equipped_emote_prefix(user_id), &pack_id.to_be_bytes()]) } } pub mod chat { use harmony_rust_sdk::api::chat::PendingInvite; - use super::concat_static; + use super::concat_arrs; pub const DM_WITH_USER_PREFIX: &[u8] = b"dm_with_"; pub const PENDING_INVITES_PREFIX: &[u8] = b"pending_invites_"; @@ -214,11 +214,11 @@ pub mod chat { } pub const fn make_pc_key(channel_id: u64) -> [u8; 13] { - concat_static(&[PRIV_CHANNEL_PREFIX, &channel_id.to_be_bytes()]) + concat_arrs(&[PRIV_CHANNEL_PREFIX, &channel_id.to_be_bytes()]) } pub const fn make_pc_creator_key(channel_id: u64) -> [u8; 14] { - concat_static(&[&make_pc_key(channel_id), &[5]]) + concat_arrs(&[&make_pc_key(channel_id), &[5]]) } pub fn make_guild_perm_key(guild_id: u64, role_id: u64, matches: &str) -> Vec { @@ -243,7 +243,7 @@ pub mod chat { } pub const fn make_role_guild_perms_prefix(guild_id: u64, role_id: u64) -> [u8; 18] { - concat_static(&[ + concat_arrs(&[ &make_guild_role_prefix(guild_id), &role_id.to_be_bytes(), &[9], @@ -251,11 +251,11 @@ pub mod chat { } pub const fn make_guild_role_key(guild_id: u64, role_id: u64) -> [u8; 17] { - concat_static(&[&make_guild_role_prefix(guild_id), &role_id.to_be_bytes()]) + concat_arrs(&[&make_guild_role_prefix(guild_id), &role_id.to_be_bytes()]) } pub const fn make_guild_user_roles_key(guild_id: u64, user_id: u64) -> [u8; 17] { - concat_static(&[ + concat_arrs(&[ &make_guild_user_roles_prefix(guild_id), &user_id.to_be_bytes(), ]) @@ -266,11 +266,11 @@ pub mod chat { // message pub const fn make_pinned_msgs_key_guild(guild_id: u64, channel_id: u64) -> [u8; 18] { - concat_static(&[&make_chan_key(guild_id, channel_id), &[6]]) + concat_arrs(&[&make_chan_key(guild_id, channel_id), &[6]]) } pub const fn make_pinned_msgs_key_pc(channel_id: u64) -> [u8; 14] { - concat_static(&[&make_pc_key(channel_id), &[6]]) + concat_arrs(&[&make_pc_key(channel_id), &[6]]) } pub fn make_pinned_msgs_key(guild_id: Option, channel_id: u64) -> Vec { @@ -281,11 +281,11 @@ pub mod chat { } pub const fn make_next_msg_id_key_guild(guild_id: u64, channel_id: u64) -> [u8; 18] { - concat_static(&[&make_chan_key(guild_id, channel_id), &[7]]) + concat_arrs(&[&make_chan_key(guild_id, channel_id), &[7]]) } pub const fn make_next_msg_id_key_pc(channel_id: u64) -> [u8; 14] { - concat_static(&[&make_pc_key(channel_id), &[7]]) + concat_arrs(&[&make_pc_key(channel_id), &[7]]) } pub fn make_next_msg_id_key(guild_id: Option, channel_id: u64) -> Vec { @@ -300,7 +300,7 @@ pub mod chat { channel_id: u64, role_id: u64, ) -> [u8; 26] { - concat_static(&[ + concat_arrs(&[ &make_chan_key(guild_id, channel_id), &[8], &role_id.to_be_bytes(), @@ -308,19 +308,19 @@ pub mod chat { } pub const fn make_msg_prefix_pc(channel_id: u64) -> [u8; 13] { - concat_static(&[&make_pc_key(channel_id), &[9]]) + concat_arrs(&[&make_pc_key(channel_id), &[9]]) } pub const fn make_msg_prefix(guild_id: u64, channel_id: u64) -> [u8; 18] { - concat_static(&[&make_chan_key(guild_id, channel_id), &[9]]) + concat_arrs(&[&make_chan_key(guild_id, channel_id), &[9]]) } pub const fn make_msg_key_pc(channel_id: u64, message_id: u64) -> [u8; 21] { - concat_static(&[&make_msg_prefix_pc(channel_id), &message_id.to_be_bytes()]) + concat_arrs(&[&make_msg_prefix_pc(channel_id), &message_id.to_be_bytes()]) } pub const fn make_msg_key_guild(guild_id: u64, channel_id: u64, message_id: u64) -> [u8; 26] { - concat_static(&[ + concat_arrs(&[ &make_msg_prefix(guild_id, channel_id), &message_id.to_be_bytes(), ]) @@ -369,19 +369,19 @@ pub mod chat { // member pub const fn make_pc_mem_prefix(channel_id: u64) -> [u8; 14] { - concat_static(&[&make_pc_key(channel_id), &[8]]) + concat_arrs(&[&make_pc_key(channel_id), &[8]]) } pub const fn make_member_key_pc(channel_id: u64, user_id: u64) -> [u8; 22] { - concat_static(&[&make_pc_mem_prefix(channel_id), &user_id.to_be_bytes()]) + concat_arrs(&[&make_pc_mem_prefix(channel_id), &user_id.to_be_bytes()]) } pub const fn make_member_key(guild_id: u64, user_id: u64) -> [u8; 17] { - concat_static(&[&make_guild_mem_prefix(guild_id), &user_id.to_be_bytes()]) + concat_arrs(&[&make_guild_mem_prefix(guild_id), &user_id.to_be_bytes()]) } pub const fn make_banned_member_key(guild_id: u64, user_id: u64) -> [u8; 17] { - concat_static(&[ + concat_arrs(&[ &make_guild_banned_mem_prefix(guild_id), &user_id.to_be_bytes(), ]) @@ -392,39 +392,39 @@ pub mod chat { // guild pub const fn make_guild_mem_prefix(guild_id: u64) -> [u8; 9] { - concat_static(&[&guild_id.to_be_bytes(), &[9]]) + concat_arrs(&[&guild_id.to_be_bytes(), &[9]]) } pub const fn make_guild_chan_prefix(guild_id: u64) -> [u8; 9] { - concat_static(&[&guild_id.to_be_bytes(), &[8]]) + concat_arrs(&[&guild_id.to_be_bytes(), &[8]]) } pub const fn make_guild_banned_mem_prefix(guild_id: u64) -> [u8; 9] { - concat_static(&[&guild_id.to_be_bytes(), &[7]]) + concat_arrs(&[&guild_id.to_be_bytes(), &[7]]) } pub const fn make_guild_role_prefix(guild_id: u64) -> [u8; 9] { - concat_static(&[&guild_id.to_be_bytes(), &[5]]) + concat_arrs(&[&guild_id.to_be_bytes(), &[5]]) } pub const fn make_guild_user_roles_prefix(guild_id: u64) -> [u8; 9] { - concat_static(&[&guild_id.to_be_bytes(), &[4]]) + concat_arrs(&[&guild_id.to_be_bytes(), &[4]]) } pub const fn make_pc_list_key_prefix(user_id: u64) -> [u8; 10] { - concat_static(&[&user_id.to_be_bytes(), &[1, 4]]) + concat_arrs(&[&user_id.to_be_bytes(), &[1, 4]]) } pub const fn make_guild_role_ordering_key(guild_id: u64) -> [u8; 10] { - concat_static(&[&guild_id.to_be_bytes(), &[1, 3]]) + concat_arrs(&[&guild_id.to_be_bytes(), &[1, 3]]) } pub const fn make_guild_list_key_prefix(user_id: u64) -> [u8; 10] { - concat_static(&[&user_id.to_be_bytes(), &[1, 2]]) + concat_arrs(&[&user_id.to_be_bytes(), &[1, 2]]) } pub const fn make_guild_chan_ordering_key(guild_id: u64) -> [u8; 10] { - concat_static(&[&guild_id.to_be_bytes(), &[1, 1]]) + concat_arrs(&[&guild_id.to_be_bytes(), &[1, 1]]) } pub fn make_guild_list_key(user_id: u64, guild_id: u64, host: &str) -> Vec { @@ -448,7 +448,7 @@ pub mod chat { // guild pub const fn make_chan_key(guild_id: u64, channel_id: u64) -> [u8; 17] { - concat_static(&[&make_guild_chan_prefix(guild_id), &channel_id.to_be_bytes()]) + concat_arrs(&[&make_guild_chan_prefix(guild_id), &channel_id.to_be_bytes()]) } pub fn make_invite_key(name: &str) -> Vec { @@ -464,7 +464,7 @@ pub mod chat { } pub const fn make_dm_with_user_key(user_id: u64, other_user_id: u64) -> [u8; 25] { - concat_static(&[ + concat_arrs(&[ DM_WITH_USER_PREFIX, &user_id.to_be_bytes(), &[b'_'], @@ -479,12 +479,12 @@ pub mod chat { } pub const fn make_user_pending_invites_key(user_id: u64) -> [u8; 24] { - concat_static(&[PENDING_INVITES_PREFIX, &user_id.to_be_bytes()]) + concat_arrs(&[PENDING_INVITES_PREFIX, &user_id.to_be_bytes()]) } } pub mod auth { - use super::concat_static; + use super::concat_arrs; pub const ATIME_PREFIX: &[u8] = b"atime_"; pub const TOKEN_PREFIX: &[u8] = b"token_"; @@ -496,11 +496,11 @@ pub mod auth { } pub const fn token_key(user_id: u64) -> [u8; 14] { - concat_static(&[TOKEN_PREFIX, &user_id.to_be_bytes()]) + concat_arrs(&[TOKEN_PREFIX, &user_id.to_be_bytes()]) } pub const fn atime_key(user_id: u64) -> [u8; 14] { - concat_static(&[ATIME_PREFIX, &user_id.to_be_bytes()]) + concat_arrs(&[ATIME_PREFIX, &user_id.to_be_bytes()]) } pub fn single_use_token_key(token_hashed: &[u8]) -> Vec { @@ -581,8 +581,9 @@ macro_rules! impl_deser { }; } -const fn concat_static(arrs: &[&[u8]]) -> [u8; LEN] { +const fn concat_arrs(arrs: &[&[u8]]) -> [u8; LEN] { // check if the lengths match. + #[cfg(debug_assertions)] { let mut new_len = 0; let mut arr_index = 0; @@ -605,7 +606,7 @@ const fn concat_static(arrs: &[&[u8]]) -> [u8; LEN] { // SAFETY: // - the pointers dont overlap because we use our own allocated array // - the pointers are guaranteed to be not null (we create one in fn body - // others are gotten as references + // others are gotten as references) // - the pointers are guaranteed to be aligned (are they?) unsafe { std::ptr::copy_nonoverlapping(arr.as_ptr(), new.as_mut_ptr().add(padding), arr.len()); From bdfb15ead14f682d4181ed870545f5014211e774 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 20 Apr 2022 21:02:33 +0000 Subject: [PATCH 52/62] refactor: use stable method --- src/impls/sync/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/impls/sync/mod.rs b/src/impls/sync/mod.rs index a601582..de1a295 100644 --- a/src/impls/sync/mod.rs +++ b/src/impls/sync/mod.rs @@ -424,7 +424,10 @@ impl SyncServer { let res = chat_tree .remove_user_pending_invite(user_id, Some(host), &location) .await; - if res.is_err_and(|err| err.identifier == "h.no-such-pending-invite") { + if res.as_ref().map_or_else( + |err| err.identifier == "h.no-such-pending-invite", + |_| false, + ) { res?; } From 66f91d3e95e7b73bb4ee7c643e127357e5cb7f3e Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Thu, 21 Apr 2022 00:28:19 +0300 Subject: [PATCH 53/62] build: rewrite dockerfile --- Dockerfile | 94 ++++++++++++++++++++++++++++++++++++++++++------------ src/lib.rs | 3 +- 2 files changed, 75 insertions(+), 22 deletions(-) diff --git a/Dockerfile b/Dockerfile index 73f25b4..232e081 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,86 @@ -FROM alpine:3.12 as builder +# syntax=docker/dockerfile:1 +FROM alpine:edge AS builder +WORKDIR /usr/src/scherzo -RUN apk add --no-cache curl +# Install required packages to build scherzo and it's dependencies +RUN apk add --no-cache cargo rust protobuf cmake -RUN cd /root && curl -L https://github.com/harmony-development/scherzo/releases/download/continuous/scherzo > scherzo && chmod +x scherzo +ENV RUSTC_BOOTSTRAP=1 \ + RUSTFLAGS="--cfg tokio_unstable" -FROM alpine:3.12 +# == Build dependencies without our own code separately for caching == +# +# Need a fake main.rs since Cargo refuses to build anything otherwise. +# +# See https://github.com/rust-lang/cargo/issues/2644 for a Cargo feature +# request that would allow just dependencies to be compiled, presumably +# regardless of whether source files are available. +RUN mkdir -p src/bin \ + && touch src/lib.rs \ + && echo 'fn main() {}' > src/main.rs \ + && echo 'fn main() {}' > src/bin/cmd.rs \ + && echo 'fn main() {}' > src/bin/migrate.rs +COPY scherzo_derive scherzo_derive +COPY Cargo.toml Cargo.lock ./ +RUN cargo build --release && rm -r src -EXPOSE 2289 +# Copy over actual scherzo sources +COPY src src +COPY resources resources +COPY protocols protocols +COPY example_config.toml build.rs ./ -RUN mkdir -p /srv/scherzo -COPY --from=builder /root/scherzo /srv/scherzo/ +# main.rs and lib.rs need their timestamp updated for this to work correctly since +# otherwise the build with the fake main.rs from above is newer than the +# source files (COPY preserves timestamps). +# +# Builds scherzo and places the binary at /usr/src/conduit/scherzo/release/scherzo +RUN touch src/main.rs \ + && touch src/lib.rs \ + && touch src/bin/cmd.rs \ + && touch src/bin/migrate.rs \ + && cargo build --release -RUN echo "listen_on_localhost = false" > /srv/scherzo/config.toml +# --------------------------------------------------------------------------------------------------------------- +# Stuff below this line actually ends up in the resulting docker image +# --------------------------------------------------------------------------------------------------------------- +FROM alpine:latest AS runner -RUN set -x ; \ - addgroup -Sg 82 www-data 2>/dev/null ; \ - adduser -S -D -H -h /srv/scherzo -G www-data -g www-data www-data 2>/dev/null ; \ - addgroup www-data www-data 2>/dev/null && exit 0 ; exit 1 +# Standard port on which scherzo launches. +# You still need to map the port when using the docker command or docker-compose. +EXPOSE 2289 -RUN chown -cR www-data:www-data /srv/scherzo +# scherzo needs: +# ca-certificates: for https +# curl: for the healthcheck script +# shadow: needed for useradd groupadd +RUN apk add --no-cache ca-certificates curl shadow -RUN apk add --no-cache \ - curl \ - ca-certificates \ - libgcc +# Created directory for the database and media files +RUN mkdir -p /srv/scherzo -VOLUME ["/srv/scherzo/db", "/srv/scherzo/media", "/srv/scherzo/logs"] +# Test if scherzo is still alive +HEALTHCHECK --start-period=5s --interval=5s CMD curl --fail -s http://localhost:2289/_harmony/about || curl -k --fail -s https://localhost:2289/_harmony/about || exit 1 -HEALTHCHECK --start-period=2s CMD curl --fail -s http://localhost:2289/_harmony/about || curl -k --fail -s https://localhost:2289/_harmony/about || exit 1 +# Copy over the actual scherzo binary from the builder stage +COPY --from=builder /usr/src/scherzo/target/release/scherzo /src/scherzo/scherzo -USER www-data +# Improve security: Don't run stuff as root, that does not need to run as root +# Most distros also use 1000:1000 for the first real user, so this should resolve volume mounting problems. +ARG USER_ID=1000 +ARG GROUP_ID=1000 +RUN set -x ; \ + groupadd -r -g ${GROUP_ID} scherzo ; \ + useradd -l -r -M -d /srv/scherzo -o -u ${USER_ID} -g scherzo scherzo && exit 0 ; exit 1 + +# Change ownership of scherzo files to scherzo user and group and make the healthcheck executable: +RUN chown -cR scherzo:scherzo /srv/scherzo + +# Change user to scherzo, no root permissions afterwards: +USER scherzo +# Set container home directory WORKDIR /srv/scherzo -ENTRYPOINT [ "/srv/scherzo/scherzo" ] \ No newline at end of file + +# Run scherzo and print backtraces on panics +ENV RUST_BACKTRACE=1 +ENTRYPOINT [ "/srv/scherzo/scherzo" ] diff --git a/src/lib.rs b/src/lib.rs index eca3cc1..13455b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,8 @@ const_mut_refs, type_alias_impl_trait, drain_filter, - is_some_with + is_some_with, + const_ptr_offset )] #![allow(clippy::unit_arg, clippy::blocks_in_if_conditions)] From 6dd09957e8a46ce69df6c69e498b8465db0ba959 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Thu, 21 Apr 2022 00:32:38 +0300 Subject: [PATCH 54/62] build: make dockerfile work actually --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 232e081..f08f196 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,8 +53,9 @@ EXPOSE 2289 # scherzo needs: # ca-certificates: for https # curl: for the healthcheck script +# libgcc: for scherzo bin # shadow: needed for useradd groupadd -RUN apk add --no-cache ca-certificates curl shadow +RUN apk add --no-cache ca-certificates curl shadow libgcc # Created directory for the database and media files RUN mkdir -p /srv/scherzo @@ -63,7 +64,7 @@ RUN mkdir -p /srv/scherzo HEALTHCHECK --start-period=5s --interval=5s CMD curl --fail -s http://localhost:2289/_harmony/about || curl -k --fail -s https://localhost:2289/_harmony/about || exit 1 # Copy over the actual scherzo binary from the builder stage -COPY --from=builder /usr/src/scherzo/target/release/scherzo /src/scherzo/scherzo +COPY --from=builder /usr/src/scherzo/target/release/scherzo /srv/scherzo/scherzo # Improve security: Don't run stuff as root, that does not need to run as root # Most distros also use 1000:1000 for the first real user, so this should resolve volume mounting problems. From d424fd93cd1923a821ce769cb139d7b4df3c2ae3 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sat, 30 Apr 2022 23:12:33 +0300 Subject: [PATCH 55/62] build(nix): simplify flake --- flake.lock | 64 ++++++++++++++++++++++++++---------------------------- flake.nix | 13 +++++------ 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/flake.lock b/flake.lock index 4639fd2..2485e3b 100644 --- a/flake.lock +++ b/flake.lock @@ -20,16 +20,16 @@ "inputs": { "flake-utils": "flake-utils", "nixpkgs": [ - "nixCargoIntegration", + "nci", "nixpkgs" ] }, "locked": { - "lastModified": 1647857022, - "narHash": "sha256-Aw70NWLOIwKhT60MHDGjgWis3DP3faCzr6ap9CSayek=", + "lastModified": 1650900878, + "narHash": "sha256-qhNncMBSa9STnhiLfELEQpYC1L4GrYHNIzyCZ/pilsI=", "owner": "numtide", "repo": "devshell", - "rev": "0a5ff74dacb9ea22614f64e61aeb3ca0bf0e7311", + "rev": "d97df53b5ddaa1cfbea7cddbd207eb2634304733", "type": "github" }, "original": { @@ -41,50 +41,49 @@ "dream2nix": { "inputs": { "alejandra": [ - "nixCargoIntegration", + "nci", "nixpkgs" ], "crane": "crane", "flake-utils-pre-commit": [ - "nixCargoIntegration", + "nci", "nixpkgs" ], "gomod2nix": [ - "nixCargoIntegration", + "nci", "nixpkgs" ], "mach-nix": [ - "nixCargoIntegration", + "nci", "nixpkgs" ], "nixpkgs": [ - "nixCargoIntegration", + "nci", "nixpkgs" ], "node2nix": [ - "nixCargoIntegration", + "nci", "nixpkgs" ], "poetry2nix": [ - "nixCargoIntegration", + "nci", "nixpkgs" ], "pre-commit-hooks": [ - "nixCargoIntegration", + "nci", "nixpkgs" ] }, "locked": { - "lastModified": 1648842063, - "narHash": "sha256-9EF3wHY6EHCywPqsahlyUd++yAQI+0G6dZGgKagxgJo=", - "owner": "yusdacra", + "lastModified": 1651223854, + "narHash": "sha256-VFeEmzUiTSvilzKKNVPbfgXTn7EvrQol//9PDbLba+8=", + "owner": "nix-community", "repo": "dream2nix", - "rev": "ca6d145e972141f9c08050f0c713163bfc00afb2", + "rev": "97d32e314e4621306adbbc2cdc71c0e84dbbd9ed", "type": "github" }, "original": { - "owner": "yusdacra", - "ref": "fix/rust-discoverer", + "owner": "nix-community", "repo": "dream2nix", "type": "github" } @@ -107,11 +106,11 @@ "flakeCompat": { "flake": false, "locked": { - "lastModified": 1648199409, - "narHash": "sha256-JwPKdC2PoVBkG6E+eWw3j6BMR6sL3COpYWfif7RVb8Y=", + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", "owner": "edolstra", "repo": "flake-compat", - "rev": "64a525ee38886ab9028e6f61790de0832aa3ef03", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", "type": "github" }, "original": { @@ -120,7 +119,7 @@ "type": "github" } }, - "nixCargoIntegration": { + "nci": { "inputs": { "devshell": "devshell", "dream2nix": "dream2nix", @@ -130,27 +129,26 @@ "rustOverlay": "rustOverlay" }, "locked": { - "lastModified": 1648879890, - "narHash": "sha256-rctrX+JiWWC6RijGm7JjGq/WUYf68b/9gq+6sqEyXro=", + "lastModified": 1651299115, + "narHash": "sha256-CYIBsYOvQxbxLvuS6tTGa9/fbYMt++bqqxKI6D1mTfE=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "50e24fdbc8414984f514cfa0e0a431e8ddf44367", + "rev": "84ca864e64a7c31a879279f18a64a610d19a10e6", "type": "github" }, "original": { "owner": "yusdacra", - "ref": "master", "repo": "nix-cargo-integration", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1648632716, - "narHash": "sha256-kCmnDeiaMsdhfnNKjxdOzwRh2H6eQb8yWAL+nNabC/Y=", + "lastModified": 1651007983, + "narHash": "sha256-GNay7yDPtLcRcKCNHldug85AhAvBpTtPEJWSSDYBw8U=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "710fed5a2483f945b14f4a58af2cd3676b42d8c8", + "rev": "e10da1c7f542515b609f8dfbcf788f3d85b14936", "type": "github" }, "original": { @@ -163,18 +161,18 @@ "root": { "inputs": { "flakeCompat": "flakeCompat", - "nixCargoIntegration": "nixCargoIntegration", + "nci": "nci", "nixpkgs": "nixpkgs" } }, "rustOverlay": { "flake": false, "locked": { - "lastModified": 1648866882, - "narHash": "sha256-yMs/RKA9pX47a03zupmQp8/RLRmKzdSDk+h5Yt7K9xU=", + "lastModified": 1651286718, + "narHash": "sha256-sPGOKDL6TNRfLnwarbdlmeD0FW4BmPfOoB/AMax91pg=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "7c90e17cd7c0b9e81d5b23f78b482088ac9961d1", + "rev": "8a687a6e5dc1f5c39715b01521a7aa0122529a05", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 64365b1..b8bfb70 100644 --- a/flake.nix +++ b/flake.nix @@ -1,8 +1,8 @@ { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - nixCargoIntegration = { - url = "github:yusdacra/nix-cargo-integration/master"; + nci = { + url = "github:yusdacra/nix-cargo-integration"; inputs.nixpkgs.follows = "nixpkgs"; }; flakeCompat = { @@ -12,16 +12,13 @@ }; outputs = inputs: - inputs.nixCargoIntegration.lib.makeOutputs { + inputs.nci.lib.makeOutputs { root = ./.; overrides = { - crateOverrides = common: _: { + crates = common: _: { mediasoup-sys = prev: let pkgs = common.pkgs; - pythonPkgs = pkgs: - with pkgs; [ - pip - ]; + pythonPkgs = pkgs: with pkgs; [pip]; pythonWithPkgs = pkgs.python3.withPackages pythonPkgs; all = (with pkgs; [cmake gnumake nodejs meson ninja]) ++ [pythonWithPkgs]; in { From c0fd457efaff3a5ea04975b479fc168bdd11a3ed Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sat, 30 Apr 2022 23:58:31 +0300 Subject: [PATCH 56/62] chore(deps): update cargo deps --- Cargo.lock | 346 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 6 +- 2 files changed, 176 insertions(+), 176 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84c4e6e..f6ab91b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,9 +45,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "arc-swap" @@ -183,9 +183,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47594e438a243791dba58124b6669561f5baa14cb12046641d8008bf035e5a25" +checksum = "f4af7447fc1214c1f3a1ace861d0216a6c8bb13965b64bbad9650f375b67689a" dependencies = [ "async-trait", "axum-core", @@ -212,9 +212,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a671c9ae99531afdd5d3ee8340b8da547779430689947144c140fc74a740244" +checksum = "3bdc19781b16e32f8a7200368a336fa4509d4b72ef15dd4e41df5290855ee1e6" dependencies = [ "async-trait", "bytes", @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "axum-server" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cfd9dbe28ebde5c0460067ea27c6f3b1d514b699c4e0a5aab0fb63e452a8a8" +checksum = "abf18303ef7e23b045301555bf8a0dfbc1444ea1a37b3c81757a32680ace4d7d" dependencies = [ "arc-swap", "bytes", @@ -238,7 +238,7 @@ dependencies = [ "hyper", "pin-project-lite", "rustls 0.20.4", - "rustls-pemfile 0.2.1", + "rustls-pemfile 1.0.0", "tokio", "tokio-rustls 0.23.3", "tower-service", @@ -400,7 +400,7 @@ dependencies = [ [[package]] name = "console-api" version = "0.2.0" -source = "git+https://github.com/tokio-rs/console.git?branch=main#d79390303590a534a8224efbe96c6023c336a32f" +source = "git+https://github.com/tokio-rs/console.git?branch=main#d91ecdf7d85443873c0b903b1dd0ca8ae24ec54a" dependencies = [ "prost", "prost-types", @@ -410,8 +410,8 @@ dependencies = [ [[package]] name = "console-subscriber" -version = "0.1.3" -source = "git+https://github.com/tokio-rs/console.git?branch=main#d79390303590a534a8224efbe96c6023c336a32f" +version = "0.1.5" +source = "git+https://github.com/tokio-rs/console.git?branch=main#d91ecdf7d85443873c0b903b1dd0ca8ae24ec54a" dependencies = [ "console-api", "crossbeam-channel", @@ -617,9 +617,9 @@ dependencies = [ [[package]] name = "exr" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4badb9489a465cb2c555af1f00f0bfd8cecd6fc12ac11da9d5b40c5dd5f0200" +checksum = "14cc0e06fb5f67e5d6beadf3a382fec9baca1aa751c6d5368fdeee7e5932c215" dependencies = [ "bit_field", "deflate", @@ -648,14 +648,14 @@ checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" [[package]] name = "flate2" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" dependencies = [ "cfg-if", "crc32fast", "libc", - "miniz_oxide 0.4.4", + "miniz_oxide", ] [[package]] @@ -668,7 +668,7 @@ dependencies = [ "futures-sink", "nanorand", "pin-project", - "spin 0.9.2", + "spin 0.9.3", ] [[package]] @@ -939,7 +939,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "harmony_build" version = "0.1.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9e777d5121997ea360c6fabb26cdd7848a81a1ee" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#96b75d8f7b065b1269e186d8b43eb306843478e1" dependencies = [ "hrpc-build", "prost-build", @@ -950,7 +950,7 @@ dependencies = [ [[package]] name = "harmony_derive" version = "0.1.3" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9e777d5121997ea360c6fabb26cdd7848a81a1ee" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#96b75d8f7b065b1269e186d8b43eb306843478e1" dependencies = [ "proc-macro2", "quote", @@ -960,7 +960,7 @@ dependencies = [ [[package]] name = "harmony_rust_sdk" version = "0.8.0" -source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#9e777d5121997ea360c6fabb26cdd7848a81a1ee" +source = "git+https://github.com/harmony-development/harmony_rust_sdk.git?branch=refactored#96b75d8f7b065b1269e186d8b43eb306843478e1" dependencies = [ "bytecheck", "harmony_build", @@ -1021,19 +1021,13 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" dependencies = [ "unicode-segmentation", ] -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - [[package]] name = "hermit-abi" version = "0.1.19" @@ -1062,9 +1056,9 @@ dependencies = [ [[package]] name = "hrpc" -version = "0.33.28" +version = "0.33.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96f52f3fcbd55e0add26fbda0bc6103b15cd3b382db644f653a25d29f9b4eb" +checksum = "e202d7fc9f596c3dc80f3af80fdcbbc54164f42b37b2cdf119b7d22562739a0e" dependencies = [ "axum-server", "base64", @@ -1121,9 +1115,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" dependencies = [ "bytes", "fnv", @@ -1149,9 +1143,9 @@ checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" [[package]] name = "httparse" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" [[package]] name = "httpdate" @@ -1228,16 +1222,16 @@ dependencies = [ [[package]] name = "image" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db207d030ae38f1eb6f240d5a1c1c88ff422aa005d10f8c6c6fc5e75286ab30e" +checksum = "28edd9d7bc256be2502e325ac0628bde30b7001b9b52e0abe31a1a9dc2701212" dependencies = [ "bytemuck", "byteorder", "color_quant", "exr", "gif", - "jpeg-decoder 0.2.4", + "jpeg-decoder", "num-iter", "num-rational", "num-traits", @@ -1291,9 +1285,9 @@ checksum = "0e85a1509a128c855368e135cffcde7eac17d8e1083f41e2b98c58bc1a5074be" [[package]] name = "ipnet" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itertools" @@ -1310,6 +1304,25 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +[[package]] +name = "jemalloc-sys" +version = "0.4.3+5.2.1-patched.2" +source = "git+https://github.com/tikv/jemallocator.git?branch=master#161451ba9b7a2e209ade8bba757db95e70f4c45b" +dependencies = [ + "cc", + "fs_extra", + "libc", +] + +[[package]] +name = "jemallocator" +version = "0.4.3" +source = "git+https://github.com/tikv/jemallocator.git?branch=master#161451ba9b7a2e209ade8bba757db95e70f4c45b" +dependencies = [ + "jemalloc-sys", + "libc", +] + [[package]] name = "jobserver" version = "0.1.24" @@ -1319,12 +1332,6 @@ dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" - [[package]] name = "jpeg-decoder" version = "0.2.4" @@ -1357,9 +1364,9 @@ checksum = "7efd1d698db0759e6ef11a7cd44407407399a910c774dd804c64c032da7826ff" [[package]] name = "lettre" -version = "0.10.0-rc.5" +version = "0.10.0-rc.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5144148f337be14dabfc0f0d85b691a68ac6c77ef22a5c47c5504b70a7c9fcf3" +checksum = "2f6c70001f7ee6c93b6687a06607c7a38f9a7ae460139a496c23da21e95bc289" dependencies = [ "async-trait", "base64", @@ -1376,7 +1383,7 @@ dependencies = [ "quoted_printable", "regex", "rustls 0.20.4", - "rustls-pemfile 0.3.0", + "rustls-pemfile 1.0.0", "tokio", "tokio-rustls 0.23.3", "webpki-roots 0.22.3", @@ -1384,15 +1391,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "libsqlite3-sys" -version = "0.23.2" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58" +checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" dependencies = [ "cc", "pkg-config", @@ -1471,6 +1478,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "matches" version = "0.1.9" @@ -1522,9 +1538,9 @@ checksum = "4475c581332565ff35669f3dbb155a4dbbe227932759c281d78d3d1adbb7f98d" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" @@ -1547,16 +1563,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - [[package]] name = "miniz_oxide" version = "0.5.1" @@ -1603,7 +1609,7 @@ dependencies = [ "log", "memchr", "mime", - "spin 0.9.2", + "spin 0.9.3", "tokio", "tokio-util 0.6.9", "version_check", @@ -1657,9 +1663,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -1667,9 +1673,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ "autocfg", "num-integer", @@ -1796,7 +1802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ "lock_api", - "parking_lot_core 0.9.2", + "parking_lot_core 0.9.3", ] [[package]] @@ -1815,9 +1821,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "cfg-if", "libc", @@ -1828,9 +1834,9 @@ dependencies = [ [[package]] name = "password-hash" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa26fd5c3cd6e6bb83dd9c0cef40fbeb77d7596339ca46c18a6f66919bb07769" +checksum = "e029e94abc8fb0065241c308f1ac6bc8d20f450e8f7c5f0b25cd9b8d526ba294" dependencies = [ "base64ct", "rand_core", @@ -1938,9 +1944,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -1963,7 +1969,7 @@ dependencies = [ "bitflags", "crc32fast", "deflate", - "miniz_oxide 0.5.1", + "miniz_oxide", ] [[package]] @@ -1995,9 +2001,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd5316aa8f5c82add416dfbc25116b84b748a21153f512917e8143640a71bbd" +checksum = "a07b0857a71a8cb765763950499cae2413c3f9cede1133478c43600d9e146890" dependencies = [ "bytes", "prost-derive", @@ -2005,14 +2011,14 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328f9f29b82409216decb172d81e936415d21245befa79cd34c3f29d87d1c50b" +checksum = "120fbe7988713f39d780a58cf1a7ef0d7ef66c6d87e5aa3438940c05357929f4" dependencies = [ "bytes", "cfg-if", "cmake", - "heck 0.4.0", + "heck", "itertools", "lazy_static", "log", @@ -2027,9 +2033,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df35198f0777b75e9ff669737c6da5136b59dba33cf5a010a6d1cc4d56defc6f" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" dependencies = [ "anyhow", "itertools", @@ -2040,9 +2046,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926681c118ae6e512a3ccefd4abbe5521a14f4cc1e207356d4d00c0b7f2006fd" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" dependencies = [ "bytes", "prost", @@ -2070,9 +2076,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -2115,9 +2121,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" dependencies = [ "autocfg", "crossbeam-deque", @@ -2127,14 +2133,13 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] @@ -2158,6 +2163,15 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.6.25" @@ -2289,30 +2303,30 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ "openssl-probe", - "rustls-pemfile 0.2.1", + "rustls-pemfile 1.0.0", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360" dependencies = [ "base64", ] [[package]] name = "rustls-pemfile" -version = "0.3.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360" +checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" dependencies = [ "base64", ] @@ -2363,6 +2377,7 @@ dependencies = [ "image", "infer", "itertools", + "jemallocator", "lazy_static", "lettre", "mediasoup", @@ -2382,7 +2397,6 @@ dependencies = [ "sled", "smol_str", "sqlx", - "tikv-jemallocator", "tokio", "tokio-util 0.7.1", "toml", @@ -2489,9 +2503,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944" dependencies = [ "itoa", "ryu", @@ -2587,9 +2601,9 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "smol_str" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ee181c12079444893cec9c8f21b13d6b314af789c9fdb041a0645f11ed9d2" +checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44" dependencies = [ "serde", ] @@ -2612,9 +2626,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d" dependencies = [ "lock_api", ] @@ -2632,9 +2646,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.5.11" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc15591eb44ffb5816a4a70a7efd5dd87bfd3aa84c4c200401c4396140525826" +checksum = "551873805652ba0d912fec5bbb0f8b4cdd96baf8e2ebf5970e5671092966019b" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2642,9 +2656,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.5.11" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195183bf6ff8328bb82c0511a83faf60aacf75840103388851db61d7a9854ae3" +checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5" dependencies = [ "ahash", "atoi", @@ -2653,6 +2667,7 @@ dependencies = [ "bytes", "crossbeam-queue", "either", + "event-listener", "flume", "futures-channel", "futures-core", @@ -2684,13 +2699,13 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.5.11" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee35713129561f5e55c554bba1c378e2a7e67f81257b7311183de98c50e6f94" +checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1" dependencies = [ "dotenv", "either", - "heck 0.3.3", + "heck", "once_cell", "proc-macro2", "quote", @@ -2702,9 +2717,9 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.5.11" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b555e70fbbf84e269ec3858b7a6515bcfe7a166a7cc9c636dd6efd20431678b6" +checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" dependencies = [ "once_cell", "tokio", @@ -2752,9 +2767,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" dependencies = [ "proc-macro2", "quote", @@ -2845,34 +2860,15 @@ dependencies = [ [[package]] name = "tiff" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0247608e998cb6ce39dfc8f4a16c50361ce71e5b52e6d24ea1227ea8ea8ee0b2" +checksum = "7cfada0986f446a770eca461e8c6566cb879682f7d687c8348aa0c857bd52286" dependencies = [ "flate2", - "jpeg-decoder 0.1.22", + "jpeg-decoder", "weezl", ] -[[package]] -name = "tikv-jemalloc-sys" -version = "0.4.3+5.2.1-patched.2" -source = "git+https://github.com/tikv/jemallocator.git?branch=master#2706fb3874e075eca51af7f672d228ce28d5c475" -dependencies = [ - "cc", - "fs_extra", - "libc", -] - -[[package]] -name = "tikv-jemallocator" -version = "0.4.3" -source = "git+https://github.com/tikv/jemallocator.git?branch=master#2706fb3874e075eca51af7f672d228ce28d5c475" -dependencies = [ - "libc", - "tikv-jemalloc-sys", -] - [[package]] name = "time" version = "0.1.43" @@ -2885,9 +2881,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -2900,9 +2896,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "0f48b6d60512a392e34dbf7fd456249fd2de3c83669ab642e021903f4015185b" dependencies = [ "bytes", "libc", @@ -3018,9 +3014,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] @@ -3079,9 +3075,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.2.5" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" +checksum = "e980386f06883cf4d0578d6c9178c81f68b45d77d00f2c2c1bc034b3439c2c56" dependencies = [ "bitflags", "bytes", @@ -3111,9 +3107,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80b9fa4360528139bc96100c160b7ae879f5567f49f1782b0b02035b0358ebf3" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ "cfg-if", "log", @@ -3124,9 +3120,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" dependencies = [ "proc-macro2", "quote", @@ -3135,9 +3131,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90442985ee2f57c9e1b548ee72ae842f4a9a20e3f417cc38dbc5dc684d9bb4ee" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" dependencies = [ "lazy_static", "valuable", @@ -3155,9 +3151,9 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ "lazy_static", "log", @@ -3184,9 +3180,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" dependencies = [ "ansi_term", + "lazy_static", + "matchers", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -3235,9 +3235,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-normalization" @@ -3499,9 +3499,9 @@ dependencies = [ [[package]] name = "weezl" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e" +checksum = "9c97e489d8f836838d497091de568cf16b117486d529ec5579233521065bd5e4" [[package]] name = "which" @@ -3547,9 +3547,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -3560,33 +3560,33 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "winreg" diff --git a/Cargo.toml b/Cargo.toml index 22fd86b..8c145e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ required-features = ["sled", "sqlite"] [features] default = ["sled"] webrtc = ["mediasoup"] -jemalloc = ["tikv-jemallocator"] +jemalloc = ["jemallocator"] # dbs sqlite = ["sqlx", "itertools"] @@ -57,7 +57,7 @@ hyper-rustls = { version = "0.23", default-features = false, features = [ "http2", ] } tower = { version = "0.4", default-features = false, features = ["limit"] } -tower-http = { version = "0.2", default-features = false, features = [ +tower-http = { version = "0.3", default-features = false, features = [ "trace", "sensitive-headers", "map-response-body", @@ -135,7 +135,7 @@ bytecheck = { version = "0.6" } mediasoup = { version = "0.9", optional = true } -tikv-jemallocator = { git = "https://github.com/tikv/jemallocator.git", branch = "master", optional = true } +jemallocator = { git = "https://github.com/tikv/jemallocator.git", branch = "master", optional = true } [build-dependencies] harmony_build = { git = "https://github.com/harmony-development/harmony_rust_sdk.git", branch = "refactored", features = [ From 5536da78b05c6edcd1c5cae72d2b977119a3c961 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 1 May 2022 01:17:14 +0300 Subject: [PATCH 57/62] feat: implement update_private_channel, introduce event and broadcast macros --- src/impls/chat/mod.rs | 4 +- .../delete_private_channel.rs | 15 ++--- .../private_channels/leave_private_channel.rs | 15 ++--- src/impls/chat/private_channels/mod.rs | 1 + .../update_private_channel.rs | 65 +++++++++++++++++++ .../update_private_channel_members.rs | 38 ----------- .../update_private_channel_name.rs | 21 ------ src/lib.rs | 3 +- src/utils/mod.rs | 27 ++++++++ 9 files changed, 108 insertions(+), 81 deletions(-) create mode 100644 src/impls/chat/private_channels/update_private_channel.rs diff --git a/src/impls/chat/mod.rs b/src/impls/chat/mod.rs index 25e495f..4ec758c 100644 --- a/src/impls/chat/mod.rs +++ b/src/impls/chat/mod.rs @@ -757,9 +757,7 @@ impl chat_service_server::ChatService for ChatServer { #[rate(5, 5)] get_private_channel_list, GetPrivateChannelListRequest, GetPrivateChannelListResponse; #[rate(3, 8)] - update_private_channel_members, UpdatePrivateChannelMembersRequest, UpdatePrivateChannelMembersResponse; - #[rate(3, 8)] - update_private_channel_name, UpdatePrivateChannelNameRequest, UpdatePrivateChannelNameResponse; + update_private_channel, UpdatePrivateChannelRequest, UpdatePrivateChannelResponse; #[rate(4, 8)] invite_user_to_guild, InviteUserToGuildRequest, InviteUserToGuildResponse; #[rate(5 ,5)] diff --git a/src/impls/chat/private_channels/delete_private_channel.rs b/src/impls/chat/private_channels/delete_private_channel.rs index 92c1851..8d00d7f 100644 --- a/src/impls/chat/private_channels/delete_private_channel.rs +++ b/src/impls/chat/private_channels/delete_private_channel.rs @@ -15,20 +15,17 @@ pub async fn handler( let deleted_channel = logic(svc.deps.as_ref(), user_id, channel_id).await?; - svc.broadcast( - EventSub::PrivateChannel(channel_id), - stream_event::Event::PrivateChannelDeleted(stream_event::PrivateChannelDeleted { - channel_id, - }), - None, - EventContext::empty(), - ); - for member in deleted_channel.members { svc.dispatch_private_channel_leave(channel_id, member) .await?; } + broadcast!( + svc, + EventSub::PrivateChannel(channel_id), + PrivateChannelDeleted { channel_id } + ); + Ok(DeletePrivateChannelResponse::new().into_response()) } diff --git a/src/impls/chat/private_channels/leave_private_channel.rs b/src/impls/chat/private_channels/leave_private_channel.rs index 40db3f5..47cfdec 100644 --- a/src/impls/chat/private_channels/leave_private_channel.rs +++ b/src/impls/chat/private_channels/leave_private_channel.rs @@ -15,19 +15,18 @@ pub async fn handler( logic(svc.deps.as_ref(), user_id, channel_id).await?; - svc.broadcast( + svc.dispatch_private_channel_leave(channel_id, user_id) + .await?; + + broadcast!( + svc, EventSub::PrivateChannel(channel_id), - stream_event::Event::UserLeftPrivateChannel(stream_event::UserLeftPrivateChannel { + UserLeftPrivateChannel { channel_id, user_id, - }), - None, - EventContext::empty(), + } ); - svc.dispatch_private_channel_leave(channel_id, user_id) - .await?; - Ok(LeavePrivateChannelResponse::new().into_response()) } diff --git a/src/impls/chat/private_channels/mod.rs b/src/impls/chat/private_channels/mod.rs index 9c44730..eccbea9 100644 --- a/src/impls/chat/private_channels/mod.rs +++ b/src/impls/chat/private_channels/mod.rs @@ -6,5 +6,6 @@ pub mod get_private_channel; pub mod get_private_channel_list; pub mod join_private_channel; pub mod leave_private_channel; +pub mod update_private_channel; pub mod update_private_channel_members; pub mod update_private_channel_name; diff --git a/src/impls/chat/private_channels/update_private_channel.rs b/src/impls/chat/private_channels/update_private_channel.rs new file mode 100644 index 0000000..c121e4a --- /dev/null +++ b/src/impls/chat/private_channels/update_private_channel.rs @@ -0,0 +1,65 @@ +use super::*; + +pub async fn handler( + svc: &ChatServer, + request: Request, +) -> ServerResult> { + let user_id = svc.deps.auth(&request).await?; + + let UpdatePrivateChannelRequest { + channel_id, + new_name, + added_members, + removed_members, + } = request.into_message().await?; + + svc.deps + .chat_tree + .check_private_channel_user(channel_id, user_id) + .await?; + + if let Some(new_name) = new_name { + update_private_channel_name::logic(svc.deps.as_ref(), channel_id, new_name.clone()).await?; + + broadcast!( + svc, + EventSub::PrivateChannel(channel_id), + PrivateChannelUpdated { + channel_id, + new_name: Some(new_name), + } + ); + } + + if added_members.is_empty().not() || removed_members.is_empty().not() { + let (added, removed) = + update_private_channel_members::logic(svc, channel_id, added_members, removed_members) + .await?; + + // dispatch invites to new members + for invitee_id in added { + svc.dispatch_user_invite_received( + user_id, + invitee_id, + pending_invite::Location::ChannelId(channel_id), + ) + .await?; + } + + // dispatch left events to removed users + for member in removed { + svc.dispatch_private_channel_leave(channel_id, member) + .await?; + broadcast!( + svc, + EventSub::PrivateChannel(channel_id), + UserLeftPrivateChannel { + channel_id, + user_id, + } + ); + } + } + + Ok(UpdatePrivateChannelResponse::new().into_response()) +} diff --git a/src/impls/chat/private_channels/update_private_channel_members.rs b/src/impls/chat/private_channels/update_private_channel_members.rs index 4176c6a..dba5dbf 100644 --- a/src/impls/chat/private_channels/update_private_channel_members.rs +++ b/src/impls/chat/private_channels/update_private_channel_members.rs @@ -1,43 +1,5 @@ use super::*; -pub async fn handler( - svc: &ChatServer, - request: Request, -) -> ServerResult> { - let user_id = svc.deps.auth(&request).await?; - - let UpdatePrivateChannelMembersRequest { - channel_id, - added_members, - removed_members, - } = request.into_message().await?; - - svc.deps - .chat_tree - .check_private_channel_user(channel_id, user_id) - .await?; - - let (added, removed) = logic(svc, channel_id, added_members, removed_members).await?; - - // dispatch invites to new members - for invitee_id in added { - svc.dispatch_user_invite_received( - user_id, - invitee_id, - pending_invite::Location::ChannelId(channel_id), - ) - .await?; - } - - // dispatch left events to removed users - for member in removed { - svc.dispatch_private_channel_leave(channel_id, member) - .await?; - } - - Ok(UpdatePrivateChannelMembersResponse::new().into_response()) -} - pub async fn logic( svc: &ChatServer, channel_id: u64, diff --git a/src/impls/chat/private_channels/update_private_channel_name.rs b/src/impls/chat/private_channels/update_private_channel_name.rs index 72a1092..e00f065 100644 --- a/src/impls/chat/private_channels/update_private_channel_name.rs +++ b/src/impls/chat/private_channels/update_private_channel_name.rs @@ -1,26 +1,5 @@ use super::*; -pub async fn handler( - svc: &ChatServer, - request: Request, -) -> ServerResult> { - let user_id = svc.deps.auth(&request).await?; - - let UpdatePrivateChannelNameRequest { - channel_id, - name: new_name, - } = request.into_message().await?; - - svc.deps - .chat_tree - .check_private_channel_user(channel_id, user_id) - .await?; - - logic(svc.deps.as_ref(), channel_id, new_name).await?; - - Ok(UpdatePrivateChannelNameResponse::new().into_response()) -} - pub async fn logic(deps: &Dependencies, channel_id: u64, new_name: String) -> ServerResult<()> { let mut private_channel = get_private_channel::logic(deps, channel_id).await?; private_channel.name = new_name.is_empty().not().then(|| new_name); diff --git a/src/lib.rs b/src/lib.rs index 13455b1..eca3cc1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,8 +5,7 @@ const_mut_refs, type_alias_impl_trait, drain_filter, - is_some_with, - const_ptr_offset + is_some_with )] #![allow(clippy::unit_arg, clippy::blocks_in_if_conditions)] diff --git a/src/utils/mod.rs b/src/utils/mod.rs index e9db072..781505a 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -89,3 +89,30 @@ where } } } + +/// create an event. shorthand for oneof variant +/// +/// ```no_compile +/// event!(PrivateChannelUpdated { channel_id, new_name }); +/// ``` +macro_rules! event { + ($t:ident $fields:tt) => {{ + stream_event::Event::$t(stream_event::$t $fields) + }}; +} + +pub(crate) use event; + +macro_rules! broadcast { + ($svc:ident, $sub:expr, $event:ident $fields:tt) => { + $crate::utils::broadcast!($svc, $sub, None, $event $fields) + }; + ($svc:ident, $sub:expr, $perm:expr, $event:ident $fields:tt) => { + $crate::utils::broadcast!($svc, $sub, $perm, EventContext::empty(), $event $fields) + }; + ($svc:ident, $sub:expr, $perm:expr, $ctx:expr, $event:ident $fields:tt) => { + $svc.broadcast($sub, $crate::utils::event!($event $fields), $perm, $ctx) + }; +} + +pub(crate) use broadcast; From 0186e041365e97586d63bfcdd4a9d491b09cc8c9 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 3 May 2022 16:16:21 +0000 Subject: [PATCH 58/62] build: specify components in rust toolchain --- rust-toolchain.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e271ee9..b76046e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,4 @@ [toolchain] channel = "nightly-2022-04-02" -targets = ["x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl"] \ No newline at end of file +targets = ["x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl"] +components = ["rust-src", "rustfmt"] \ No newline at end of file From 71743c3787b2f4650f7a90d424533bc29c309ae5 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 3 May 2022 04:44:36 +0300 Subject: [PATCH 59/62] chore: update gitpod.yml --- .gitpod.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitpod.yml b/.gitpod.yml index 1ff2f5e..7b42604 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,5 +1,4 @@ +image: yusdacra/gitpod-workspace-base-nix:latest tasks: - - init: echo "entering devshell..." - command: nix develop - - + - init: nix develop -c echo + - command: nix develop From bfb54448bd0c5c7c79d7245f65a1af7abfcf2ea3 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 3 May 2022 19:59:18 +0000 Subject: [PATCH 60/62] chore: remove init command from gitpod.yml --- .gitpod.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitpod.yml b/.gitpod.yml index 7b42604..2723aa9 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,4 +1,3 @@ image: yusdacra/gitpod-workspace-base-nix:latest tasks: - - init: nix develop -c echo - command: nix develop From b077c23a074e67707c404e711456750519be3909 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 3 May 2022 20:05:47 +0000 Subject: [PATCH 61/62] ci: update nix installer action --- .github/workflows/nix.yml | 2 +- .github/workflows/rust.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 4c4c3f5..137e166 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -15,7 +15,7 @@ jobs: - name: Checkout repo uses: actions/checkout@v3 - name: Install nix - uses: cachix/install-nix-action@v16 + uses: cachix/install-nix-action@v17 with: extra_nix_config: | experimental-features = nix-command flakes diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c2467e4..9ec2955 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -33,7 +33,7 @@ jobs: submodules: true - name: Install nix - uses: cachix/install-nix-action@v16 + uses: cachix/install-nix-action@v17 with: extra_nix_config: | experimental-features = nix-command flakes @@ -76,7 +76,7 @@ jobs: submodules: true - name: Install nix - uses: cachix/install-nix-action@v16 + uses: cachix/install-nix-action@v17 with: extra_nix_config: | experimental-features = nix-command flakes From badd71403e079baf51a7b5b13a3477154e159e65 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Wed, 4 May 2022 20:01:06 +0000 Subject: [PATCH 62/62] build(nix): add debug-server command for convenient server run --- flake.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/flake.nix b/flake.nix index b8bfb70..f271dda 100644 --- a/flake.nix +++ b/flake.nix @@ -36,6 +36,10 @@ commands = prev.commands ++ [ + { + name = "debug-server"; + command = ''cargo run --no-default-features --features sled -- -d''; + } { name = "generate-cert"; command = ''