diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5043f23b..3fd834e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,16 @@ concurrency: cancel-in-progress: true env: + # sccache only on main repo + SCCACHE_GHA_ENABLED: "${{ !startsWith(github.ref, 'refs/tags/') && (github.event.pull_request.draft != true) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && (vars.SCCACHE_ENDPOINT != '') && (github.event.pull_request.user.login != 'renovate[bot]') && 'true' || 'false' }}" + RUSTC_WRAPPER: "${{ !startsWith(github.ref, 'refs/tags/') && (github.event.pull_request.draft != true) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && (vars.SCCACHE_ENDPOINT != '') && (github.event.pull_request.user.login != 'renovate[bot]') && 'sccache' || '' }}" + SCCACHE_BUCKET: "${{ (github.event.pull_request.draft != true) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && (vars.SCCACHE_ENDPOINT != '') && (github.event.pull_request.user.login != 'renovate[bot]') && 'sccache' || '' }}" + SCCACHE_S3_USE_SSL: ${{ vars.SCCACHE_S3_USE_SSL }} + SCCACHE_REGION: ${{ vars.SCCACHE_REGION }} + SCCACHE_ENDPOINT: ${{ vars.SCCACHE_ENDPOINT }} + SCCACHE_CACHE_MULTIARCH: ${{ vars.SCCACHE_CACHE_MULTIARCH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # Required to make some things output color TERM: ansi # Publishing to my nix binary cache @@ -113,6 +123,13 @@ jobs: bin/nix-build-and-cache just '.#devShells.x86_64-linux.all-features' bin/nix-build-and-cache just '.#devShells.x86_64-linux.dynamic' + # use sccache for Rust + - name: Run sccache-cache + # we want a fresh-state when we do releases/tags to avoid potential cache poisoning attacks impacting + # releases and tags + #if: ${{ (env.SCCACHE_GHA_ENABLED == 'true') && !startsWith(github.ref, 'refs/tags/') }} + uses: mozilla-actions/sccache-action@main + # use rust-cache - uses: Swatinem/rust-cache@v2 # we want a fresh-state when we do releases/tags to avoid potential cache poisoning attacks impacting @@ -230,6 +247,13 @@ jobs: direnv allow nix develop .#all-features --command true --impure + # use sccache for Rust + - name: Run sccache-cache + # we want a fresh-state when we do releases/tags to avoid potential cache poisoning attacks impacting + # releases and tags + #if: ${{ (env.SCCACHE_GHA_ENABLED == 'true') && !startsWith(github.ref, 'refs/tags/') }} + uses: mozilla-actions/sccache-action@main + # use rust-cache - uses: Swatinem/rust-cache@v2 # we want a fresh-state when we do releases/tags to avoid potential cache poisoning attacks impacting diff --git a/Cargo.lock b/Cargo.lock index d81fdbc0..c28f4eab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,9 +55,9 @@ checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" [[package]] name = "arbitrary" @@ -79,7 +79,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -105,9 +105,9 @@ dependencies = [ [[package]] name = "as_variant" -version = "1.3.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dbc3a507a82b17ba0d98f6ce8fd6954ea0c8152e98009d36a40d8dcc8ce078a" +checksum = "f38fa22307249f86fb7fad906fcae77f2564caeb56d7209103c551cd1cf4798f" [[package]] name = "assign" @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.22" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a194f9d963d8099596278594b3107448656ba73831c9d8c783e613ce86da64" +checksum = "310c9bcae737a48ef5cdee3174184e6d548b292739ede61a1f955ef76a738861" dependencies = [ "brotli", "flate2", @@ -142,17 +142,6 @@ dependencies = [ "zstd-safe", ] -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "async-stream" version = "0.3.6" @@ -172,18 +161,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -232,25 +221,27 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.13.0" +version = "1.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b756939cb2f8dc900aa6dcd505e6e2428e9cae7ff7b028c49e3946efa70878" +checksum = "5e4e8200b9a4a5801a769d50eeabc05670fec7e959a8cb7a63a93e4e519942ae" dependencies = [ "aws-lc-sys", + "paste", "zeroize", ] [[package]] name = "aws-lc-sys" -version = "0.28.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f7720b74ed28ca77f90769a71fd8c637a0137f6fae4ae947e1050229cff57f" +checksum = "0f9dd2e03ee80ca2822dd6ea431163d2ef259f2066a4d6ccaca6d9dcb386aa43" dependencies = [ "bindgen 0.69.5", "cc", "cmake", "dunce", "fs_extra", + "paste", ] [[package]] @@ -343,15 +334,16 @@ dependencies = [ [[package]] name = "axum-server" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495c05f60d6df0093e8fb6e74aa5846a0ad06abaf96d76166283720bf740f8ab" +checksum = "56bac90848f6a9393ac03c63c640925c4b7c8ca21654de40d53f55964667c7d8" dependencies = [ "arc-swap", "bytes", - "fs-err", + "futures-util", "http", "http-body", + "http-body-util", "hyper", "hyper-util", "pin-project-lite", @@ -360,6 +352,7 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls", + "tower 0.4.13", "tower-service", ] @@ -411,9 +404,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.7.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bindgen" @@ -434,7 +427,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn", + "syn 2.0.98", "which", ] @@ -453,7 +446,7 @@ dependencies = [ "regex", "rustc-hash 2.1.1", "shlex", - "syn", + "syn 2.0.98", ] [[package]] @@ -542,9 +535,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" [[package]] name = "byteorder" @@ -560,15 +553,15 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.10.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" [[package]] name = "bytesize" -version = "2.0.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3c8f83209414aacf0eeae3cf730b18d6981697fba62f200fcfb92b9f082acba" +checksum = "2d2c12f985c78475a6b8d629afd0c360260ef34cfef52efccdcfd31972f81c2e" [[package]] name = "bzip2-sys" @@ -592,9 +585,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.17" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "jobserver", "libc", @@ -663,9 +656,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.35" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", "clap_derive", @@ -673,9 +666,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstyle", "clap_lex", @@ -683,14 +676,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -777,7 +770,6 @@ dependencies = [ name = "conduwuit_api" version = "0.5.0" dependencies = [ - "async-trait", "axum", "axum-client-ip", "axum-extra", @@ -793,9 +785,9 @@ dependencies = [ "http-body-util", "hyper", "ipaddress", - "itertools 0.14.0", + "itertools 0.13.0", "log", - "rand 0.8.5", + "rand", "reqwest", "ruma", "serde", @@ -813,7 +805,6 @@ dependencies = [ "argon2", "arrayvec", "axum", - "axum-extra", "bytes", "bytesize", "cargo_toml", @@ -832,14 +823,14 @@ dependencies = [ "http", "http-body-util", "ipaddress", - "itertools 0.14.0", + "itertools 0.13.0", "libc", "libloading", "log", "maplit", "nix", "num-traits", - "rand 0.8.5", + "rand", "regex", "reqwest", "ring", @@ -851,7 +842,7 @@ dependencies = [ "serde_yaml", "smallstr", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.11", "tikv-jemalloc-ctl", "tikv-jemalloc-sys", "tikv-jemallocator", @@ -886,10 +877,10 @@ dependencies = [ name = "conduwuit_macros" version = "0.5.0" dependencies = [ - "itertools 0.14.0", + "itertools 0.13.0", "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -938,15 +929,15 @@ dependencies = [ "const-str", "either", "futures", - "hickory-resolver 0.25.1", + "hickory-resolver", "http", "image", "ipaddress", - "itertools 0.14.0", + "itertools 0.13.0", "log", "loole", "lru-cache", - "rand 0.8.5", + "rand", "regex", "reqwest", "ruma", @@ -1009,9 +1000,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const-str" -version = "0.6.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e991226a70654b49d34de5ed064885f0bef0348a8e70018b8ff1ac80aa984a2" +checksum = "3618cccc083bb987a415d85c02ca6c9994ea5b44731ec28b9ecf09658655fba9" [[package]] name = "const_panic" @@ -1072,17 +1063,11 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - [[package]] name = "crokey" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ff945e42bb93d29b10ba509970066a269903a932f0ea07d99d8621f97e90d7" +checksum = "520e83558f4c008ac06fa6a86e5c1d4357be6f994cce7434463ebcdaadf47bb1" dependencies = [ "crokey-proc_macros", "crossterm", @@ -1093,15 +1078,15 @@ dependencies = [ [[package]] name = "crokey-proc_macros" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "665f2180fd82d0ba2bf3deb45fafabb18f23451024ff71ee47f6bfdfb4bbe09e" +checksum = "370956e708a1ce65fe4ac5bb7185791e0ece7485087f17736d54a23a0895049f" dependencies = [ "crossterm", "proc-macro2", "quote", "strict", - "syn", + "syn 1.0.109", ] [[package]] @@ -1119,9 +1104,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] @@ -1209,7 +1194,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -1236,7 +1221,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -1279,9 +1264,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] @@ -1305,7 +1290,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -1332,7 +1317,7 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core 0.6.4", + "rand_core", "serde", "sha2", "subtle", @@ -1341,9 +1326,9 @@ dependencies = [ [[package]] name = "either" -version = "1.15.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" dependencies = [ "serde", ] @@ -1357,7 +1342,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -1388,9 +1373,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.4" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ "event-listener", "pin-project-lite", @@ -1454,9 +1439,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" dependencies = [ "crc32fast", "miniz_oxide", @@ -1487,16 +1472,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "fs-err" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f89bda4c2a21204059a977ed3bfe746677dfd137b83c339e702b0ac91d482aa" -dependencies = [ - "autocfg", - "tokio", -] - [[package]] name = "fs_extra" version = "1.3.0" @@ -1568,7 +1543,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -1601,19 +1576,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generator" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" -dependencies = [ - "cfg-if", - "libc", - "log", - "rustversion", - "windows 0.58.0", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1639,16 +1601,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", - "js-sys", "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", - "wasm-bindgen", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] @@ -1685,7 +1645,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.8.0", + "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -1694,9 +1654,9 @@ dependencies = [ [[package]] name = "half" -version = "2.5.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", @@ -1791,7 +1751,7 @@ dependencies = [ "idna", "ipnet", "once_cell", - "rand 0.8.5", + "rand", "thiserror 1.0.69", "tinyvec", "tokio", @@ -1799,34 +1759,6 @@ dependencies = [ "url", ] -[[package]] -name = "hickory-proto" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d844af74f7b799e41c78221be863bade11c430d46042c3b49ca8ae0c6d27287" -dependencies = [ - "async-recursion", - "async-trait", - "cfg-if", - "critical-section", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna", - "ipnet", - "once_cell", - "rand 0.9.0", - "ring", - "serde", - "thiserror 2.0.12", - "tinyvec", - "tokio", - "tracing", - "url", -] - [[package]] name = "hickory-resolver" version = "0.24.4" @@ -1835,12 +1767,12 @@ checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" dependencies = [ "cfg-if", "futures-util", - "hickory-proto 0.24.4", + "hickory-proto", "ipconfig", "lru-cache", "once_cell", "parking_lot", - "rand 0.8.5", + "rand", "resolv-conf", "smallvec", "thiserror 1.0.69", @@ -1848,28 +1780,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hickory-resolver" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a128410b38d6f931fcc6ca5c107a3b02cabd6c05967841269a4ad65d23c44331" -dependencies = [ - "cfg-if", - "futures-util", - "hickory-proto 0.25.1", - "ipconfig", - "moka", - "once_cell", - "parking_lot", - "rand 0.9.0", - "resolv-conf", - "serde", - "smallvec", - "thiserror 2.0.12", - "tokio", - "tracing", -] - [[package]] name = "hmac" version = "0.12.1" @@ -1888,6 +1798,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "hostname" version = "0.4.0" @@ -1896,7 +1817,7 @@ checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" dependencies = [ "cfg-if", "libc", - "windows 0.52.0", + "windows", ] [[package]] @@ -1910,14 +1831,14 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] name = "http" -version = "1.3.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -1945,12 +1866,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.3" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http", "http-body", "pin-project-lite", @@ -1958,9 +1879,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.10.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" [[package]] name = "httpdate" @@ -1970,9 +1891,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.2.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" @@ -2016,9 +1937,9 @@ dependencies = [ [[package]] name = "hyper-timeout" -version = "0.5.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" dependencies = [ "hyper", "hyper-util", @@ -2029,8 +1950,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.11" -source = "git+https://github.com/girlbossceo/hyper-util?rev=e4ae7628fe4fcdacef9788c4c8415317a4489941#e4ae7628fe4fcdacef9788c4c8415317a4489941" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" dependencies = [ "bytes", "futures-channel", @@ -2038,10 +1960,10 @@ dependencies = [ "http", "http-body", "hyper", - "libc", "pin-project-lite", "socket2", "tokio", + "tower 0.4.13", "tower-service", "tracing", ] @@ -2087,9 +2009,9 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.5.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] name = "icu_normalizer" @@ -2111,9 +2033,9 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] name = "icu_properties" @@ -2132,9 +2054,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" [[package]] name = "icu_provider" @@ -2161,7 +2083,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -2187,9 +2109,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.6" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" dependencies = [ "bytemuck", "byteorder-lite", @@ -2215,7 +2137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" dependencies = [ "byteorder-lite", - "quick-error", + "quick-error 2.0.1", ] [[package]] @@ -2236,9 +2158,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -2265,7 +2187,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -2329,17 +2251,16 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ - "getrandom 0.3.2", "libc", ] @@ -2417,7 +2338,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn", + "syn 2.0.98", ] [[package]] @@ -2440,9 +2361,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] name = "libfuzzer-sys" @@ -2466,9 +2387,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.22" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" dependencies = [ "cc", "pkg-config", @@ -2505,9 +2426,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "loole" @@ -2519,19 +2440,6 @@ dependencies = [ "futures-sink", ] -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - [[package]] name = "loop9" version = "0.1.5" @@ -2598,6 +2506,12 @@ dependencies = [ "xml5ever", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.1.0" @@ -2637,29 +2551,29 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minicbor" -version = "0.26.3" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1936e27fffe7d8557c060eb82cb71668608cd1a5fb56b63e66d22ae8d7564321" +checksum = "c0452a60c1863c1f50b5f77cd295e8d2786849f35883f0b9e18e7e6e1b5691b0" dependencies = [ "minicbor-derive", ] [[package]] name = "minicbor-derive" -version = "0.16.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9882ef5c56df184b8ffc107fc6c61e33ee3a654b021961d790a78571bb9d67a" +checksum = "bd2209fff77f705b00c737016a48e73733d7fbccb8b007194db148f03561fb70" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] name = "minicbor-serde" -version = "0.4.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e45e8beeefea1b8b6f52fa188a5b6ea3746c2885606af8d4d8bf31cee633fb" +checksum = "becf18ac384ecf6f53b2db3b1549eebff664c67ecf259ae99be5912193291686" dependencies = [ "minicbor", "serde", @@ -2702,25 +2616,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "moka" -version = "0.12.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" -dependencies = [ - "crossbeam-channel", - "crossbeam-epoch", - "crossbeam-utils", - "loom", - "parking_lot", - "portable-atomic", - "rustc_version", - "smallvec", - "tagptr", - "thiserror 1.0.69", - "uuid", -] - [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -2818,7 +2713,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -2882,13 +2777,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -dependencies = [ - "critical-section", - "portable-atomic", -] +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "openssl-probe" @@ -2904,7 +2795,7 @@ checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a" dependencies = [ "futures-core", "futures-sink", - "indexmap 2.8.0", + "indexmap 2.7.1", "js-sys", "once_cell", "pin-project-lite", @@ -2953,7 +2844,7 @@ dependencies = [ "opentelemetry", "ordered-float 4.6.0", "percent-encoding", - "rand 0.8.5", + "rand", "thiserror 1.0.69", "tokio", "tokio-stream", @@ -3030,7 +2921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -3060,7 +2951,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -3095,7 +2986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand 0.8.5", + "rand", ] [[package]] @@ -3109,22 +3000,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -3151,9 +3042,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "png" @@ -3168,12 +3059,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "portable-atomic" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" - [[package]] name = "powerfmt" version = "0.2.0" @@ -3182,9 +3067,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.21" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", ] @@ -3197,28 +3082,28 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "prettyplease" -version = "0.2.31" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" +checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.98", ] [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -3231,7 +3116,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", "version_check", "yansi", ] @@ -3252,7 +3137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -3275,7 +3160,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -3314,6 +3199,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quick-error" version = "2.0.1" @@ -3322,39 +3213,37 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quinn" -version = "0.11.7" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", - "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash 2.1.1", "rustls", "socket2", - "thiserror 2.0.12", + "thiserror 2.0.11", "tokio", "tracing", - "web-time 1.1.0", ] [[package]] name = "quinn-proto" -version = "0.11.10" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", - "getrandom 0.3.2", - "rand 0.9.0", + "getrandom 0.2.15", + "rand", "ring", "rustc-hash 2.1.1", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.12", + "thiserror 2.0.11", "tinyvec", "tracing", "web-time 1.1.0", @@ -3362,9 +3251,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.11" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" +checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" dependencies = [ "cfg_aliases", "libc", @@ -3376,19 +3265,13 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - [[package]] name = "rand" version = "0.8.5" @@ -3396,19 +3279,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", - "zerocopy", + "rand_chacha", + "rand_core", ] [[package]] @@ -3418,17 +3290,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", + "rand_core", ] [[package]] @@ -3440,15 +3302,6 @@ dependencies = [ "getrandom 0.2.15", ] -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.2", -] - [[package]] name = "rav1e" version = "0.7.1" @@ -3475,8 +3328,8 @@ dependencies = [ "once_cell", "paste", "profiling", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "simd_helpers", "system-deps", "thiserror 1.0.69", @@ -3493,7 +3346,7 @@ dependencies = [ "avif-serialize", "imgref", "loop9", - "quick-error", + "quick-error 2.0.1", "rav1e", "rayon", "rgb", @@ -3521,9 +3374,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" dependencies = [ "bitflags 2.9.0", ] @@ -3574,9 +3427,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "async-compression", "base64 0.22.1", @@ -3585,7 +3438,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "hickory-resolver 0.24.4", + "hickory-resolver", "http", "http-body", "http-body-util", @@ -3612,7 +3465,6 @@ dependencies = [ "tokio-rustls", "tokio-socks", "tokio-util", - "tower 0.5.2", "tower-service", "url", "wasm-bindgen", @@ -3624,10 +3476,12 @@ dependencies = [ [[package]] name = "resolv-conf" -version = "0.7.1" -source = "git+https://github.com/girlbossceo/resolv-conf?rev=200e958941d522a70c5877e3d846f55b5586c68d#200e958941d522a70c5877e3d846f55b5586c68d" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" dependencies = [ - "hostname", + "hostname 0.3.1", + "quick-error 1.2.3", ] [[package]] @@ -3638,9 +3492,9 @@ checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" [[package]] name = "ring" -version = "0.17.14" +version = "0.17.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +checksum = "ed9b823fa29b721a59671b41d6b06e66b29e0628e207e8b1c3ceeda701ec928d" dependencies = [ "cc", "cfg-if", @@ -3653,7 +3507,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.10.1" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "assign", "js_int", @@ -3673,7 +3527,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.10.0" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "js_int", "ruma-common", @@ -3685,7 +3539,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.18.0" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "as_variant", "assign", @@ -3700,7 +3554,7 @@ dependencies = [ "serde", "serde_html_form", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.11", "url", "web-time 1.1.0", ] @@ -3708,7 +3562,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.13.0" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "as_variant", "base64 0.22.1", @@ -3716,11 +3570,11 @@ dependencies = [ "form_urlencoded", "getrandom 0.2.15", "http", - "indexmap 2.8.0", + "indexmap 2.7.1", "js_int", "konst", "percent-encoding", - "rand 0.8.5", + "rand", "regex", "ruma-identifiers-validation", "ruma-macros", @@ -3728,7 +3582,7 @@ dependencies = [ "serde_html_form", "serde_json", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.11", "time", "tracing", "url", @@ -3740,10 +3594,10 @@ dependencies = [ [[package]] name = "ruma-events" version = "0.28.1" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "as_variant", - "indexmap 2.8.0", + "indexmap 2.7.1", "js_int", "js_option", "percent-encoding", @@ -3755,7 +3609,7 @@ dependencies = [ "serde", "serde_json", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.11", "tracing", "url", "web-time 1.1.0", @@ -3765,7 +3619,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.9.0" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "bytes", "headers", @@ -3775,28 +3629,28 @@ dependencies = [ "js_int", "memchr", "mime", - "rand 0.8.5", + "rand", "ruma-common", "ruma-events", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.11", "tracing", ] [[package]] name = "ruma-identifiers-validation" version = "0.9.5" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "js_int", - "thiserror 2.0.12", + "thiserror 2.0.11", ] [[package]] name = "ruma-identity-service-api" version = "0.9.0" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "js_int", "ruma-common", @@ -3806,7 +3660,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.13.0" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "cfg-if", "proc-macro-crate", @@ -3814,14 +3668,14 @@ dependencies = [ "quote", "ruma-identifiers-validation", "serde", - "syn", + "syn 2.0.98", "toml", ] [[package]] name = "ruma-push-gateway-api" version = "0.9.0" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "js_int", "ruma-common", @@ -3833,17 +3687,17 @@ dependencies = [ [[package]] name = "ruma-signatures" version = "0.15.0" -source = "git+https://github.com/girlbossceo/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4" +source = "git+https://github.com/girlbossceo/ruwuma?rev=d197318a2507d38ffe6ee524d0d52728ca72538a#d197318a2507d38ffe6ee524d0d52728ca72538a" dependencies = [ "base64 0.22.1", "ed25519-dalek", "pkcs8", - "rand 0.8.5", + "rand", "ruma-common", "serde_json", "sha2", "subslice", - "thiserror 2.0.12", + "thiserror 2.0.11", ] [[package]] @@ -3914,9 +3768,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.25" +version = "0.23.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ "aws-lc-rs", "log", @@ -3960,9 +3814,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "aws-lc-rs", "ring", @@ -3972,9 +3826,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "rustyline-async" @@ -3986,16 +3840,16 @@ dependencies = [ "futures-util", "pin-project", "thingbuf", - "thiserror 2.0.12", + "thiserror 2.0.11", "unicode-segmentation", "unicode-width 0.2.0", ] [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "sanitize-filename" @@ -4015,12 +3869,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -4061,15 +3909,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "sentry" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255914a8e53822abd946e2ce8baa41d4cded6b8e938913b7f7b9da5b7ab44335" +checksum = "016958f51b96861dead7c1e02290f138411d05e94fad175c8636a835dee6e51e" dependencies = [ "httpdate", "reqwest", @@ -4089,9 +3937,9 @@ dependencies = [ [[package]] name = "sentry-backtrace" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00293cd332a859961f24fd69258f7e92af736feaeb91020cff84dac4188a4302" +checksum = "e57712c24e99252ef175b4b06c485294f10ad6bc5b5e1567ff3803ee7a0b7d3f" dependencies = [ "backtrace", "once_cell", @@ -4101,11 +3949,11 @@ dependencies = [ [[package]] name = "sentry-contexts" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961990f9caa76476c481de130ada05614cd7f5aa70fb57c2142f0e09ad3fb2aa" +checksum = "eba8754ec3b9279e00aa6d64916f211d44202370a1699afde1db2c16cbada089" dependencies = [ - "hostname", + "hostname 0.4.0", "libc", "os_info", "rustc_version", @@ -4115,12 +3963,12 @@ dependencies = [ [[package]] name = "sentry-core" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a6409d845707d82415c800290a5d63be5e3df3c2e417b0997c60531dfbd35ef" +checksum = "f9f8b6dcd4fbae1e3e22b447f32670360b27e31b62ab040f7fb04e0f80c04d92" dependencies = [ "once_cell", - "rand 0.8.5", + "rand", "sentry-types", "serde", "serde_json", @@ -4128,9 +3976,9 @@ dependencies = [ [[package]] name = "sentry-debug-images" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ab5df4f3b64760508edfe0ba4290feab5acbbda7566a79d72673065888e5cc" +checksum = "8982a69133d3f5e4efdbfa0776937fca43c3a2e275a8fe184f50b1b0aa92e07c" dependencies = [ "findshlibs", "once_cell", @@ -4139,9 +3987,9 @@ dependencies = [ [[package]] name = "sentry-log" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693841da8dfb693af29105edfbea1d91348a13d23dd0a5d03761eedb9e450c46" +checksum = "efcbfbb74628eaef033c1154d4bb082437c7592ce2282c7c5ccb455c4c97a06d" dependencies = [ "log", "sentry-core", @@ -4149,9 +3997,9 @@ dependencies = [ [[package]] name = "sentry-panic" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609b1a12340495ce17baeec9e08ff8ed423c337c1a84dffae36a178c783623f3" +checksum = "de296dae6f01e931b65071ee5fe28d66a27909857f744018f107ed15fd1f6b25" dependencies = [ "sentry-backtrace", "sentry-core", @@ -4159,9 +4007,9 @@ dependencies = [ [[package]] name = "sentry-tower" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b98005537e38ee3bc10e7d36e7febe9b8e573d03f2ddd85fcdf05d21f9abd6d" +checksum = "fcdaf9b1939589476bd57751d12a9653bbfe356610fc476d03d7683189183ab7" dependencies = [ "http", "pin-project", @@ -4173,9 +4021,9 @@ dependencies = [ [[package]] name = "sentry-tracing" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f4e86402d5c50239dc7d8fd3f6d5e048221d5fcb4e026d8d50ab57fe4644cb" +checksum = "263f73c757ed7915d3e1e34625eae18cad498a95b4261603d4ce3f87b159a6f0" dependencies = [ "sentry-backtrace", "sentry-core", @@ -4185,13 +4033,13 @@ dependencies = [ [[package]] name = "sentry-types" -version = "0.37.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3f117b8755dbede8260952de2aeb029e20f432e72634e8969af34324591631" +checksum = "a71ed3a389948a6a6d92b98e997a2723ca22f09660c5a7b7388ecd509a70a527" dependencies = [ "debugid", "hex", - "rand 0.8.5", + "rand", "serde", "serde_json", "thiserror 1.0.69", @@ -4202,22 +4050,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -4227,7 +4075,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d2de91cf02bbc07cde38891769ccd5d4f073d22a40683aa4bc7a95781aaa2c4" dependencies = [ "form_urlencoded", - "indexmap 2.8.0", + "indexmap 2.7.1", "itoa", "ryu", "serde", @@ -4235,9 +4083,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ "itoa", "memchr", @@ -4247,9 +4095,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -4292,7 +4140,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.7.1", "itoa", "ryu", "serde", @@ -4372,7 +4220,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -4426,9 +4274,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4458,9 +4306,9 @@ checksum = "f42444fea5b87a39db4218d9422087e66a85d0e7a0963a439b07bcdf91804006" [[package]] name = "string_cache" -version = "0.8.9" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe" dependencies = [ "new_debug_unreachable", "parking_lot", @@ -4498,9 +4346,20 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.100" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -4524,7 +4383,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -4540,12 +4399,6 @@ dependencies = [ "version-compare", ] -[[package]] -name = "tagptr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" - [[package]] name = "target-lexicon" version = "0.12.16" @@ -4600,11 +4453,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.11", ] [[package]] @@ -4615,18 +4468,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -4702,9 +4555,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -4717,15 +4570,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -4743,9 +4596,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -4758,9 +4611,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.2" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -4782,7 +4635,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -4832,9 +4685,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -4870,7 +4723,7 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.7.1", "serde", "serde_spanned", "toml_datetime", @@ -4918,7 +4771,7 @@ dependencies = [ "indexmap 1.9.3", "pin-project", "pin-project-lite", - "rand 0.8.5", + "rand", "slab", "tokio", "tokio-util", @@ -4982,6 +4835,7 @@ name = "tracing" version = "0.1.41" source = "git+https://github.com/girlbossceo/tracing?rev=1e64095a8051a1adf0d1faa307f9f030889ec2aa#1e64095a8051a1adf0d1faa307f9f030889ec2aa" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4994,7 +4848,7 @@ source = "git+https://github.com/girlbossceo/tracing?rev=1e64095a8051a1adf0d1faa dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -5115,9 +4969,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" [[package]] name = "unicode-segmentation" @@ -5202,11 +5056,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.16.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.1", "serde", ] @@ -5262,9 +5116,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.13.3+wasi-0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" dependencies = [ "wit-bindgen-rt", ] @@ -5291,7 +5145,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.98", "wasm-bindgen-shared", ] @@ -5326,7 +5180,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5411,9 +5265,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" [[package]] name = "wildmatch" @@ -5449,17 +5303,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", + "windows-core", "windows-targets 0.52.6", ] @@ -5472,56 +5316,15 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result 0.3.2", - "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", ] [[package]] @@ -5533,34 +5336,16 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result 0.2.0", + "windows-result", "windows-targets 0.52.6", ] -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -5612,29 +5397,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -5647,12 +5416,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -5665,12 +5428,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -5683,24 +5440,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -5713,12 +5458,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -5731,12 +5470,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -5749,12 +5482,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -5767,17 +5494,11 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" dependencies = [ "memchr", ] @@ -5794,9 +5515,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.39.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ "bitflags 2.9.0", ] @@ -5850,28 +5571,29 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -5891,7 +5613,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", "synstructure", ] @@ -5920,7 +5642,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.98", ] [[package]] @@ -5934,20 +5656,19 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "7.2.4" +version = "7.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" +version = "2.0.14+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +checksum = "8fb060d4926e4ac3a3ad15d864e99ceb5f343c6b34f5bd6d81ae6ed417311be5" dependencies = [ - "bindgen 0.71.1", "cc", "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index f5ee3f0f..feb43f5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,18 +20,18 @@ license = "Apache-2.0" # See also `rust-toolchain.toml` readme = "README.md" repository = "https://github.com/girlbossceo/conduwuit" -rust-version = "1.86.0" +rust-version = "1.85.0" version = "0.5.0" [workspace.metadata.crane] name = "conduwuit" [workspace.dependencies.arrayvec] -version = "0.7.6" +version = "0.7.4" features = ["serde"] [workspace.dependencies.smallvec] -version = "1.14.0" +version = "1.13.2" features = [ "const_generics", "const_new", @@ -45,7 +45,7 @@ version = "0.3" features = ["ffi", "std", "union"] [workspace.dependencies.const-str] -version = "0.6.2" +version = "0.5.7" [workspace.dependencies.ctor] version = "0.2.9" @@ -81,13 +81,13 @@ version = "0.8.5" # Used for the http request / response body type for Ruma endpoints used with reqwest [workspace.dependencies.bytes] -version = "1.10.1" +version = "1.9.0" [workspace.dependencies.http-body-util] -version = "0.1.3" +version = "0.1.2" [workspace.dependencies.http] -version = "1.3.1" +version = "1.2.0" [workspace.dependencies.regex] version = "1.11.1" @@ -111,7 +111,7 @@ default-features = false features = ["typed-header", "tracing"] [workspace.dependencies.axum-server] -version = "0.7.2" +version = "0.7.1" default-features = false # to listen on both HTTP and HTTPS if listening on TLS dierctly from conduwuit for complement or sytest @@ -122,7 +122,7 @@ version = "0.7" version = "0.6.1" [workspace.dependencies.tower] -version = "0.5.2" +version = "0.5.1" default-features = false features = ["util"] @@ -141,12 +141,12 @@ features = [ ] [workspace.dependencies.rustls] -version = "0.23.25" +version = "0.23.19" default-features = false features = ["aws_lc_rs"] [workspace.dependencies.reqwest] -version = "0.12.15" +version = "0.12.9" default-features = false features = [ "rustls-tls-native-roots", @@ -156,12 +156,12 @@ features = [ ] [workspace.dependencies.serde] -version = "1.0.219" +version = "1.0.216" default-features = false features = ["rc"] [workspace.dependencies.serde_json] -version = "1.0.140" +version = "1.0.133" default-features = false features = ["raw_value"] @@ -204,7 +204,7 @@ features = [ # logging [workspace.dependencies.log] -version = "0.4.27" +version = "0.4.22" default-features = false [workspace.dependencies.tracing] version = "0.1.41" @@ -224,7 +224,7 @@ default-features = false # used for conduwuit's CLI and admin room command parsing [workspace.dependencies.clap] -version = "4.5.35" +version = "4.5.23" default-features = false features = [ "derive", @@ -237,12 +237,12 @@ features = [ ] [workspace.dependencies.futures] -version = "0.3.31" +version = "0.3.30" default-features = false features = ["std", "async-await"] [workspace.dependencies.tokio] -version = "1.44.2" +version = "1.42.0" default-features = false features = [ "fs", @@ -275,7 +275,7 @@ features = ["alloc", "std"] default-features = false [workspace.dependencies.hyper] -version = "1.6.0" +version = "1.5.1" default-features = false features = [ "server", @@ -284,7 +284,8 @@ features = [ ] [workspace.dependencies.hyper-util] -version = "0.1.11" +# hyper-util >=0.1.9 seems to have DNS issues +version = "=0.1.8" default-features = false features = [ "server-auto", @@ -294,7 +295,7 @@ features = [ # to support multiple variations of setting a config option [workspace.dependencies.either] -version = "1.15.0" +version = "1.13.0" default-features = false features = ["serde"] @@ -305,27 +306,22 @@ default-features = false features = ["env", "toml"] [workspace.dependencies.hickory-resolver] -version = "0.25.1" +version = "0.24.2" default-features = false -features = [ - "serde", - "system-config", - "tokio", -] # Used for conduwuit::Error type [workspace.dependencies.thiserror] -version = "2.0.12" +version = "2.0.7" default-features = false # Used when hashing the state [workspace.dependencies.ring] -version = "0.17.14" +version = "0.17.8" default-features = false # Used to make working with iterators easier, was already a transitive depdendency [workspace.dependencies.itertools] -version = "0.14.0" +version = "0.13.0" # to parse user-friendly time durations in admin commands #TODO: overlaps chrono? @@ -341,7 +337,7 @@ version = "0.4.0" version = "2.3.1" [workspace.dependencies.async-trait] -version = "0.1.88" +version = "0.1.83" [workspace.dependencies.lru-cache] version = "0.1.2" @@ -350,7 +346,7 @@ version = "0.1.2" [workspace.dependencies.ruma] git = "https://github.com/girlbossceo/ruwuma" #branch = "conduwuit-changes" -rev = "920148dca1076454ca0ca5d43b5ce1aa708381d4" +rev = "d197318a2507d38ffe6ee524d0d52728ca72538a" features = [ "compat", "rand", @@ -409,7 +405,7 @@ default-features = false # optional opentelemetry, performance measurements, flamegraphs, etc for performance measurements and monitoring [workspace.dependencies.opentelemetry] -version = "0.21.0" +version = "0.29.0" [workspace.dependencies.tracing-flame] version = "0.2.0" @@ -418,16 +414,16 @@ version = "0.2.0" version = "0.22.0" [workspace.dependencies.opentelemetry_sdk] -version = "0.21.2" +version = "0.29.0" features = ["rt-tokio"] [workspace.dependencies.opentelemetry-jaeger] -version = "0.20.0" +version = "0.22.0" features = ["rt-tokio"] # optional sentry metrics for crash/panic reporting [workspace.dependencies.sentry] -version = "0.37.0" +version = "0.35.0" default-features = false features = [ "backtrace", @@ -443,9 +439,9 @@ features = [ ] [workspace.dependencies.sentry-tracing] -version = "0.37.0" +version = "0.35.0" [workspace.dependencies.sentry-tower] -version = "0.37.0" +version = "0.35.0" # jemalloc usage [workspace.dependencies.tikv-jemalloc-sys] @@ -479,7 +475,7 @@ default-features = false features = ["resource"] [workspace.dependencies.sd-notify] -version = "0.4.5" +version = "0.4.3" default-features = false [workspace.dependencies.hardened_malloc-rs] @@ -496,25 +492,25 @@ version = "0.4.3" default-features = false [workspace.dependencies.termimad] -version = "0.31.2" +version = "0.31.1" default-features = false [workspace.dependencies.checked_ops] version = "0.1" [workspace.dependencies.syn] -version = "2.0" +version = "2.0.90" default-features = false features = ["full", "extra-traits"] [workspace.dependencies.quote] -version = "1.0" +version = "1.0.37" [workspace.dependencies.proc-macro2] -version = "1.0" +version = "1.0.89" [workspace.dependencies.bytesize] -version = "2.0" +version = "1.3.2" [workspace.dependencies.core_affinity] version = "0.8.1" @@ -526,11 +522,11 @@ version = "0.2" version = "0.2" [workspace.dependencies.minicbor] -version = "0.26.3" +version = "0.25.1" features = ["std"] [workspace.dependencies.minicbor-serde] -version = "0.4.1" +version = "0.3.2" features = ["std"] [workspace.dependencies.maplit] @@ -570,23 +566,10 @@ rev = "fe4aebeeaae435af60087ddd56b573a2e0be671d" git = "https://github.com/girlbossceo/async-channel" rev = "92e5e74063bf2a3b10414bcc8a0d68b235644280" -# adds affinity masks for selecting more than one core at a time [patch.crates-io.core_affinity] git = "https://github.com/girlbossceo/core_affinity_rs" rev = "9c8e51510c35077df888ee72a36b4b05637147da" -# reverts hyperium#148 conflicting with our delicate federation resolver hooks -[patch.crates-io.hyper-util] -git = "https://github.com/girlbossceo/hyper-util" -rev = "e4ae7628fe4fcdacef9788c4c8415317a4489941" - -# allows no-aaaa option in resolv.conf -# bumps rust edition and toolchain to 1.86.0 and 2024 -# use sat_add on line number errors -[patch.crates-io.resolv-conf] -git = "https://github.com/girlbossceo/resolv-conf" -rev = "200e958941d522a70c5877e3d846f55b5586c68d" - # # Our crates # @@ -909,7 +892,6 @@ needless_continue = { level = "allow", priority = 1 } no_effect_underscore_binding = { level = "allow", priority = 1 } similar_names = { level = "allow", priority = 1 } single_match_else = { level = "allow", priority = 1 } -struct_excessive_bools = { level = "allow", priority = 1 } struct_field_names = { level = "allow", priority = 1 } unnecessary_wraps = { level = "allow", priority = 1 } unused_async = { level = "allow", priority = 1 } diff --git a/conduwuit-example.toml b/conduwuit-example.toml index 118bc57d..15e6dd37 100644 --- a/conduwuit-example.toml +++ b/conduwuit-example.toml @@ -195,6 +195,14 @@ # #servernameevent_data_cache_capacity = varies by system +# This item is undocumented. Please contribute documentation for it. +# +#server_visibility_cache_capacity = varies by system + +# This item is undocumented. Please contribute documentation for it. +# +#user_visibility_cache_capacity = varies by system + # This item is undocumented. Please contribute documentation for it. # #stateinfo_cache_capacity = varies by system @@ -527,9 +535,9 @@ # Default room version conduwuit will create rooms with. # -# Per spec, room version 11 is the default. +# Per spec, room version 10 is the default. # -#default_room_version = 11 +#default_room_version = 10 # This item is undocumented. Please contribute documentation for it. # @@ -594,7 +602,7 @@ # Currently, conduwuit doesn't support inbound batched key requests, so # this list should only contain other Synapse servers. # -# example: ["matrix.org", "tchncs.de"] +# example: ["matrix.org", "envs.net", "tchncs.de"] # #trusted_servers = ["matrix.org"] @@ -1186,16 +1194,13 @@ # #prune_missing_media = false -# Vector list of regex patterns of server names that conduwuit will refuse -# to download remote media from. -# -# example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"] +# Vector list of servers that conduwuit will refuse to download remote +# media from. # #prevent_media_downloads_from = [] -# List of forbidden server names via regex patterns that we will block -# incoming AND outgoing federation with, and block client room joins / -# remote user invites. +# List of forbidden server names that we will block incoming AND outgoing +# federation with, and block client room joins / remote user invites. # # This check is applied on the room ID, room alias, sender server name, # sender user's server name, inbound federation X-Matrix origin, and @@ -1203,15 +1208,11 @@ # # Basically "global" ACLs. # -# example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"] -# #forbidden_remote_server_names = [] -# List of forbidden server names via regex patterns that we will block all -# outgoing federated room directory requests for. Useful for preventing -# our users from wandering into bad servers or spaces. -# -# example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"] +# List of forbidden server names that we will block all outgoing federated +# room directory requests for. Useful for preventing our users from +# wandering into bad servers or spaces. # #forbidden_remote_room_directory_server_names = [] @@ -1322,7 +1323,7 @@ # used, and startup as warnings if any room aliases in your database have # a forbidden room alias/ID. # -# example: ["19dollarfortnitecards", "b[4a]droom", "badphrase"] +# example: ["19dollarfortnitecards", "b[4a]droom"] # #forbidden_alias_names = [] @@ -1335,7 +1336,7 @@ # startup as warnings if any local users in your database have a forbidden # username. # -# example: ["administrator", "b[a4]dusernam[3e]", "badphrase"] +# example: ["administrator", "b[a4]dusernam[3e]"] # #forbidden_usernames = [] diff --git a/flake.nix b/flake.nix index 49e860ed..9db2e90a 100644 --- a/flake.nix +++ b/flake.nix @@ -26,7 +26,7 @@ file = ./rust-toolchain.toml; # See also `rust-toolchain.toml` - sha256 = "sha256-X/4ZBHO3iW0fOenQ3foEvscgAPJYl2abspaBThDOukI="; + sha256 = "sha256-AJ6LX/Q/Er9kS15bn9iflkUwcgYqRQxiOIL2ToVAXaU="; }; mkScope = pkgs: pkgs.lib.makeScope pkgs.newScope (self: { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index aadc8f99..97b4a789 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -9,7 +9,7 @@ # If you're having trouble making the relevant changes, bug a maintainer. [toolchain] -channel = "1.86.0" +channel = "1.85.0" profile = "minimal" components = [ # For rust-analyzer diff --git a/src/admin/debug/commands.rs b/src/admin/debug/commands.rs index 87ca03a0..c6f6a170 100644 --- a/src/admin/debug/commands.rs +++ b/src/admin/debug/commands.rs @@ -6,9 +6,7 @@ use std::{ }; use conduwuit::{ - Error, Result, debug_error, err, info, - matrix::pdu::{PduEvent, PduId, RawPduId}, - trace, utils, + Error, PduEvent, PduId, RawPduId, Result, debug_error, err, info, trace, utils, utils::{ stream::{IterStream, ReadyExt}, string::EMPTY, diff --git a/src/admin/query/raw.rs b/src/admin/query/raw.rs index c503eee5..23f11cc8 100644 --- a/src/admin/query/raw.rs +++ b/src/admin/query/raw.rs @@ -1,16 +1,15 @@ -use std::{borrow::Cow, collections::BTreeMap, ops::Deref, sync::Arc}; +use std::{borrow::Cow, collections::BTreeMap, ops::Deref}; use clap::Subcommand; use conduwuit::{ Err, Result, apply, at, is_zero, utils::{ - stream::{IterStream, ReadyExt, TryIgnore, TryParallelExt}, + IterStream, + stream::{ReadyExt, TryIgnore, TryParallelExt}, string::EMPTY, }, }; -use conduwuit_database::Map; -use conduwuit_service::Services; -use futures::{FutureExt, Stream, StreamExt, TryStreamExt}; +use futures::{FutureExt, StreamExt, TryStreamExt}; use ruma::events::room::message::RoomMessageEventContent; use tokio::time::Instant; @@ -173,18 +172,22 @@ pub(super) async fn compact( ) -> Result { use conduwuit_database::compact::Options; - let default_all_maps: Option<_> = map.is_none().then(|| { - self.services - .db - .keys() - .map(Deref::deref) - .map(ToOwned::to_owned) - }); + let default_all_maps = map + .is_none() + .then(|| { + self.services + .db + .keys() + .map(Deref::deref) + .map(ToOwned::to_owned) + }) + .into_iter() + .flatten(); let maps: Vec<_> = map .unwrap_or_default() .into_iter() - .chain(default_all_maps.into_iter().flatten()) + .chain(default_all_maps) .map(|map| self.services.db.get(&map)) .filter_map(Result::ok) .cloned() @@ -234,8 +237,25 @@ pub(super) async fn raw_count( ) -> Result { let prefix = prefix.as_deref().unwrap_or(EMPTY); + let default_all_maps = map + .is_none() + .then(|| self.services.db.keys().map(Deref::deref)) + .into_iter() + .flatten(); + + let maps: Vec<_> = map + .iter() + .map(String::as_str) + .chain(default_all_maps) + .map(|map| self.services.db.get(map)) + .filter_map(Result::ok) + .cloned() + .collect(); + let timer = Instant::now(); - let count = with_maps_or(map.as_deref(), self.services) + let count = maps + .iter() + .stream() .then(|map| map.raw_count_prefix(&prefix)) .ready_fold(0_usize, usize::saturating_add) .await; @@ -280,8 +300,25 @@ pub(super) async fn raw_keys_sizes( ) -> Result { let prefix = prefix.as_deref().unwrap_or(EMPTY); + let default_all_maps = map + .is_none() + .then(|| self.services.db.keys().map(Deref::deref)) + .into_iter() + .flatten(); + + let maps: Vec<_> = map + .iter() + .map(String::as_str) + .chain(default_all_maps) + .map(|map| self.services.db.get(map)) + .filter_map(Result::ok) + .cloned() + .collect(); + let timer = Instant::now(); - let result = with_maps_or(map.as_deref(), self.services) + let result = maps + .iter() + .stream() .map(|map| map.raw_keys_prefix(&prefix)) .flatten() .ignore_err() @@ -308,8 +345,25 @@ pub(super) async fn raw_keys_total( ) -> Result { let prefix = prefix.as_deref().unwrap_or(EMPTY); + let default_all_maps = map + .is_none() + .then(|| self.services.db.keys().map(Deref::deref)) + .into_iter() + .flatten(); + + let maps: Vec<_> = map + .iter() + .map(String::as_str) + .chain(default_all_maps) + .map(|map| self.services.db.get(map)) + .filter_map(Result::ok) + .cloned() + .collect(); + let timer = Instant::now(); - let result = with_maps_or(map.as_deref(), self.services) + let result = maps + .iter() + .stream() .map(|map| map.raw_keys_prefix(&prefix)) .flatten() .ignore_err() @@ -333,8 +387,25 @@ pub(super) async fn raw_vals_sizes( ) -> Result { let prefix = prefix.as_deref().unwrap_or(EMPTY); + let default_all_maps = map + .is_none() + .then(|| self.services.db.keys().map(Deref::deref)) + .into_iter() + .flatten(); + + let maps: Vec<_> = map + .iter() + .map(String::as_str) + .chain(default_all_maps) + .map(|map| self.services.db.get(map)) + .filter_map(Result::ok) + .cloned() + .collect(); + let timer = Instant::now(); - let result = with_maps_or(map.as_deref(), self.services) + let result = maps + .iter() + .stream() .map(|map| map.raw_stream_prefix(&prefix)) .flatten() .ignore_err() @@ -362,8 +433,25 @@ pub(super) async fn raw_vals_total( ) -> Result { let prefix = prefix.as_deref().unwrap_or(EMPTY); + let default_all_maps = map + .is_none() + .then(|| self.services.db.keys().map(Deref::deref)) + .into_iter() + .flatten(); + + let maps: Vec<_> = map + .iter() + .map(String::as_str) + .chain(default_all_maps) + .map(|map| self.services.db.get(map)) + .filter_map(Result::ok) + .cloned() + .collect(); + let timer = Instant::now(); - let result = with_maps_or(map.as_deref(), self.services) + let result = maps + .iter() + .stream() .map(|map| map.raw_stream_prefix(&prefix)) .flatten() .ignore_err() @@ -485,20 +573,3 @@ pub(super) async fn raw_maps(&self) -> Result { Ok(RoomMessageEventContent::notice_markdown(format!("{list:#?}"))) } - -fn with_maps_or<'a>( - map: Option<&'a str>, - services: &'a Services, -) -> impl Stream> + Send + 'a { - let default_all_maps = map - .is_none() - .then(|| services.db.keys().map(Deref::deref)) - .into_iter() - .flatten(); - - map.into_iter() - .chain(default_all_maps) - .map(|map| services.db.get(map)) - .filter_map(Result::ok) - .stream() -} diff --git a/src/admin/user/commands.rs b/src/admin/user/commands.rs index 45e550be..35067304 100644 --- a/src/admin/user/commands.rs +++ b/src/admin/user/commands.rs @@ -2,8 +2,7 @@ use std::{collections::BTreeMap, fmt::Write as _}; use api::client::{full_user_deactivate, join_room_by_id_helper, leave_room}; use conduwuit::{ - Result, debug, debug_warn, error, info, is_equal_to, - matrix::pdu::PduBuilder, + PduBuilder, Result, debug, debug_warn, error, info, is_equal_to, utils::{self, ReadyExt}, warn, }; diff --git a/src/api/Cargo.toml b/src/api/Cargo.toml index 7890561c..385e786f 100644 --- a/src/api/Cargo.toml +++ b/src/api/Cargo.toml @@ -35,7 +35,6 @@ brotli_compression = [ ] [dependencies] -async-trait.workspace = true axum-client-ip.workspace = true axum-extra.workspace = true axum.workspace = true diff --git a/src/api/client/account.rs b/src/api/client/account.rs index 32f2530c..32438098 100644 --- a/src/api/client/account.rs +++ b/src/api/client/account.rs @@ -3,13 +3,9 @@ use std::fmt::Write; use axum::extract::State; use axum_client_ip::InsecureClientIp; use conduwuit::{ - Err, Error, Result, debug_info, err, error, info, is_equal_to, - matrix::pdu::PduBuilder, - utils, - utils::{ReadyExt, stream::BroadbandExt}, - warn, + Err, Error, PduBuilder, Result, debug_info, err, error, info, is_equal_to, utils, + utils::ReadyExt, warn, }; -use conduwuit_service::Services; use futures::{FutureExt, StreamExt}; use register::RegistrationKind; use ruma::{ @@ -33,6 +29,7 @@ use ruma::{ }, push, }; +use service::Services; use super::{DEVICE_ID_LENGTH, SESSION_ID_LENGTH, TOKEN_LENGTH, join_room_by_id_helper}; use crate::Ruma; @@ -148,7 +145,7 @@ pub(crate) async fn register_route( let is_guest = body.kind == RegistrationKind::Guest; let emergency_mode_enabled = services.config.emergency_password.is_some(); - if !services.config.allow_registration && body.appservice_info.is_none() { + if !services.globals.allow_registration() && body.appservice_info.is_none() { match (body.username.as_ref(), body.initial_device_display_name.as_ref()) { | (Some(username), Some(device_display_name)) => { info!(%is_guest, user = %username, device_name = %device_display_name, "Rejecting registration attempt as registration is disabled"); @@ -168,8 +165,8 @@ pub(crate) async fn register_route( } if is_guest - && (!services.config.allow_guest_registration - || (services.config.allow_registration + && (!services.globals.allow_guest_registration() + || (services.globals.allow_registration() && services.globals.registration_token.is_some())) { info!( @@ -320,14 +317,14 @@ pub(crate) async fn register_route( // Success! }, | _ => match body.json_body { - | Some(ref json) => { + | Some(json) => { uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH)); services.uiaa.create( &UserId::parse_with_server_name("", services.globals.server_name()) .unwrap(), "".into(), &uiaainfo, - json, + &json, ); return Err(Error::Uiaa(uiaainfo)); }, @@ -375,12 +372,8 @@ pub(crate) async fn register_route( ) .await?; - if (!is_guest && body.inhibit_login) - || body - .appservice_info - .as_ref() - .is_some_and(|appservice| appservice.registration.device_management) - { + // Inhibit login does not work for guests + if !is_guest && body.inhibit_login { return Ok(register::v3::Response { access_token: None, user_id, @@ -447,7 +440,7 @@ pub(crate) async fn register_route( } // log in conduit admin channel if a guest registered - if body.appservice_info.is_none() && is_guest && services.config.log_guest_registrations { + if body.appservice_info.is_none() && is_guest && services.globals.log_guest_registrations() { debug_info!("New guest user \"{user_id}\" registered on this server."); if !device_display_name.is_empty() { @@ -496,7 +489,7 @@ pub(crate) async fn register_route( if body.appservice_info.is_none() && !services.server.config.auto_join_rooms.is_empty() - && (services.config.allow_guests_auto_join_rooms || !is_guest) + && (services.globals.allow_guests_auto_join_rooms() || !is_guest) { for room in &services.server.config.auto_join_rooms { let Ok(room_id) = services.rooms.alias.resolve(room).await else { @@ -634,26 +627,6 @@ pub(crate) async fn change_password_route( .ready_filter(|id| *id != sender_device) .for_each(|id| services.users.remove_device(sender_user, id)) .await; - - // Remove all pushers except the ones associated with this session - services - .pusher - .get_pushkeys(sender_user) - .map(ToOwned::to_owned) - .broad_filter_map(|pushkey| async move { - services - .pusher - .get_pusher_device(&pushkey) - .await - .ok() - .filter(|pusher_device| pusher_device != sender_device) - .is_some() - .then_some(pushkey) - }) - .for_each(|pushkey| async move { - services.pusher.delete_pusher(sender_user, &pushkey).await; - }) - .await; } info!("User {sender_user} changed their password."); diff --git a/src/api/client/account_data.rs b/src/api/client/account_data.rs index e44ce4e7..60c18b37 100644 --- a/src/api/client/account_data.rs +++ b/src/api/client/account_data.rs @@ -1,6 +1,5 @@ use axum::extract::State; -use conduwuit::{Err, Result, err}; -use conduwuit_service::Services; +use conduwuit::{Err, err}; use ruma::{ RoomId, UserId, api::client::config::{ @@ -16,7 +15,7 @@ use ruma::{ use serde::Deserialize; use serde_json::{json, value::RawValue as RawJsonValue}; -use crate::Ruma; +use crate::{Result, Ruma, service::Services}; /// # `PUT /_matrix/client/r0/user/{userId}/account_data/{type}` /// diff --git a/src/api/client/alias.rs b/src/api/client/alias.rs index 9f1b05f8..319e5141 100644 --- a/src/api/client/alias.rs +++ b/src/api/client/alias.rs @@ -1,12 +1,12 @@ use axum::extract::State; use conduwuit::{Err, Result, debug}; -use conduwuit_service::Services; use futures::StreamExt; use rand::seq::SliceRandom; use ruma::{ OwnedServerName, RoomAliasId, RoomId, api::client::alias::{create_alias, delete_alias, get_alias}, }; +use service::Services; use crate::Ruma; diff --git a/src/api/client/appservice.rs b/src/api/client/appservice.rs index eb6b3312..84955309 100644 --- a/src/api/client/appservice.rs +++ b/src/api/client/appservice.rs @@ -22,13 +22,7 @@ pub(crate) async fn appservice_ping( ))); } - if appservice_info.registration.url.is_none() - || appservice_info - .registration - .url - .as_ref() - .is_some_and(|url| url.is_empty() || url == "null") - { + if appservice_info.registration.url.is_none() { return Err!(Request(UrlNotSet( "Appservice does not have a URL set, there is nothing to ping." ))); diff --git a/src/api/client/backup.rs b/src/api/client/backup.rs index 2ad37cf3..83955fea 100644 --- a/src/api/client/backup.rs +++ b/src/api/client/backup.rs @@ -1,7 +1,7 @@ use std::cmp::Ordering; use axum::extract::State; -use conduwuit::{Err, Result, err}; +use conduwuit::{Err, err}; use ruma::{ UInt, api::client::backup::{ @@ -13,7 +13,7 @@ use ruma::{ }, }; -use crate::Ruma; +use crate::{Result, Ruma}; /// # `POST /_matrix/client/r0/room_keys/version` /// diff --git a/src/api/client/context.rs b/src/api/client/context.rs index dbc2a22f..cb95dfef 100644 --- a/src/api/client/context.rs +++ b/src/api/client/context.rs @@ -1,20 +1,18 @@ use axum::extract::State; use conduwuit::{ - Err, Result, at, debug_warn, err, - matrix::pdu::PduEvent, - ref_at, + Err, PduEvent, Result, at, debug_warn, err, ref_at, utils::{ IterStream, future::TryExtExt, stream::{BroadbandExt, ReadyExt, TryIgnore, WidebandExt}, }, }; -use conduwuit_service::rooms::{lazy_loading, lazy_loading::Options, short::ShortStateKey}; use futures::{ FutureExt, StreamExt, TryFutureExt, TryStreamExt, future::{OptionFuture, join, join3, try_join3}, }; use ruma::{OwnedEventId, UserId, api::client::context::get_context, events::StateEventType}; +use service::rooms::{lazy_loading, lazy_loading::Options, short::ShortStateKey}; use crate::{ Ruma, @@ -107,7 +105,7 @@ pub(crate) async fn get_context_route( .collect(); let (base_event, events_before, events_after): (_, Vec<_>, Vec<_>) = - join3(base_event, events_before, events_after).boxed().await; + join3(base_event, events_before, events_after).await; let lazy_loading_context = lazy_loading::Context { user_id: sender_user, @@ -184,7 +182,7 @@ pub(crate) async fn get_context_route( .await; Ok(get_context::v3::Response { - event: base_event.map(at!(1)).map(PduEvent::into_room_event), + event: base_event.map(at!(1)).as_ref().map(PduEvent::to_room_event), start: events_before .last() @@ -203,13 +201,13 @@ pub(crate) async fn get_context_route( events_before: events_before .into_iter() .map(at!(1)) - .map(PduEvent::into_room_event) + .map(|pdu| pdu.to_room_event()) .collect(), events_after: events_after .into_iter() .map(at!(1)) - .map(PduEvent::into_room_event) + .map(|pdu| pdu.to_room_event()) .collect(), state, diff --git a/src/api/client/device.rs b/src/api/client/device.rs index 5519a1a5..6a845aed 100644 --- a/src/api/client/device.rs +++ b/src/api/client/device.rs @@ -1,9 +1,9 @@ use axum::extract::State; use axum_client_ip::InsecureClientIp; -use conduwuit::{Err, Error, Result, debug, err, utils}; +use conduwuit::{Err, err}; use futures::StreamExt; use ruma::{ - MilliSecondsSinceUnixEpoch, OwnedDeviceId, + MilliSecondsSinceUnixEpoch, api::client::{ device::{self, delete_device, delete_devices, get_device, get_devices, update_device}, error::ErrorKind, @@ -12,7 +12,7 @@ use ruma::{ }; use super::SESSION_ID_LENGTH; -use crate::{Ruma, client::DEVICE_ID_LENGTH}; +use crate::{Error, Result, Ruma, utils}; /// # `GET /_matrix/client/r0/devices` /// @@ -59,58 +59,26 @@ pub(crate) async fn update_device_route( InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result { - let sender_user = body.sender_user(); - let appservice = body.appservice_info.as_ref(); + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - match services + let mut device = services .users .get_device_metadata(sender_user, &body.device_id) .await - { - | Ok(mut device) => { - device.display_name.clone_from(&body.display_name); - device.last_seen_ip.clone_from(&Some(client.to_string())); - device - .last_seen_ts - .clone_from(&Some(MilliSecondsSinceUnixEpoch::now())); + .map_err(|_| err!(Request(NotFound("Device not found."))))?; - services - .users - .update_device_metadata(sender_user, &body.device_id, &device) - .await?; + device.display_name.clone_from(&body.display_name); + device.last_seen_ip.clone_from(&Some(client.to_string())); + device + .last_seen_ts + .clone_from(&Some(MilliSecondsSinceUnixEpoch::now())); - Ok(update_device::v3::Response {}) - }, - | Err(_) => { - let Some(appservice) = appservice else { - return Err!(Request(NotFound("Device not found."))); - }; - if !appservice.registration.device_management { - return Err!(Request(NotFound("Device not found."))); - } + services + .users + .update_device_metadata(sender_user, &body.device_id, &device) + .await?; - debug!( - "Creating new device for {sender_user} from appservice {} as MSC4190 is enabled \ - and device ID does not exist", - appservice.registration.id - ); - - let device_id = OwnedDeviceId::from(utils::random_string(DEVICE_ID_LENGTH)); - - services - .users - .create_device( - sender_user, - &device_id, - &appservice.registration.as_token, - None, - Some(client.to_string()), - ) - .await?; - - return Ok(update_device::v3::Response {}); - }, - } + Ok(update_device::v3::Response {}) } /// # `DELETE /_matrix/client/r0/devices/{deviceId}` @@ -127,21 +95,8 @@ pub(crate) async fn delete_device_route( State(services): State, body: Ruma, ) -> Result { - let (sender_user, sender_device) = body.sender(); - let appservice = body.appservice_info.as_ref(); - - if appservice.is_some_and(|appservice| appservice.registration.device_management) { - debug!( - "Skipping UIAA for {sender_user} as this is from an appservice and MSC4190 is \ - enabled" - ); - services - .users - .remove_device(sender_user, &body.device_id) - .await; - - return Ok(delete_device::v3::Response {}); - } + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + let sender_device = body.sender_device.as_ref().expect("user is authenticated"); // UIAA let mut uiaainfo = UiaaInfo { @@ -165,11 +120,11 @@ pub(crate) async fn delete_device_route( // Success! }, | _ => match body.json_body { - | Some(ref json) => { + | Some(json) => { uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH)); services .uiaa - .create(sender_user, sender_device, &uiaainfo, json); + .create(sender_user, sender_device, &uiaainfo, &json); return Err!(Uiaa(uiaainfo)); }, @@ -187,12 +142,11 @@ pub(crate) async fn delete_device_route( Ok(delete_device::v3::Response {}) } -/// # `POST /_matrix/client/v3/delete_devices` +/// # `PUT /_matrix/client/r0/devices/{deviceId}` /// -/// Deletes the given list of devices. +/// Deletes the given device. /// -/// - Requires UIAA to verify user password unless from an appservice with -/// MSC4190 enabled. +/// - Requires UIAA to verify user password /// /// For each device: /// - Invalidates access token @@ -204,20 +158,8 @@ pub(crate) async fn delete_devices_route( State(services): State, body: Ruma, ) -> Result { - let (sender_user, sender_device) = body.sender(); - let appservice = body.appservice_info.as_ref(); - - if appservice.is_some_and(|appservice| appservice.registration.device_management) { - debug!( - "Skipping UIAA for {sender_user} as this is from an appservice and MSC4190 is \ - enabled" - ); - for device_id in &body.devices { - services.users.remove_device(sender_user, device_id).await; - } - - return Ok(delete_devices::v3::Response {}); - } + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + let sender_device = body.sender_device.as_ref().expect("user is authenticated"); // UIAA let mut uiaainfo = UiaaInfo { @@ -241,11 +183,11 @@ pub(crate) async fn delete_devices_route( // Success! }, | _ => match body.json_body { - | Some(ref json) => { + | Some(json) => { uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH)); services .uiaa - .create(sender_user, sender_device, &uiaainfo, json); + .create(sender_user, sender_device, &uiaainfo, &json); return Err(Error::Uiaa(uiaainfo)); }, diff --git a/src/api/client/directory.rs b/src/api/client/directory.rs index b44b9f64..7ce32e4c 100644 --- a/src/api/client/directory.rs +++ b/src/api/client/directory.rs @@ -1,19 +1,7 @@ use axum::extract::State; use axum_client_ip::InsecureClientIp; -use conduwuit::{ - Err, Result, err, info, - utils::{ - TryFutureExtExt, - math::Expected, - result::FlatOk, - stream::{ReadyExt, WidebandExt}, - }, -}; -use conduwuit_service::Services; -use futures::{ - FutureExt, StreamExt, TryFutureExt, - future::{join, join4, join5}, -}; +use conduwuit::{Err, Error, Result, info, warn}; +use futures::{StreamExt, TryFutureExt}; use ruma::{ OwnedRoomId, RoomId, ServerName, UInt, UserId, api::{ @@ -22,6 +10,7 @@ use ruma::{ get_public_rooms, get_public_rooms_filtered, get_room_visibility, set_room_visibility, }, + error::ErrorKind, room, }, federation, @@ -36,6 +25,7 @@ use ruma::{ }, uint, }; +use service::Services; use crate::Ruma; @@ -52,13 +42,10 @@ pub(crate) async fn get_public_rooms_filtered_route( ) -> Result { if let Some(server) = &body.server { if services + .server .config .forbidden_remote_room_directory_server_names - .is_match(server.host()) - || services - .config - .forbidden_remote_server_names - .is_match(server.host()) + .contains(server) { return Err!(Request(Forbidden("Server is banned on this homeserver."))); } @@ -74,7 +61,11 @@ pub(crate) async fn get_public_rooms_filtered_route( ) .await .map_err(|e| { - err!(Request(Unknown(warn!(?body.server, "Failed to return /publicRooms: {e}")))) + warn!(?body.server, "Failed to return /publicRooms: {e}"); + Error::BadRequest( + ErrorKind::Unknown, + "Failed to return the requested server's public room list.", + ) })?; Ok(response) @@ -93,13 +84,10 @@ pub(crate) async fn get_public_rooms_route( ) -> Result { if let Some(server) = &body.server { if services + .server .config .forbidden_remote_room_directory_server_names - .is_match(server.host()) - || services - .config - .forbidden_remote_server_names - .is_match(server.host()) + .contains(server) { return Err!(Request(Forbidden("Server is banned on this homeserver."))); } @@ -115,7 +103,11 @@ pub(crate) async fn get_public_rooms_route( ) .await .map_err(|e| { - err!(Request(Unknown(warn!(?body.server, "Failed to return /publicRooms: {e}")))) + warn!(?body.server, "Failed to return /publicRooms: {e}"); + Error::BadRequest( + ErrorKind::Unknown, + "Failed to return the requested server's public room list.", + ) })?; Ok(get_public_rooms::v3::Response { @@ -135,7 +127,7 @@ pub(crate) async fn set_room_visibility_route( InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result { - let sender_user = body.sender_user(); + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); if !services.rooms.metadata.exists(&body.room_id).await { // Return 404 if the room doesn't exist @@ -179,9 +171,10 @@ pub(crate) async fn set_room_visibility_route( .await; } - return Err!(Request(Forbidden( + return Err(Error::BadRequest( + ErrorKind::forbidden(), "Publishing rooms to the room directory is not allowed", - ))); + )); } services.rooms.directory.set_public(&body.room_id); @@ -199,7 +192,10 @@ pub(crate) async fn set_room_visibility_route( }, | room::Visibility::Private => services.rooms.directory.set_not_public(&body.room_id), | _ => { - return Err!(Request(InvalidParam("Room visibility type is not supported.",))); + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "Room visibility type is not supported.", + )); }, } @@ -215,7 +211,7 @@ pub(crate) async fn get_room_visibility_route( ) -> Result { if !services.rooms.metadata.exists(&body.room_id).await { // Return 404 if the room doesn't exist - return Err!(Request(NotFound("Room not found"))); + return Err(Error::BadRequest(ErrorKind::NotFound, "Room not found")); } Ok(get_room_visibility::v3::Response { @@ -263,8 +259,8 @@ pub(crate) async fn get_public_rooms_filtered_helper( } // Use limit or else 10, with maximum 100 - let limit: usize = limit.map_or(10_u64, u64::from).try_into()?; - let mut num_since: usize = 0; + let limit = limit.map_or(10, u64::from); + let mut num_since: u64 = 0; if let Some(s) = &since { let mut characters = s.chars(); @@ -272,14 +268,14 @@ pub(crate) async fn get_public_rooms_filtered_helper( | Some('n') => false, | Some('p') => true, | _ => { - return Err!(Request(InvalidParam("Invalid `since` token"))); + return Err(Error::BadRequest(ErrorKind::InvalidParam, "Invalid `since` token")); }, }; num_since = characters .collect::() .parse() - .map_err(|_| err!(Request(InvalidParam("Invalid `since` token."))))?; + .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `since` token."))?; if backwards { num_since = num_since.saturating_sub(limit); @@ -291,12 +287,11 @@ pub(crate) async fn get_public_rooms_filtered_helper( .directory .public_rooms() .map(ToOwned::to_owned) - .wide_then(|room_id| public_rooms_chunk(services, room_id)) - .ready_filter_map(|chunk| { + .then(|room_id| public_rooms_chunk(services, room_id)) + .filter_map(|chunk| async move { if !filter.room_types.is_empty() && !filter.room_types.contains(&RoomTypeFilter::from(chunk.room_type.clone())) { return None; } - if let Some(query) = filter.generic_search_term.as_ref().map(|q| q.to_lowercase()) { if let Some(name) = &chunk.name { if name.as_str().to_lowercase().contains(&query) { @@ -328,24 +323,40 @@ pub(crate) async fn get_public_rooms_filtered_helper( all_rooms.sort_by(|l, r| r.num_joined_members.cmp(&l.num_joined_members)); - let total_room_count_estimate = UInt::try_from(all_rooms.len()) - .unwrap_or_else(|_| uint!(0)) - .into(); + let total_room_count_estimate = UInt::try_from(all_rooms.len()).unwrap_or_else(|_| uint!(0)); - let chunk: Vec<_> = all_rooms.into_iter().skip(num_since).take(limit).collect(); + let chunk: Vec<_> = all_rooms + .into_iter() + .skip( + num_since + .try_into() + .expect("num_since should not be this high"), + ) + .take(limit.try_into().expect("limit should not be this high")) + .collect(); - let prev_batch = num_since.ne(&0).then_some(format!("p{num_since}")); + let prev_batch = if num_since == 0 { + None + } else { + Some(format!("p{num_since}")) + }; - let next_batch = chunk - .len() - .ge(&limit) - .then_some(format!("n{}", num_since.expected_add(limit))); + let next_batch = if chunk.len() < limit.try_into().unwrap() { + None + } else { + Some(format!( + "n{}", + num_since + .checked_add(limit) + .expect("num_since and limit should not be that large") + )) + }; Ok(get_public_rooms_filtered::v3::Response { chunk, prev_batch, next_batch, - total_room_count_estimate, + total_room_count_estimate: Some(total_room_count_estimate), }) } @@ -363,7 +374,7 @@ async fn user_can_publish_room( .await { | Ok(event) => serde_json::from_str(event.content.get()) - .map_err(|_| err!(Database("Invalid event content for m.room.power_levels"))) + .map_err(|_| Error::bad_database("Invalid event content for m.room.power_levels")) .map(|content: RoomPowerLevelsEventContent| { RoomPowerLevels::from(content) .user_can_send_state(user_id, StateEventType::RoomHistoryVisibility) @@ -383,61 +394,60 @@ async fn user_can_publish_room( } async fn public_rooms_chunk(services: &Services, room_id: OwnedRoomId) -> PublicRoomsChunk { - let name = services.rooms.state_accessor.get_name(&room_id).ok(); - - let room_type = services.rooms.state_accessor.get_room_type(&room_id).ok(); - - let canonical_alias = services - .rooms - .state_accessor - .get_canonical_alias(&room_id) - .ok(); - - let avatar_url = services.rooms.state_accessor.get_avatar(&room_id); - - let topic = services.rooms.state_accessor.get_room_topic(&room_id).ok(); - - let world_readable = services.rooms.state_accessor.is_world_readable(&room_id); - - let join_rule = services - .rooms - .state_accessor - .room_state_get_content(&room_id, &StateEventType::RoomJoinRules, "") - .map_ok(|c: RoomJoinRulesEventContent| match c.join_rule { - | JoinRule::Public => PublicRoomJoinRule::Public, - | JoinRule::Knock => "knock".into(), - | JoinRule::KnockRestricted(_) => "knock_restricted".into(), - | _ => "invite".into(), - }); - - let guest_can_join = services.rooms.state_accessor.guest_can_join(&room_id); - - let num_joined_members = services.rooms.state_cache.room_joined_count(&room_id); - - let ( - (avatar_url, canonical_alias, guest_can_join, join_rule, name), - (num_joined_members, room_type, topic, world_readable), - ) = join( - join5(avatar_url, canonical_alias, guest_can_join, join_rule, name), - join4(num_joined_members, room_type, topic, world_readable), - ) - .boxed() - .await; - PublicRoomsChunk { - avatar_url: avatar_url.into_option().unwrap_or_default().url, - canonical_alias, - guest_can_join, - join_rule: join_rule.unwrap_or_default(), - name, - num_joined_members: num_joined_members - .map(TryInto::try_into) - .map(Result::ok) - .flat_ok() - .unwrap_or_else(|| uint!(0)), + canonical_alias: services + .rooms + .state_accessor + .get_canonical_alias(&room_id) + .await + .ok(), + name: services.rooms.state_accessor.get_name(&room_id).await.ok(), + num_joined_members: services + .rooms + .state_cache + .room_joined_count(&room_id) + .await + .unwrap_or(0) + .try_into() + .expect("joined count overflows ruma UInt"), + topic: services + .rooms + .state_accessor + .get_room_topic(&room_id) + .await + .ok(), + world_readable: services + .rooms + .state_accessor + .is_world_readable(&room_id) + .await, + guest_can_join: services.rooms.state_accessor.guest_can_join(&room_id).await, + avatar_url: services + .rooms + .state_accessor + .get_avatar(&room_id) + .await + .into_option() + .unwrap_or_default() + .url, + join_rule: services + .rooms + .state_accessor + .room_state_get_content(&room_id, &StateEventType::RoomJoinRules, "") + .map_ok(|c: RoomJoinRulesEventContent| match c.join_rule { + | JoinRule::Public => PublicRoomJoinRule::Public, + | JoinRule::Knock => "knock".into(), + | JoinRule::KnockRestricted(_) => "knock_restricted".into(), + | _ => "invite".into(), + }) + .await + .unwrap_or_default(), + room_type: services + .rooms + .state_accessor + .get_room_type(&room_id) + .await + .ok(), room_id, - room_type, - topic, - world_readable, } } diff --git a/src/api/client/filter.rs b/src/api/client/filter.rs index 97044ffc..84086452 100644 --- a/src/api/client/filter.rs +++ b/src/api/client/filter.rs @@ -1,8 +1,8 @@ use axum::extract::State; -use conduwuit::{Result, err}; +use conduwuit::err; use ruma::api::client::filter::{create_filter, get_filter}; -use crate::Ruma; +use crate::{Result, Ruma}; /// # `GET /_matrix/client/r0/user/{userId}/filter/{filterId}` /// diff --git a/src/api/client/keys.rs b/src/api/client/keys.rs index 650c573f..f50d7afa 100644 --- a/src/api/client/keys.rs +++ b/src/api/client/keys.rs @@ -1,8 +1,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use axum::extract::State; -use conduwuit::{Err, Error, Result, debug, debug_warn, err, result::NotFound, utils}; -use conduwuit_service::{Services, users::parse_master_key}; +use conduwuit::{Err, Error, Result, debug, debug_warn, err, info, result::NotFound, utils}; use futures::{StreamExt, stream::FuturesUnordered}; use ruma::{ OneTimeKeyAlgorithm, OwnedDeviceId, OwnedUserId, UserId, @@ -10,8 +9,7 @@ use ruma::{ client::{ error::ErrorKind, keys::{ - claim_keys, get_key_changes, get_keys, upload_keys, - upload_signatures::{self}, + claim_keys, get_key_changes, get_keys, upload_keys, upload_signatures, upload_signing_keys, }, uiaa::{AuthFlow, AuthType, UiaaInfo}, @@ -24,7 +22,10 @@ use ruma::{ use serde_json::json; use super::SESSION_ID_LENGTH; -use crate::Ruma; +use crate::{ + Ruma, + service::{Services, users::parse_master_key}, +}; /// # `POST /_matrix/client/r0/keys/upload` /// @@ -177,7 +178,7 @@ pub(crate) async fn upload_signing_keys_route( body.master_key.as_ref(), ) .await - .inspect_err(|e| debug!(?e)) + .inspect_err(|e| info!(?e)) { | Ok(exists) => { if let Some(result) = exists { @@ -307,60 +308,53 @@ async fn check_for_new_keys( /// # `POST /_matrix/client/r0/keys/signatures/upload` /// /// Uploads end-to-end key signatures from the sender user. -/// -/// TODO: clean this timo-code up more and integrate failures. tried to improve -/// it a bit to stop exploding the entire request on bad sigs, but needs way -/// more work. pub(crate) async fn upload_signatures_route( State(services): State, body: Ruma, ) -> Result { - if body.signed_keys.is_empty() { - debug!("Empty signed_keys sent in key signature upload"); - return Ok(upload_signatures::v3::Response::new()); - } - - let sender_user = body.sender_user(); + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); for (user_id, keys) in &body.signed_keys { for (key_id, key) in keys { - let Ok(key) = serde_json::to_value(key) - .inspect_err(|e| debug_warn!(?key_id, "Invalid \"key\" JSON: {e}")) - else { - continue; - }; + let key = serde_json::to_value(key) + .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid key JSON"))?; - let Some(signatures) = key.get("signatures") else { - continue; - }; + for signature in key + .get("signatures") + .ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Missing signatures field."))? + .get(sender_user.to_string()) + .ok_or(Error::BadRequest( + ErrorKind::InvalidParam, + "Invalid user in signatures field.", + ))? + .as_object() + .ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Invalid signature."))? + .clone() + { + // Signature validation? + let signature = ( + signature.0, + signature + .1 + .as_str() + .ok_or(Error::BadRequest( + ErrorKind::InvalidParam, + "Invalid signature value.", + ))? + .to_owned(), + ); - let Some(sender_user_val) = signatures.get(sender_user.to_string()) else { - continue; - }; - - let Some(sender_user_object) = sender_user_val.as_object() else { - continue; - }; - - for (signature, val) in sender_user_object.clone() { - let Some(val) = val.as_str().map(ToOwned::to_owned) else { - continue; - }; - let signature = (signature, val); - - if let Err(_e) = services + services .users .sign_key(user_id, key_id, signature, sender_user) - .await - .inspect_err(|e| debug_warn!("{e}")) - { - continue; - } + .await?; } } } - Ok(upload_signatures::v3::Response { failures: BTreeMap::new() }) + Ok(upload_signatures::v3::Response { + failures: BTreeMap::new(), // TODO: integrate + }) } /// # `POST /_matrix/client/r0/keys/changes` diff --git a/src/api/client/membership.rs b/src/api/client/membership.rs index 1eeacf83..11395e83 100644 --- a/src/api/client/membership.rs +++ b/src/api/client/membership.rs @@ -9,25 +9,13 @@ use std::{ use axum::extract::State; use axum_client_ip::InsecureClientIp; use conduwuit::{ - Err, Result, at, debug, debug_info, debug_warn, err, error, info, - matrix::{ - StateKey, - pdu::{PduBuilder, PduEvent, gen_event_id, gen_event_id_canonical_json}, - state_res, - }, + Err, PduEvent, Result, StateKey, at, debug, debug_info, debug_warn, err, error, info, + pdu::{PduBuilder, gen_event_id_canonical_json}, result::{FlatOk, NotFound}, - trace, + state_res, trace, utils::{self, IterStream, ReadyExt, shuffle}, warn, }; -use conduwuit_service::{ - Services, - appservice::RegistrationInfo, - rooms::{ - state::RoomMutexGuard, - state_compressor::{CompressedState, HashSetCompressStateEvent}, - }, -}; use futures::{FutureExt, StreamExt, TryFutureExt, future::join4, join}; use ruma::{ CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedRoomId, OwnedServerName, @@ -56,6 +44,15 @@ use ruma::{ }, }, }; +use service::{ + Services, + appservice::RegistrationInfo, + pdu::gen_event_id, + rooms::{ + state::RoomMutexGuard, + state_compressor::{CompressedState, HashSetCompressStateEvent}, + }, +}; use crate::{Ruma, client::full_user_deactivate}; @@ -79,9 +76,10 @@ async fn banned_room_check( if let Some(room_id) = room_id { if services.rooms.metadata.is_banned(room_id).await || services + .server .config .forbidden_remote_server_names - .is_match(room_id.server_name().unwrap().host()) + .contains(&room_id.server_name().unwrap().to_owned()) { warn!( "User {user_id} who is not an admin attempted to send an invite for or \ @@ -119,9 +117,10 @@ async fn banned_room_check( } } else if let Some(server_name) = server_name { if services + .server .config .forbidden_remote_server_names - .is_match(server_name.host()) + .contains(&server_name.to_owned()) { warn!( "User {user_id} who is not an admin tried joining a room which has the server \ @@ -476,9 +475,9 @@ pub(crate) async fn leave_room_route( State(services): State, body: Ruma, ) -> Result { - leave_room(&services, body.sender_user(), &body.room_id, body.reason.clone()) - .await - .map(|()| leave_room::v3::Response::new()) + leave_room(&services, body.sender_user(), &body.room_id, body.reason.clone()).await?; + + Ok(leave_room::v3::Response::new()) } /// # `POST /_matrix/client/r0/rooms/{roomId}/invite` @@ -492,7 +491,7 @@ pub(crate) async fn invite_user_route( ) -> Result { let sender_user = body.sender_user(); - if !services.users.is_admin(sender_user).await && services.config.block_non_admin_invites { + if !services.users.is_admin(sender_user).await && services.globals.block_non_admin_invites() { info!( "User {sender_user} is not an admin and attempted to send an invite to room {}", &body.room_id @@ -1629,7 +1628,7 @@ pub(crate) async fn invite_helper( reason: Option, is_direct: bool, ) -> Result { - if !services.users.is_admin(sender_user).await && services.config.block_non_admin_invites { + if !services.users.is_admin(sender_user).await && services.globals.block_non_admin_invites() { info!( "User {sender_user} is not an admin and attempted to send an invite to room \ {room_id}" @@ -1764,8 +1763,8 @@ pub(crate) async fn invite_helper( Ok(()) } -// Make a user leave all their joined rooms, rescinds knocks, forgets all rooms, -// and ignores errors +// Make a user leave all their joined rooms, forgets all rooms, and ignores +// errors pub async fn leave_all_rooms(services: &Services, user_id: &UserId) { let rooms_joined = services .rooms @@ -1779,17 +1778,7 @@ pub async fn leave_all_rooms(services: &Services, user_id: &UserId) { .rooms_invited(user_id) .map(|(r, _)| r); - let rooms_knocked = services - .rooms - .state_cache - .rooms_knocked(user_id) - .map(|(r, _)| r); - - let all_rooms: Vec<_> = rooms_joined - .chain(rooms_invited) - .chain(rooms_knocked) - .collect() - .await; + let all_rooms: Vec<_> = rooms_joined.chain(rooms_invited).collect().await; for room_id in all_rooms { // ignore errors @@ -1806,40 +1795,7 @@ pub async fn leave_room( user_id: &UserId, room_id: &RoomId, reason: Option, -) -> Result { - let default_member_content = RoomMemberEventContent { - membership: MembershipState::Leave, - reason: reason.clone(), - join_authorized_via_users_server: None, - is_direct: None, - avatar_url: None, - displayname: None, - third_party_invite: None, - blurhash: None, - }; - - if services.rooms.metadata.is_banned(room_id).await - || services.rooms.metadata.is_disabled(room_id).await - { - // the room is banned/disabled, the room must be rejected locally since we - // cant/dont want to federate with this server - services - .rooms - .state_cache - .update_membership( - room_id, - user_id, - default_member_content, - user_id, - None, - None, - true, - ) - .await?; - - return Ok(()); - } - +) -> Result<()> { // Ask a remote server if we don't have this room and are not knocking on it if !services .rooms @@ -1872,7 +1828,7 @@ pub async fn leave_room( .update_membership( room_id, user_id, - default_member_content, + RoomMemberEventContent::new(MembershipState::Leave), user_id, last_state, None, @@ -1892,23 +1848,26 @@ pub async fn leave_room( ) .await else { - debug_warn!( + // Fix for broken rooms + warn!( "Trying to leave a room you are not a member of, marking room as left locally." ); - return services + services .rooms .state_cache .update_membership( room_id, user_id, - default_member_content, + RoomMemberEventContent::new(MembershipState::Leave), user_id, None, None, true, ) - .await; + .await?; + + return Ok(()); }; services @@ -1938,7 +1897,7 @@ async fn remote_leave_room( room_id: &RoomId, ) -> Result<()> { let mut make_leave_response_and_server = - Err!(BadServerResponse("No remote server available to assist in leaving {room_id}.")); + Err!(BadServerResponse("No server available to assist in leaving.")); let mut servers: HashSet = services .rooms @@ -2018,25 +1977,20 @@ async fn remote_leave_room( let (make_leave_response, remote_server) = make_leave_response_and_server?; let Some(room_version_id) = make_leave_response.room_version else { - return Err!(BadServerResponse(warn!( - "No room version was returned by {remote_server} for {room_id}, room version is \ - likely not supported by conduwuit" - ))); + return Err!(BadServerResponse("Remote room version is not supported by conduwuit")); }; if !services.server.supported_room_version(&room_version_id) { - return Err!(BadServerResponse(warn!( - "Remote room version {room_version_id} for {room_id} is not supported by conduwuit", - ))); + return Err!(BadServerResponse( + "Remote room version {room_version_id} is not supported by conduwuit" + )); } let mut leave_event_stub = serde_json::from_str::( make_leave_response.event.get(), ) .map_err(|e| { - err!(BadServerResponse(warn!( - "Invalid make_leave event json received from {remote_server} for {room_id}: {e:?}" - ))) + err!(BadServerResponse("Invalid make_leave event json received from server: {e:?}")) })?; // TODO: Is origin needed? diff --git a/src/api/client/message.rs b/src/api/client/message.rs index db11ef4a..c755cc47 100644 --- a/src/api/client/message.rs +++ b/src/api/client/message.rs @@ -1,24 +1,12 @@ use axum::extract::State; use conduwuit::{ - Err, Result, at, - matrix::{ - Event, - pdu::{PduCount, PduEvent}, - }, + Err, Event, PduCount, PduEvent, Result, at, utils::{ IterStream, ReadyExt, result::{FlatOk, LogErr}, stream::{BroadbandExt, TryIgnore, WidebandExt}, }, }; -use conduwuit_service::{ - Services, - rooms::{ - lazy_loading, - lazy_loading::{Options, Witness}, - timeline::PdusIterItem, - }, -}; use futures::{FutureExt, StreamExt, TryFutureExt, future::OptionFuture, pin_mut}; use ruma::{ RoomId, UserId, @@ -29,6 +17,14 @@ use ruma::{ events::{AnyStateEvent, StateEventType, TimelineEventType, TimelineEventType::*}, serde::Raw, }; +use service::{ + Services, + rooms::{ + lazy_loading, + lazy_loading::{Options, Witness}, + timeline::PdusIterItem, + }, +}; use crate::Ruma; @@ -161,7 +157,7 @@ pub(crate) async fn get_message_events_route( let chunk = events .into_iter() .map(at!(1)) - .map(PduEvent::into_room_event) + .map(|pdu| pdu.to_room_event()) .collect(); Ok(get_message_events::v3::Response { @@ -261,9 +257,10 @@ pub(crate) async fn is_ignored_pdu( let ignored_type = IGNORED_MESSAGE_TYPES.binary_search(&pdu.kind).is_ok(); let ignored_server = services + .server .config .forbidden_remote_server_names - .is_match(pdu.sender().server_name().host()); + .contains(pdu.sender().server_name()); if ignored_type && (ignored_server || services.users.user_is_ignored(&pdu.sender, user_id).await) diff --git a/src/api/client/openid.rs b/src/api/client/openid.rs index 8d2de68d..671d0c6d 100644 --- a/src/api/client/openid.rs +++ b/src/api/client/openid.rs @@ -1,14 +1,14 @@ use std::time::Duration; use axum::extract::State; -use conduwuit::{Error, Result, utils}; +use conduwuit::utils; use ruma::{ api::client::{account, error::ErrorKind}, authentication::TokenType, }; use super::TOKEN_LENGTH; -use crate::Ruma; +use crate::{Error, Result, Ruma}; /// # `POST /_matrix/client/v3/user/{userId}/openid/request_token` /// diff --git a/src/api/client/presence.rs b/src/api/client/presence.rs index 548e5cce..9b41a721 100644 --- a/src/api/client/presence.rs +++ b/src/api/client/presence.rs @@ -1,10 +1,12 @@ use std::time::Duration; use axum::extract::State; -use conduwuit::{Err, Result}; -use ruma::api::client::presence::{get_presence, set_presence}; +use ruma::api::client::{ + error::ErrorKind, + presence::{get_presence, set_presence}, +}; -use crate::Ruma; +use crate::{Error, Result, Ruma}; /// # `PUT /_matrix/client/r0/presence/{userId}/status` /// @@ -13,17 +15,24 @@ pub(crate) async fn set_presence_route( State(services): State, body: Ruma, ) -> Result { - if !services.config.allow_local_presence { - return Err!(Request(Forbidden("Presence is disabled on this server"))); + if !services.globals.allow_local_presence() { + return Err(Error::BadRequest( + ErrorKind::forbidden(), + "Presence is disabled on this server", + )); } - if body.sender_user() != body.user_id && body.appservice_info.is_none() { - return Err!(Request(InvalidParam("Not allowed to set presence of other users"))); + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + if sender_user != &body.user_id && body.appservice_info.is_none() { + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "Not allowed to set presence of other users", + )); } services .presence - .set_presence(body.sender_user(), &body.presence, None, None, body.status_msg.clone()) + .set_presence(sender_user, &body.presence, None, None, body.status_msg.clone()) .await?; Ok(set_presence::v3::Response {}) @@ -38,15 +47,21 @@ pub(crate) async fn get_presence_route( State(services): State, body: Ruma, ) -> Result { - if !services.config.allow_local_presence { - return Err!(Request(Forbidden("Presence is disabled on this server",))); + if !services.globals.allow_local_presence() { + return Err(Error::BadRequest( + ErrorKind::forbidden(), + "Presence is disabled on this server", + )); } + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + let mut presence_event = None; + let has_shared_rooms = services .rooms .state_cache - .user_sees_user(body.sender_user(), &body.user_id) + .user_sees_user(sender_user, &body.user_id) .await; if has_shared_rooms { @@ -84,6 +99,9 @@ pub(crate) async fn get_presence_route( presence: presence.content.presence, }) }, - | _ => Err!(Request(NotFound("Presence state for this user was not found"))), + | _ => Err(Error::BadRequest( + ErrorKind::NotFound, + "Presence state for this user was not found", + )), } } diff --git a/src/api/client/profile.rs b/src/api/client/profile.rs index 3699b590..12e5ebcc 100644 --- a/src/api/client/profile.rs +++ b/src/api/client/profile.rs @@ -3,11 +3,10 @@ use std::collections::BTreeMap; use axum::extract::State; use conduwuit::{ Err, Error, Result, - matrix::pdu::PduBuilder, + pdu::PduBuilder, utils::{IterStream, stream::TryIgnore}, warn, }; -use conduwuit_service::Services; use futures::{StreamExt, TryStreamExt, future::join3}; use ruma::{ OwnedMxcUri, OwnedRoomId, UserId, @@ -23,6 +22,7 @@ use ruma::{ events::room::member::{MembershipState, RoomMemberEventContent}, presence::PresenceState, }; +use service::Services; use crate::Ruma; @@ -52,7 +52,7 @@ pub(crate) async fn set_displayname_route( update_displayname(&services, &body.user_id, body.displayname.clone(), &all_joined_rooms) .await; - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { // Presence update services .presence @@ -147,7 +147,7 @@ pub(crate) async fn set_avatar_url_route( ) .await; - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { // Presence update services .presence diff --git a/src/api/client/push.rs b/src/api/client/push.rs index 81020ffa..384b9dbc 100644 --- a/src/api/client/push.rs +++ b/src/api/client/push.rs @@ -1,6 +1,5 @@ use axum::extract::State; -use conduwuit::{Err, Error, Result, err}; -use conduwuit_service::Services; +use conduwuit::{Err, err}; use ruma::{ CanonicalJsonObject, CanonicalJsonValue, api::client::{ @@ -20,8 +19,9 @@ use ruma::{ RemovePushRuleError, Ruleset, }, }; +use service::Services; -use crate::Ruma; +use crate::{Error, Result, Ruma}; /// # `GET /_matrix/client/r0/pushrules/` /// @@ -503,7 +503,7 @@ pub(crate) async fn set_pushers_route( services .pusher - .set_pusher(sender_user, body.sender_device(), &body.action) + .set_pusher(sender_user, &body.action) .await?; Ok(set_pusher::v3::Response::new()) diff --git a/src/api/client/read_marker.rs b/src/api/client/read_marker.rs index fbfc8fea..187616b4 100644 --- a/src/api/client/read_marker.rs +++ b/src/api/client/read_marker.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use axum::extract::State; -use conduwuit::{Err, PduCount, Result, err}; +use conduwuit::{Err, PduCount, err}; use ruma::{ MilliSecondsSinceUnixEpoch, api::client::{read_marker::set_read_marker, receipt::create_receipt}, @@ -11,7 +11,7 @@ use ruma::{ }, }; -use crate::Ruma; +use crate::{Result, Ruma}; /// # `POST /_matrix/client/r0/rooms/{roomId}/read_markers` /// @@ -50,7 +50,7 @@ pub(crate) async fn set_read_marker_route( } // ping presence - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { services .presence .ping_presence(sender_user, &ruma::presence::PresenceState::Online) @@ -126,7 +126,7 @@ pub(crate) async fn create_receipt_route( } // ping presence - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { services .presence .ping_presence(sender_user, &ruma::presence::PresenceState::Online) diff --git a/src/api/client/redact.rs b/src/api/client/redact.rs index 8dbe47a6..7b512d06 100644 --- a/src/api/client/redact.rs +++ b/src/api/client/redact.rs @@ -1,10 +1,9 @@ use axum::extract::State; -use conduwuit::{Result, matrix::pdu::PduBuilder}; use ruma::{ api::client::redact::redact_event, events::room::redaction::RoomRedactionEventContent, }; -use crate::Ruma; +use crate::{Result, Ruma, service::pdu::PduBuilder}; /// # `PUT /_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}` /// diff --git a/src/api/client/relations.rs b/src/api/client/relations.rs index b8c2dd4d..7ed40f14 100644 --- a/src/api/client/relations.rs +++ b/src/api/client/relations.rs @@ -1,10 +1,8 @@ use axum::extract::State; use conduwuit::{ - Result, at, - matrix::pdu::PduCount, + PduCount, Result, at, utils::{IterStream, ReadyExt, result::FlatOk, stream::WidebandExt}, }; -use conduwuit_service::{Services, rooms::timeline::PdusIterItem}; use futures::StreamExt; use ruma::{ EventId, RoomId, UInt, UserId, @@ -17,6 +15,7 @@ use ruma::{ }, events::{TimelineEventType, relation::RelationType}, }; +use service::{Services, rooms::timeline::PdusIterItem}; use crate::Ruma; diff --git a/src/api/client/report.rs b/src/api/client/report.rs index 4ee8ebe5..7922caca 100644 --- a/src/api/client/report.rs +++ b/src/api/client/report.rs @@ -2,8 +2,7 @@ use std::time::Duration; use axum::extract::State; use axum_client_ip::InsecureClientIp; -use conduwuit::{Err, Error, Result, debug_info, info, matrix::pdu::PduEvent, utils::ReadyExt}; -use conduwuit_service::Services; +use conduwuit::{Err, info, utils::ReadyExt}; use rand::Rng; use ruma::{ EventId, RoomId, UserId, @@ -16,7 +15,10 @@ use ruma::{ }; use tokio::time::sleep; -use crate::Ruma; +use crate::{ + Error, Result, Ruma, debug_info, + service::{Services, pdu::PduEvent}, +}; /// # `POST /_matrix/client/v3/rooms/{roomId}/report` /// diff --git a/src/api/client/room/create.rs b/src/api/client/room/create.rs index 4ce53f15..bb06e966 100644 --- a/src/api/client/room/create.rs +++ b/src/api/client/room/create.rs @@ -2,11 +2,8 @@ use std::collections::BTreeMap; use axum::extract::State; use conduwuit::{ - Err, Error, Result, debug_info, debug_warn, err, error, info, - matrix::{StateKey, pdu::PduBuilder}, - warn, + Err, Error, Result, StateKey, debug_info, debug_warn, err, error, info, pdu::PduBuilder, warn, }; -use conduwuit_service::{Services, appservice::RegistrationInfo}; use futures::FutureExt; use ruma::{ CanonicalJsonObject, Int, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomId, RoomVersionId, @@ -32,6 +29,7 @@ use ruma::{ serde::{JsonObject, Raw}, }; use serde_json::{json, value::to_raw_value}; +use service::{Services, appservice::RegistrationInfo}; use crate::{Ruma, client::invite_helper}; @@ -374,7 +372,7 @@ pub(crate) async fn create_room_route( // Silently skip encryption events if they are not allowed if pdu_builder.event_type == TimelineEventType::RoomEncryption - && !services.config.allow_encryption + && !services.globals.allow_encryption() { continue; } diff --git a/src/api/client/room/event.rs b/src/api/client/room/event.rs index 2b115b5c..84b591cd 100644 --- a/src/api/client/room/event.rs +++ b/src/api/client/room/event.rs @@ -40,5 +40,5 @@ pub(crate) async fn get_room_event_route( event.add_age().ok(); - Ok(get_room_event::v3::Response { event: event.into_room_event() }) + Ok(get_room_event::v3::Response { event: event.to_room_event() }) } diff --git a/src/api/client/room/initial_sync.rs b/src/api/client/room/initial_sync.rs index ca63610b..e4c76ae0 100644 --- a/src/api/client/room/initial_sync.rs +++ b/src/api/client/room/initial_sync.rs @@ -55,7 +55,7 @@ pub(crate) async fn room_initial_sync_route( chunk: events .into_iter() .map(at!(1)) - .map(PduEvent::into_room_event) + .map(|pdu| pdu.to_room_event()) .collect(), }; diff --git a/src/api/client/room/mod.rs b/src/api/client/room/mod.rs index 86d68f7e..16fcadab 100644 --- a/src/api/client/room/mod.rs +++ b/src/api/client/room/mod.rs @@ -2,14 +2,9 @@ mod aliases; mod create; mod event; mod initial_sync; -mod summary; mod upgrade; pub(crate) use self::{ - aliases::get_room_aliases_route, - create::create_room_route, - event::get_room_event_route, - initial_sync::room_initial_sync_route, - summary::{get_room_summary, get_room_summary_legacy}, - upgrade::upgrade_room_route, + aliases::get_room_aliases_route, create::create_room_route, event::get_room_event_route, + initial_sync::room_initial_sync_route, upgrade::upgrade_room_route, }; diff --git a/src/api/client/room/summary.rs b/src/api/client/room/summary.rs deleted file mode 100644 index 67d2e2ad..00000000 --- a/src/api/client/room/summary.rs +++ /dev/null @@ -1,330 +0,0 @@ -use axum::extract::State; -use axum_client_ip::InsecureClientIp; -use conduwuit::{ - Err, Result, debug_warn, trace, - utils::{IterStream, future::TryExtExt}, -}; -use futures::{ - FutureExt, StreamExt, - future::{OptionFuture, join3}, - stream::FuturesUnordered, -}; -use ruma::{ - OwnedServerName, RoomId, UserId, - api::{ - client::room::get_summary, - federation::space::{SpaceHierarchyParentSummary, get_hierarchy}, - }, - events::room::member::MembershipState, - space::SpaceRoomJoinRule::{self, *}, -}; -use service::Services; - -use crate::{Ruma, RumaResponse}; - -/// # `GET /_matrix/client/unstable/im.nheko.summary/rooms/{roomIdOrAlias}/summary` -/// -/// Returns a short description of the state of a room. -/// -/// This is the "wrong" endpoint that some implementations/clients may use -/// according to the MSC. Request and response bodies are the same as -/// `get_room_summary`. -/// -/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266) -pub(crate) async fn get_room_summary_legacy( - State(services): State, - InsecureClientIp(client): InsecureClientIp, - body: Ruma, -) -> Result> { - get_room_summary(State(services), InsecureClientIp(client), body) - .boxed() - .await - .map(RumaResponse) -} - -/// # `GET /_matrix/client/unstable/im.nheko.summary/summary/{roomIdOrAlias}` -/// -/// Returns a short description of the state of a room. -/// -/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266) -#[tracing::instrument(skip_all, fields(%client), name = "room_summary")] -pub(crate) async fn get_room_summary( - State(services): State, - InsecureClientIp(client): InsecureClientIp, - body: Ruma, -) -> Result { - let (room_id, servers) = services - .rooms - .alias - .resolve_with_servers(&body.room_id_or_alias, Some(body.via.clone())) - .await?; - - if services.rooms.metadata.is_banned(&room_id).await { - return Err!(Request(Forbidden("This room is banned on this homeserver."))); - } - - room_summary_response(&services, &room_id, &servers, body.sender_user.as_deref()) - .boxed() - .await -} - -async fn room_summary_response( - services: &Services, - room_id: &RoomId, - servers: &[OwnedServerName], - sender_user: Option<&UserId>, -) -> Result { - if services - .rooms - .state_cache - .server_in_room(services.globals.server_name(), room_id) - .await - { - return local_room_summary_response(services, room_id, sender_user) - .boxed() - .await; - } - - let room = - remote_room_summary_hierarchy_response(services, room_id, servers, sender_user).await?; - - Ok(get_summary::msc3266::Response { - room_id: room_id.to_owned(), - canonical_alias: room.canonical_alias, - avatar_url: room.avatar_url, - guest_can_join: room.guest_can_join, - name: room.name, - num_joined_members: room.num_joined_members, - topic: room.topic, - world_readable: room.world_readable, - join_rule: room.join_rule, - room_type: room.room_type, - room_version: room.room_version, - encryption: room.encryption, - allowed_room_ids: room.allowed_room_ids, - membership: sender_user.is_some().then_some(MembershipState::Leave), - }) -} - -async fn local_room_summary_response( - services: &Services, - room_id: &RoomId, - sender_user: Option<&UserId>, -) -> Result { - trace!(?sender_user, "Sending local room summary response for {room_id:?}"); - let join_rule = services.rooms.state_accessor.get_join_rules(room_id); - let world_readable = services.rooms.state_accessor.is_world_readable(room_id); - let guest_can_join = services.rooms.state_accessor.guest_can_join(room_id); - - let (join_rule, world_readable, guest_can_join) = - join3(join_rule, world_readable, guest_can_join).await; - trace!("{join_rule:?}, {world_readable:?}, {guest_can_join:?}"); - - user_can_see_summary( - services, - room_id, - &join_rule.clone().into(), - guest_can_join, - world_readable, - join_rule.allowed_rooms(), - sender_user, - ) - .await?; - - let canonical_alias = services - .rooms - .state_accessor - .get_canonical_alias(room_id) - .ok(); - - let name = services.rooms.state_accessor.get_name(room_id).ok(); - - let topic = services.rooms.state_accessor.get_room_topic(room_id).ok(); - - let room_type = services.rooms.state_accessor.get_room_type(room_id).ok(); - - let avatar_url = services - .rooms - .state_accessor - .get_avatar(room_id) - .map(|res| res.into_option().unwrap_or_default().url); - - let room_version = services.rooms.state.get_room_version(room_id).ok(); - - let encryption = services - .rooms - .state_accessor - .get_room_encryption(room_id) - .ok(); - - let num_joined_members = services - .rooms - .state_cache - .room_joined_count(room_id) - .unwrap_or(0); - - let membership: OptionFuture<_> = sender_user - .map(|sender_user| { - services - .rooms - .state_accessor - .get_member(room_id, sender_user) - .map_ok_or(MembershipState::Leave, |content| content.membership) - }) - .into(); - - let ( - canonical_alias, - name, - num_joined_members, - topic, - avatar_url, - room_type, - room_version, - encryption, - membership, - ) = futures::join!( - canonical_alias, - name, - num_joined_members, - topic, - avatar_url, - room_type, - room_version, - encryption, - membership, - ); - - Ok(get_summary::msc3266::Response { - room_id: room_id.to_owned(), - canonical_alias, - avatar_url, - guest_can_join, - name, - num_joined_members: num_joined_members.try_into().unwrap_or_default(), - topic, - world_readable, - room_type, - room_version, - encryption, - membership, - allowed_room_ids: join_rule.allowed_rooms().map(Into::into).collect(), - join_rule: join_rule.into(), - }) -} - -/// used by MSC3266 to fetch a room's info if we do not know about it -async fn remote_room_summary_hierarchy_response( - services: &Services, - room_id: &RoomId, - servers: &[OwnedServerName], - sender_user: Option<&UserId>, -) -> Result { - trace!(?sender_user, ?servers, "Sending remote room summary response for {room_id:?}"); - if !services.config.allow_federation { - return Err!(Request(Forbidden("Federation is disabled."))); - } - - if services.rooms.metadata.is_disabled(room_id).await { - return Err!(Request(Forbidden( - "Federaton of room {room_id} is currently disabled on this server." - ))); - } - - let request = get_hierarchy::v1::Request::new(room_id.to_owned()); - - let mut requests: FuturesUnordered<_> = servers - .iter() - .map(|server| { - services - .sending - .send_federation_request(server, request.clone()) - }) - .collect(); - - while let Some(Ok(response)) = requests.next().await { - trace!("{response:?}"); - let room = response.room.clone(); - if room.room_id != room_id { - debug_warn!( - "Room ID {} returned does not belong to the requested room ID {}", - room.room_id, - room_id - ); - continue; - } - - return user_can_see_summary( - services, - room_id, - &room.join_rule, - room.guest_can_join, - room.world_readable, - room.allowed_room_ids.iter().map(AsRef::as_ref), - sender_user, - ) - .await - .map(|()| room); - } - - Err!(Request(NotFound( - "Room is unknown to this server and was unable to fetch over federation with the \ - provided servers available" - ))) -} - -async fn user_can_see_summary<'a, I>( - services: &Services, - room_id: &RoomId, - join_rule: &SpaceRoomJoinRule, - guest_can_join: bool, - world_readable: bool, - allowed_room_ids: I, - sender_user: Option<&UserId>, -) -> Result -where - I: Iterator + Send, -{ - let is_public_room = matches!(join_rule, Public | Knock | KnockRestricted); - match sender_user { - | Some(sender_user) => { - let user_can_see_state_events = services - .rooms - .state_accessor - .user_can_see_state_events(sender_user, room_id); - let is_guest = services.users.is_deactivated(sender_user).unwrap_or(false); - let user_in_allowed_restricted_room = allowed_room_ids - .stream() - .any(|room| services.rooms.state_cache.is_joined(sender_user, room)); - - let (user_can_see_state_events, is_guest, user_in_allowed_restricted_room) = - join3(user_can_see_state_events, is_guest, user_in_allowed_restricted_room) - .boxed() - .await; - - if user_can_see_state_events - || (is_guest && guest_can_join) - || is_public_room - || user_in_allowed_restricted_room - { - return Ok(()); - } - - Err!(Request(Forbidden( - "Room is not world readable, not publicly accessible/joinable, restricted room \ - conditions not met, and guest access is forbidden. Not allowed to see details \ - of this room." - ))) - }, - | None => { - if is_public_room || world_readable { - return Ok(()); - } - - Err!(Request(Forbidden( - "Room is not world readable or publicly accessible/joinable, authentication is \ - required" - ))) - }, - } -} diff --git a/src/api/client/room/upgrade.rs b/src/api/client/room/upgrade.rs index 9ec0b3bb..4ac341a9 100644 --- a/src/api/client/room/upgrade.rs +++ b/src/api/client/room/upgrade.rs @@ -1,10 +1,7 @@ use std::cmp::max; use axum::extract::State; -use conduwuit::{ - Error, Result, err, info, - matrix::{StateKey, pdu::PduBuilder}, -}; +use conduwuit::{Error, Result, StateKey, err, info, pdu::PduBuilder}; use futures::StreamExt; use ruma::{ CanonicalJsonObject, RoomId, RoomVersionId, @@ -106,7 +103,7 @@ pub(crate) async fn upgrade_room_route( // Use the m.room.tombstone event as the predecessor let predecessor = Some(ruma::events::room::create::PreviousRoom::new( body.room_id.clone(), - Some(tombstone_event_id), + (*tombstone_event_id).to_owned(), )); // Send a m.room.create event containing a predecessor field and the applicable diff --git a/src/api/client/search.rs b/src/api/client/search.rs index d4dcde57..f3366843 100644 --- a/src/api/client/search.rs +++ b/src/api/client/search.rs @@ -2,12 +2,10 @@ use std::collections::BTreeMap; use axum::extract::State; use conduwuit::{ - Err, Result, at, is_true, - matrix::pdu::PduEvent, + Err, PduEvent, Result, at, is_true, result::FlatOk, utils::{IterStream, stream::ReadyExt}, }; -use conduwuit_service::{Services, rooms::search::RoomQuery}; use futures::{FutureExt, StreamExt, TryFutureExt, TryStreamExt, future::OptionFuture}; use ruma::{ OwnedRoomId, RoomId, UInt, UserId, @@ -19,6 +17,7 @@ use ruma::{ serde::Raw, }; use search_events::v3::{Request, Response}; +use service::{Services, rooms::search::RoomQuery}; use crate::Ruma; @@ -144,7 +143,7 @@ async fn category_room_events( .map(at!(2)) .flatten() .stream() - .map(PduEvent::into_room_event) + .map(|pdu| pdu.to_room_event()) .map(|result| SearchResult { rank: None, result: Some(result), diff --git a/src/api/client/send.rs b/src/api/client/send.rs index f753fa65..b01d1ed6 100644 --- a/src/api/client/send.rs +++ b/src/api/client/send.rs @@ -1,11 +1,11 @@ use std::collections::BTreeMap; use axum::extract::State; -use conduwuit::{Err, Result, err, matrix::pdu::PduBuilder, utils}; +use conduwuit::{Err, err}; use ruma::{api::client::message::send_message_event, events::MessageLikeEventType}; use serde_json::from_str; -use crate::Ruma; +use crate::{Result, Ruma, service::pdu::PduBuilder, utils}; /// # `PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}` /// @@ -25,7 +25,8 @@ pub(crate) async fn send_message_event_route( let appservice_info = body.appservice_info.as_ref(); // Forbid m.room.encrypted if encryption is disabled - if MessageLikeEventType::RoomEncrypted == body.event_type && !services.config.allow_encryption + if MessageLikeEventType::RoomEncrypted == body.event_type + && !services.globals.allow_encryption() { return Err!(Request(Forbidden("Encryption has been disabled"))); } diff --git a/src/api/client/session.rs b/src/api/client/session.rs index 2499a43d..3de625e4 100644 --- a/src/api/client/session.rs +++ b/src/api/client/session.rs @@ -2,11 +2,7 @@ use std::time::Duration; use axum::extract::State; use axum_client_ip::InsecureClientIp; -use conduwuit::{ - Err, Error, Result, debug, err, info, utils, - utils::{ReadyExt, hash}, -}; -use conduwuit_service::uiaa::SESSION_ID_LENGTH; +use conduwuit::{Err, debug, err, info, utils::ReadyExt}; use futures::StreamExt; use ruma::{ UserId, @@ -26,9 +22,10 @@ use ruma::{ uiaa, }, }; +use service::uiaa::SESSION_ID_LENGTH; use super::{DEVICE_ID_LENGTH, TOKEN_LENGTH}; -use crate::Ruma; +use crate::{Error, Result, Ruma, utils, utils::hash}; /// # `GET /_matrix/client/v3/login` /// diff --git a/src/api/client/space.rs b/src/api/client/space.rs index 4eee9d76..a667f852 100644 --- a/src/api/client/space.rs +++ b/src/api/client/space.rs @@ -8,16 +8,16 @@ use conduwuit::{ Err, Result, utils::{future::TryExtExt, stream::IterStream}, }; -use conduwuit_service::{ +use futures::{StreamExt, TryFutureExt, future::OptionFuture}; +use ruma::{ + OwnedRoomId, OwnedServerName, RoomId, UInt, UserId, api::client::space::get_hierarchy, +}; +use service::{ Services, rooms::spaces::{ PaginationToken, SummaryAccessibility, get_parent_children_via, summary_to_chunk, }, }; -use futures::{StreamExt, TryFutureExt, future::OptionFuture}; -use ruma::{ - OwnedRoomId, OwnedServerName, RoomId, UInt, UserId, api::client::space::get_hierarchy, -}; use crate::Ruma; @@ -155,7 +155,11 @@ where break; } - if parents.len() > max_depth { + if children.is_empty() { + break; + } + + if parents.len() >= max_depth { continue; } diff --git a/src/api/client/state.rs b/src/api/client/state.rs index 2ddc8f14..9563c26d 100644 --- a/src/api/client/state.rs +++ b/src/api/client/state.rs @@ -1,10 +1,5 @@ use axum::extract::State; -use conduwuit::{ - Err, Result, err, - matrix::pdu::{PduBuilder, PduEvent}, - utils::BoolExt, -}; -use conduwuit_service::Services; +use conduwuit::{Err, PduEvent, Result, err, pdu::PduBuilder, utils::BoolExt}; use futures::TryStreamExt; use ruma::{ OwnedEventId, RoomId, UserId, @@ -21,6 +16,7 @@ use ruma::{ }, serde::Raw, }; +use service::Services; use crate::{Ruma, RumaResponse}; @@ -211,7 +207,7 @@ async fn allowed_to_send_state_event( // irreversible mistakes match json.deserialize_as::() { | Ok(acl_content) => { - if acl_content.allow_is_empty() { + if acl_content.allow.is_empty() { return Err!(Request(BadJson(debug_warn!( ?room_id, "Sending an ACL event with an empty allow key will permanently \ @@ -220,7 +216,9 @@ async fn allowed_to_send_state_event( )))); } - if acl_content.deny_contains("*") && acl_content.allow_contains("*") { + if acl_content.deny.contains(&String::from("*")) + && acl_content.allow.contains(&String::from("*")) + { return Err!(Request(BadJson(debug_warn!( ?room_id, "Sending an ACL event with a deny and allow key value of \"*\" will \ @@ -229,9 +227,8 @@ async fn allowed_to_send_state_event( )))); } - if acl_content.deny_contains("*") + if acl_content.deny.contains(&String::from("*")) && !acl_content.is_allowed(services.globals.server_name()) - && !acl_content.allow_contains(services.globals.server_name().as_str()) { return Err!(Request(BadJson(debug_warn!( ?room_id, @@ -241,9 +238,8 @@ async fn allowed_to_send_state_event( )))); } - if !acl_content.allow_contains("*") + if !acl_content.allow.contains(&String::from("*")) && !acl_content.is_allowed(services.globals.server_name()) - && !acl_content.allow_contains(services.globals.server_name().as_str()) { return Err!(Request(BadJson(debug_warn!( ?room_id, diff --git a/src/api/client/sync/mod.rs b/src/api/client/sync/mod.rs index 14459acf..3eab76cc 100644 --- a/src/api/client/sync/mod.rs +++ b/src/api/client/sync/mod.rs @@ -3,14 +3,12 @@ mod v4; mod v5; use conduwuit::{ - Error, PduCount, Result, - matrix::pdu::PduEvent, + PduCount, utils::{ IterStream, stream::{BroadbandExt, ReadyExt, TryIgnore}, }, }; -use conduwuit_service::Services; use futures::{StreamExt, pin_mut}; use ruma::{ RoomId, UserId, @@ -23,6 +21,7 @@ use ruma::{ pub(crate) use self::{ v3::sync_events_route, v4::sync_events_v4_route, v5::sync_events_v5_route, }; +use crate::{Error, PduEvent, Result, service::Services}; pub(crate) const DEFAULT_BUMP_TYPES: &[TimelineEventType; 6] = &[CallInvite, PollStart, Beacon, RoomEncrypted, RoomMessage, Sticker]; diff --git a/src/api/client/sync/v3.rs b/src/api/client/sync/v3.rs index 24930941..70c4c6a7 100644 --- a/src/api/client/sync/v3.rs +++ b/src/api/client/sync/v3.rs @@ -6,20 +6,15 @@ use std::{ use axum::extract::State; use conduwuit::{ - Result, at, err, error, extract_variant, is_equal_to, - matrix::{ - Event, - pdu::{EventHash, PduCount, PduEvent}, - }, - pair_of, ref_at, + PduCount, PduEvent, Result, at, err, error, extract_variant, is_equal_to, pair_of, + pdu::{Event, EventHash}, + ref_at, result::FlatOk, utils::{ self, BoolExt, IterStream, ReadyExt, TryFutureExtExt, - future::OptionStream, math::ruma_from_u64, stream::{BroadbandExt, Tools, TryExpect, WidebandExt}, }, - warn, }; use conduwuit_service::{ Services, @@ -123,7 +118,7 @@ pub(crate) async fn sync_events_route( let (sender_user, sender_device) = body.sender(); // Presence update - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { services .presence .ping_presence(sender_user, &body.body.set_presence) @@ -284,8 +279,8 @@ pub(crate) async fn build_sync_events( }); let presence_updates: OptionFuture<_> = services - .config - .allow_local_presence + .globals + .allow_local_presence() .then(|| process_presence_updates(services, since, sender_user)) .into(); @@ -433,12 +428,9 @@ async fn handle_left_room( return Ok(None); } - if !services.rooms.metadata.exists(room_id).await - || services.rooms.metadata.is_disabled(room_id).await - || services.rooms.metadata.is_banned(room_id).await - { + if !services.rooms.metadata.exists(room_id).await { // This is just a rejected invite, not a room we know - // Insert a leave event anyways for the client + // Insert a leave event anyways let event = PduEvent { event_id: EventId::new(services.globals.server_name()), sender: sender_user.to_owned(), @@ -469,7 +461,7 @@ async fn handle_left_room( events: Vec::new(), }, state: RoomState { - events: vec![event.into_sync_state_event()], + events: vec![event.to_sync_state_event()], }, })); } @@ -497,7 +489,7 @@ async fn handle_left_room( .room_state_get_id(room_id, &StateEventType::RoomMember, sender_user.as_str()) .await else { - warn!("Left {room_id} but no left state event"); + error!("Left room but no left state event"); return Ok(None); }; @@ -507,7 +499,7 @@ async fn handle_left_room( .pdu_shortstatehash(&left_event_id) .await else { - warn!(event_id = %left_event_id, "Leave event has no state in {room_id}"); + error!(event_id = %left_event_id, "Leave event has no state"); return Ok(None); }; @@ -554,7 +546,7 @@ async fn handle_left_room( continue; } - left_state_events.push(pdu.into_sync_state_event()); + left_state_events.push(pdu.to_sync_state_event()); } } @@ -873,8 +865,8 @@ async fn load_joined_room( }, state: RoomState { events: state_events - .into_iter() - .map(PduEvent::into_sync_state_event) + .iter() + .map(PduEvent::to_sync_state_event) .collect(), }, ephemeral: Ephemeral { events: edus }, @@ -1037,7 +1029,7 @@ async fn calculate_state_incremental<'a>( }) .into(); - let state_diff_ids: OptionFuture<_> = (!full_state && state_changed) + let state_diff: OptionFuture<_> = (!full_state && state_changed) .then(|| { StreamExt::into_future( services @@ -1062,9 +1054,45 @@ async fn calculate_state_incremental<'a>( }) .into(); + let lazy_state_ids = lazy_state_ids + .map(|opt| { + opt.map(|(curr, next)| { + let opt = curr; + let iter = Option::into_iter(opt); + IterStream::stream(iter).chain(next) + }) + }) + .map(Option::into_iter) + .map(IterStream::stream) + .flatten_stream() + .flatten(); + + let state_diff_ids = state_diff + .map(|opt| { + opt.map(|(curr, next)| { + let opt = curr; + let iter = Option::into_iter(opt); + IterStream::stream(iter).chain(next) + }) + }) + .map(Option::into_iter) + .map(IterStream::stream) + .flatten_stream() + .flatten(); + let state_events = current_state_ids - .stream() - .chain(state_diff_ids.stream()) + .map(|opt| { + opt.map(|(curr, next)| { + let opt = curr; + let iter = Option::into_iter(opt); + IterStream::stream(iter).chain(next) + }) + }) + .map(Option::into_iter) + .map(IterStream::stream) + .flatten_stream() + .flatten() + .chain(state_diff_ids) .broad_filter_map(|(shortstatekey, shorteventid)| async move { if witness.is_none() || encrypted_room { return Some(shorteventid); @@ -1072,7 +1100,7 @@ async fn calculate_state_incremental<'a>( lazy_filter(services, sender_user, shortstatekey, shorteventid).await }) - .chain(lazy_state_ids.stream()) + .chain(lazy_state_ids) .broad_filter_map(|shorteventid| { services .rooms diff --git a/src/api/client/sync/v4.rs b/src/api/client/sync/v4.rs index f7edb8c0..5fdcbab8 100644 --- a/src/api/client/sync/v4.rs +++ b/src/api/client/sync/v4.rs @@ -6,7 +6,7 @@ use std::{ use axum::extract::State; use conduwuit::{ - Error, PduCount, PduEvent, Result, debug, error, extract_variant, + Error, PduCount, Result, debug, error, extract_variant, utils::{ BoolExt, IterStream, ReadyExt, TryFutureExtExt, math::{ruma_from_usize, usize_from_ruma, usize_from_u64_truncated}, @@ -438,10 +438,7 @@ pub(crate) async fn sync_events_v4_route( let mut known_subscription_rooms = BTreeSet::new(); for (room_id, room) in &body.room_subscriptions { - if !services.rooms.metadata.exists(room_id).await - || services.rooms.metadata.is_disabled(room_id).await - || services.rooms.metadata.is_banned(room_id).await - { + if !services.rooms.metadata.exists(room_id).await { continue; } let todo_room = @@ -637,7 +634,7 @@ pub(crate) async fn sync_events_v4_route( .state_accessor .room_state_get(room_id, &state.0, &state.1) .await - .map(PduEvent::into_sync_state_event) + .map(|s| s.to_sync_state_event()) .ok() }) .collect() diff --git a/src/api/client/sync/v5.rs b/src/api/client/sync/v5.rs index 684752ec..b4c1b815 100644 --- a/src/api/client/sync/v5.rs +++ b/src/api/client/sync/v5.rs @@ -6,19 +6,13 @@ use std::{ use axum::extract::State; use conduwuit::{ - Error, Result, debug, error, extract_variant, - matrix::{ - TypeStateKey, - pdu::{PduCount, PduEvent}, - }, - trace, + Error, Result, TypeStateKey, debug, error, extract_variant, trace, utils::{ BoolExt, IterStream, ReadyExt, TryFutureExtExt, math::{ruma_from_usize, usize_from_ruma}, }, warn, }; -use conduwuit_service::rooms::read_receipt::pack_receipts; use futures::{FutureExt, StreamExt, TryFutureExt}; use ruma::{ DeviceId, OwnedEventId, OwnedRoomId, RoomId, UInt, UserId, @@ -33,6 +27,7 @@ use ruma::{ serde::Raw, uint, }; +use service::{PduCount, rooms::read_receipt::pack_receipts}; use super::{filter_rooms, share_encrypted_room}; use crate::{ @@ -219,10 +214,7 @@ async fn fetch_subscriptions( ) { let mut known_subscription_rooms = BTreeSet::new(); for (room_id, room) in &body.room_subscriptions { - if !services.rooms.metadata.exists(room_id).await - || services.rooms.metadata.is_disabled(room_id).await - || services.rooms.metadata.is_banned(room_id).await - { + if !services.rooms.metadata.exists(room_id).await { continue; } let todo_room = @@ -515,7 +507,7 @@ async fn process_rooms( .state_accessor .room_state_get(room_id, &state.0, &state.1) .await - .map(PduEvent::into_sync_state_event) + .map(|s| s.to_sync_state_event()) .ok() }) .collect() diff --git a/src/api/client/tag.rs b/src/api/client/tag.rs index caafe10d..3b3b40d4 100644 --- a/src/api/client/tag.rs +++ b/src/api/client/tag.rs @@ -1,7 +1,6 @@ use std::collections::BTreeMap; use axum::extract::State; -use conduwuit::Result; use ruma::{ api::client::tag::{create_tag, delete_tag, get_tags}, events::{ @@ -10,7 +9,7 @@ use ruma::{ }, }; -use crate::Ruma; +use crate::{Result, Ruma}; /// # `PUT /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}` /// diff --git a/src/api/client/thirdparty.rs b/src/api/client/thirdparty.rs index 0713a882..790b27d3 100644 --- a/src/api/client/thirdparty.rs +++ b/src/api/client/thirdparty.rs @@ -1,9 +1,8 @@ use std::collections::BTreeMap; -use conduwuit::Result; use ruma::api::client::thirdparty::get_protocols; -use crate::{Ruma, RumaResponse}; +use crate::{Result, Ruma, RumaResponse}; /// # `GET /_matrix/client/r0/thirdparty/protocols` /// diff --git a/src/api/client/threads.rs b/src/api/client/threads.rs index 5b838bef..d25e52c0 100644 --- a/src/api/client/threads.rs +++ b/src/api/client/threads.rs @@ -1,12 +1,9 @@ use axum::extract::State; -use conduwuit::{ - Result, at, - matrix::pdu::{PduCount, PduEvent}, -}; +use conduwuit::{PduCount, PduEvent, at}; use futures::StreamExt; use ruma::{api::client::threads::get_threads, uint}; -use crate::Ruma; +use crate::{Result, Ruma}; /// # `GET /_matrix/client/r0/rooms/{roomId}/threads` pub(crate) async fn get_threads_route( @@ -56,7 +53,7 @@ pub(crate) async fn get_threads_route( chunk: threads .into_iter() .map(at!(1)) - .map(PduEvent::into_room_event) + .map(|pdu| pdu.to_room_event()) .collect(), }) } diff --git a/src/api/client/to_device.rs b/src/api/client/to_device.rs index 8ad9dc99..1b942fba 100644 --- a/src/api/client/to_device.rs +++ b/src/api/client/to_device.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use axum::extract::State; use conduwuit::{Error, Result}; -use conduwuit_service::sending::EduBuf; use futures::StreamExt; use ruma::{ api::{ @@ -11,6 +10,7 @@ use ruma::{ }, to_device::DeviceIdOrAllDevices, }; +use service::sending::EduBuf; use crate::Ruma; diff --git a/src/api/client/typing.rs b/src/api/client/typing.rs index 1d8d02fd..ccfa7340 100644 --- a/src/api/client/typing.rs +++ b/src/api/client/typing.rs @@ -1,8 +1,8 @@ use axum::extract::State; -use conduwuit::{Err, Result, utils, utils::math::Tried}; +use conduwuit::{Err, utils::math::Tried}; use ruma::api::client::typing::create_typing_event; -use crate::Ruma; +use crate::{Result, Ruma, utils}; /// # `PUT /_matrix/client/r0/rooms/{roomId}/typing/{userId}` /// @@ -64,7 +64,7 @@ pub(crate) async fn create_typing_event_route( } // ping presence - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { services .presence .ping_presence(&body.user_id, &ruma::presence::PresenceState::Online) diff --git a/src/api/client/unstable.rs b/src/api/client/unstable.rs index e21eaf21..08da5a37 100644 --- a/src/api/client/unstable.rs +++ b/src/api/client/unstable.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use axum::extract::State; use axum_client_ip::InsecureClientIp; -use conduwuit::{Err, Error, Result}; +use conduwuit::Err; use futures::StreamExt; use ruma::{ OwnedRoomId, @@ -14,14 +14,16 @@ use ruma::{ delete_profile_key, delete_timezone_key, get_profile_key, get_timezone_key, set_profile_key, set_timezone_key, }, + room::get_summary, }, federation, }, + events::room::member::MembershipState, presence::PresenceState, }; use super::{update_avatar_url, update_displayname}; -use crate::Ruma; +use crate::{Error, Result, Ruma, RumaResponse}; /// # `GET /_matrix/client/unstable/uk.half-shot.msc2666/user/mutual_rooms` /// @@ -36,10 +38,13 @@ pub(crate) async fn get_mutual_rooms_route( InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result { - let sender_user = body.sender_user(); + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - if sender_user == body.user_id { - return Err!(Request(Unknown("You cannot request rooms in common with yourself."))); + if sender_user == &body.user_id { + return Err(Error::BadRequest( + ErrorKind::Unknown, + "You cannot request rooms in common with yourself.", + )); } if !services.users.exists(&body.user_id).await { @@ -60,6 +65,129 @@ pub(crate) async fn get_mutual_rooms_route( }) } +/// # `GET /_matrix/client/unstable/im.nheko.summary/rooms/{roomIdOrAlias}/summary` +/// +/// Returns a short description of the state of a room. +/// +/// This is the "wrong" endpoint that some implementations/clients may use +/// according to the MSC. Request and response bodies are the same as +/// `get_room_summary`. +/// +/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266) +pub(crate) async fn get_room_summary_legacy( + State(services): State, + InsecureClientIp(client): InsecureClientIp, + body: Ruma, +) -> Result> { + get_room_summary(State(services), InsecureClientIp(client), body) + .await + .map(RumaResponse) +} + +/// # `GET /_matrix/client/unstable/im.nheko.summary/summary/{roomIdOrAlias}` +/// +/// Returns a short description of the state of a room. +/// +/// TODO: support fetching remote room info if we don't know the room +/// +/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266) +#[tracing::instrument(skip_all, fields(%client), name = "room_summary")] +pub(crate) async fn get_room_summary( + State(services): State, + InsecureClientIp(client): InsecureClientIp, + body: Ruma, +) -> Result { + let sender_user = body.sender_user.as_ref(); + + let room_id = services.rooms.alias.resolve(&body.room_id_or_alias).await?; + + if !services.rooms.metadata.exists(&room_id).await { + return Err(Error::BadRequest(ErrorKind::NotFound, "Room is unknown to this server")); + } + + if sender_user.is_none() + && !services + .rooms + .state_accessor + .is_world_readable(&room_id) + .await + { + return Err(Error::BadRequest( + ErrorKind::forbidden(), + "Room is not world readable, authentication is required", + )); + } + + Ok(get_summary::msc3266::Response { + room_id: room_id.clone(), + canonical_alias: services + .rooms + .state_accessor + .get_canonical_alias(&room_id) + .await + .ok(), + avatar_url: services + .rooms + .state_accessor + .get_avatar(&room_id) + .await + .into_option() + .unwrap_or_default() + .url, + guest_can_join: services.rooms.state_accessor.guest_can_join(&room_id).await, + name: services.rooms.state_accessor.get_name(&room_id).await.ok(), + num_joined_members: services + .rooms + .state_cache + .room_joined_count(&room_id) + .await + .unwrap_or(0) + .try_into()?, + topic: services + .rooms + .state_accessor + .get_room_topic(&room_id) + .await + .ok(), + world_readable: services + .rooms + .state_accessor + .is_world_readable(&room_id) + .await, + join_rule: services + .rooms + .state_accessor + .get_join_rule(&room_id) + .await + .unwrap_or_default() + .0, + room_type: services + .rooms + .state_accessor + .get_room_type(&room_id) + .await + .ok(), + room_version: services.rooms.state.get_room_version(&room_id).await.ok(), + membership: if let Some(sender_user) = sender_user { + services + .rooms + .state_accessor + .get_member(&room_id, sender_user) + .await + .map_or_else(|_| MembershipState::Leave, |content| content.membership) + .into() + } else { + None + }, + encryption: services + .rooms + .state_accessor + .get_room_encryption(&room_id) + .await + .ok(), + }) +} + /// # `DELETE /_matrix/client/unstable/uk.tcpip.msc4133/profile/:user_id/us.cloke.msc4175.tz` /// /// Deletes the `tz` (timezone) of a user, as per MSC4133 and MSC4175. @@ -77,7 +205,7 @@ pub(crate) async fn delete_timezone_key_route( services.users.set_timezone(&body.user_id, None); - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { // Presence update services .presence @@ -105,7 +233,7 @@ pub(crate) async fn set_timezone_key_route( services.users.set_timezone(&body.user_id, body.tz.clone()); - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { // Presence update services .presence @@ -198,7 +326,7 @@ pub(crate) async fn set_profile_key_route( ); } - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { // Presence update services .presence @@ -257,7 +385,7 @@ pub(crate) async fn delete_profile_key_route( .set_profile_key(&body.user_id, &body.key_name, None); } - if services.config.allow_local_presence { + if services.globals.allow_local_presence() { // Presence update services .presence diff --git a/src/api/client/unversioned.rs b/src/api/client/unversioned.rs index 232d5b28..4e2b7d9d 100644 --- a/src/api/client/unversioned.rs +++ b/src/api/client/unversioned.rs @@ -1,11 +1,10 @@ use std::collections::BTreeMap; use axum::{Json, extract::State, response::IntoResponse}; -use conduwuit::Result; use futures::StreamExt; use ruma::api::client::discovery::get_supported_versions; -use crate::Ruma; +use crate::{Result, Ruma}; /// # `GET /_matrix/client/versions` /// diff --git a/src/api/client/user_directory.rs b/src/api/client/user_directory.rs index 99b3bb67..c5d79a56 100644 --- a/src/api/client/user_directory.rs +++ b/src/api/client/user_directory.rs @@ -1,19 +1,15 @@ use axum::extract::State; -use conduwuit::{ - Result, - utils::{future::BoolExt, stream::BroadbandExt}, -}; -use futures::{FutureExt, StreamExt, pin_mut}; +use conduwuit::utils::TryFutureExtExt; +use futures::{StreamExt, pin_mut}; use ruma::{ - api::client::user_directory::search_users::{self}, - events::room::join_rules::JoinRule, + api::client::user_directory::search_users, + events::{ + StateEventType, + room::join_rules::{JoinRule, RoomJoinRulesEventContent}, + }, }; -use crate::Ruma; - -// conduwuit can handle a lot more results than synapse -const LIMIT_MAX: usize = 500; -const LIMIT_DEFAULT: usize = 10; +use crate::{Result, Ruma}; /// # `POST /_matrix/client/r0/user_directory/search` /// @@ -25,63 +21,78 @@ pub(crate) async fn search_users_route( State(services): State, body: Ruma, ) -> Result { - let sender_user = body.sender_user(); - let limit = usize::try_from(body.limit) - .map_or(LIMIT_DEFAULT, usize::from) - .min(LIMIT_MAX); + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + let limit = usize::try_from(body.limit).map_or(10, usize::from).min(100); // default limit is 10 - let mut users = services - .users - .stream() - .map(ToOwned::to_owned) - .broad_filter_map(async |user_id| { - let user = search_users::v3::User { - user_id: user_id.clone(), - display_name: services.users.displayname(&user_id).await.ok(), - avatar_url: services.users.avatar_url(&user_id).await.ok(), - }; + let users = services.users.stream().filter_map(|user_id| async { + // Filter out buggy users (they should not exist, but you never know...) + let user = search_users::v3::User { + user_id: user_id.to_owned(), + display_name: services.users.displayname(user_id).await.ok(), + avatar_url: services.users.avatar_url(user_id).await.ok(), + }; - let user_id_matches = user - .user_id - .as_str() - .to_lowercase() - .contains(&body.search_term.to_lowercase()); + let user_id_matches = user + .user_id + .to_string() + .to_lowercase() + .contains(&body.search_term.to_lowercase()); - let user_displayname_matches = user.display_name.as_ref().is_some_and(|name| { + let user_displayname_matches = user + .display_name + .as_ref() + .filter(|name| { name.to_lowercase() .contains(&body.search_term.to_lowercase()) - }); + }) + .is_some(); - if !user_id_matches && !user_displayname_matches { - return None; + if !user_id_matches && !user_displayname_matches { + return None; + } + + // It's a matching user, but is the sender allowed to see them? + let mut user_visible = false; + + let user_is_in_public_rooms = services + .rooms + .state_cache + .rooms_joined(&user.user_id) + .any(|room| { + services + .rooms + .state_accessor + .room_state_get_content::( + room, + &StateEventType::RoomJoinRules, + "", + ) + .map_ok_or(false, |content| content.join_rule == JoinRule::Public) + }) + .await; + + if user_is_in_public_rooms { + user_visible = true; + } else { + let user_is_in_shared_rooms = services + .rooms + .state_cache + .user_sees_user(sender_user, &user.user_id) + .await; + + if user_is_in_shared_rooms { + user_visible = true; } + } - let user_in_public_room = services - .rooms - .state_cache - .rooms_joined(&user_id) - .map(ToOwned::to_owned) - .any(|room| async move { - services - .rooms - .state_accessor - .get_join_rules(&room) - .map(|rule| matches!(rule, JoinRule::Public)) - .await - }); + user_visible.then_some(user) + }); - let user_sees_user = services - .rooms - .state_cache - .user_sees_user(sender_user, &user_id); + pin_mut!(users); - pin_mut!(user_in_public_room, user_sees_user); + let limited = users.by_ref().next().await.is_some(); - user_in_public_room.or(user_sees_user).await.then_some(user) - }); - - let results = users.by_ref().take(limit).collect().await; - let limited = users.next().await.is_some(); + let results = users.take(limit).collect().await; Ok(search_users::v3::Response { results, limited }) } diff --git a/src/api/client/voip.rs b/src/api/client/voip.rs index 91991d24..37e67984 100644 --- a/src/api/client/voip.rs +++ b/src/api/client/voip.rs @@ -2,12 +2,12 @@ use std::time::{Duration, SystemTime}; use axum::extract::State; use base64::{Engine as _, engine::general_purpose}; -use conduwuit::{Err, Result, utils}; +use conduwuit::{Err, utils}; use hmac::{Hmac, Mac}; use ruma::{SecondsSinceUnixEpoch, UserId, api::client::voip::get_turn_server_info}; use sha1::Sha1; -use crate::Ruma; +use crate::{Result, Ruma}; const RANDOM_USER_ID_LENGTH: usize = 10; diff --git a/src/api/client/well_known.rs b/src/api/client/well_known.rs index eedab981..abda61b0 100644 --- a/src/api/client/well_known.rs +++ b/src/api/client/well_known.rs @@ -1,5 +1,4 @@ use axum::{Json, extract::State, response::IntoResponse}; -use conduwuit::{Error, Result}; use ruma::api::client::{ discovery::{ discover_homeserver::{self, HomeserverInfo, SlidingSyncProxyInfo}, @@ -8,7 +7,7 @@ use ruma::api::client::{ error::ErrorKind, }; -use crate::Ruma; +use crate::{Error, Result, Ruma}; /// # `GET /.well-known/matrix/client` /// diff --git a/src/api/mod.rs b/src/api/mod.rs index 9ca24e72..8df17a59 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,4 +1,3 @@ -#![type_length_limit = "16384"] //TODO: reduce me #![allow(clippy::toplevel_ref_arg)] pub mod client; @@ -8,6 +7,8 @@ pub mod server; extern crate conduwuit_core as conduwuit; extern crate conduwuit_service as service; +pub(crate) use conduwuit::{Error, Result, debug_info, pdu::PduEvent, utils}; + pub(crate) use self::router::{Ruma, RumaResponse, State}; conduwuit::mod_ctor! {} diff --git a/src/api/router/args.rs b/src/api/router/args.rs index 26713dcc..65a68fa4 100644 --- a/src/api/router/args.rs +++ b/src/api/router/args.rs @@ -1,7 +1,6 @@ use std::{mem, ops::Deref}; -use async_trait::async_trait; -use axum::{body::Body, extract::FromRequest}; +use axum::{async_trait, body::Body, extract::FromRequest}; use bytes::{BufMut, Bytes, BytesMut}; use conduwuit::{Error, Result, debug, debug_warn, err, trace, utils::string::EMPTY}; use ruma::{ diff --git a/src/api/router/auth.rs b/src/api/router/auth.rs index 0eb61ca6..5cd7b831 100644 --- a/src/api/router/auth.rs +++ b/src/api/router/auth.rs @@ -317,9 +317,10 @@ fn auth_server_checks(services: &Services, x_matrix: &XMatrix) -> Result<()> { let origin = &x_matrix.origin; if services + .server .config .forbidden_remote_server_names - .is_match(origin.host()) + .contains(origin) { return Err!(Request(Forbidden(debug_warn!( "Federation requests from {origin} denied." diff --git a/src/api/server/backfill.rs b/src/api/server/backfill.rs index 3cfbcedc..5c875807 100644 --- a/src/api/server/backfill.rs +++ b/src/api/server/backfill.rs @@ -6,17 +6,11 @@ use conduwuit::{ utils::{IterStream, ReadyExt, stream::TryTools}, }; use futures::{FutureExt, StreamExt, TryStreamExt}; -use ruma::{MilliSecondsSinceUnixEpoch, api::federation::backfill::get_backfill}; +use ruma::{MilliSecondsSinceUnixEpoch, api::federation::backfill::get_backfill, uint}; use super::AccessCheck; use crate::Ruma; -/// arbitrary number but synapse's is 100 and we can handle lots of these -/// anyways -const LIMIT_MAX: usize = 150; -/// no spec defined number but we can handle a lot of these -const LIMIT_DEFAULT: usize = 50; - /// # `GET /_matrix/federation/v1/backfill/` /// /// Retrieves events from before the sender joined the room, if the room's @@ -36,9 +30,9 @@ pub(crate) async fn get_backfill_route( let limit = body .limit + .min(uint!(100)) .try_into() - .unwrap_or(LIMIT_DEFAULT) - .min(LIMIT_MAX); + .expect("UInt could not be converted to usize"); let from = body .v diff --git a/src/api/server/get_missing_events.rs b/src/api/server/get_missing_events.rs index 04dc30ed..3d0bbb07 100644 --- a/src/api/server/get_missing_events.rs +++ b/src/api/server/get_missing_events.rs @@ -1,15 +1,13 @@ use axum::extract::State; -use conduwuit::{Result, debug, debug_error, utils::to_canonical_object}; -use ruma::api::federation::event::get_missing_events; +use conduwuit::{Error, Result}; +use ruma::{ + CanonicalJsonValue, EventId, RoomId, + api::{client::error::ErrorKind, federation::event::get_missing_events}, +}; use super::AccessCheck; use crate::Ruma; -/// arbitrary number but synapse's is 20 and we can handle lots of these anyways -const LIMIT_MAX: usize = 50; -/// spec says default is 10 -const LIMIT_DEFAULT: usize = 10; - /// # `POST /_matrix/federation/v1/get_missing_events/{roomId}` /// /// Retrieves events that the sender is missing. @@ -26,11 +24,7 @@ pub(crate) async fn get_missing_events_route( .check() .await?; - let limit = body - .limit - .try_into() - .unwrap_or(LIMIT_DEFAULT) - .min(LIMIT_MAX); + let limit = body.limit.try_into()?; let mut queued_events = body.latest_events.clone(); // the vec will never have more entries the limit @@ -38,52 +32,60 @@ pub(crate) async fn get_missing_events_route( let mut i: usize = 0; while i < queued_events.len() && events.len() < limit { - let Ok(pdu) = services.rooms.timeline.get_pdu(&queued_events[i]).await else { - debug!( - ?body.origin, - "Event {} does not exist locally, skipping", &queued_events[i] - ); - i = i.saturating_add(1); - continue; - }; - - if body.earliest_events.contains(&queued_events[i]) { - i = i.saturating_add(1); - continue; - } - - if !services + if let Ok(pdu) = services .rooms - .state_accessor - .server_can_see_event(body.origin(), &body.room_id, &queued_events[i]) + .timeline + .get_pdu_json(&queued_events[i]) .await { - debug!( - ?body.origin, - "Server cannot see {:?} in {:?}, skipping", pdu.event_id, pdu.room_id + let room_id_str = pdu + .get("room_id") + .and_then(|val| val.as_str()) + .ok_or_else(|| Error::bad_database("Invalid event in database."))?; + + let event_room_id = <&RoomId>::try_from(room_id_str) + .map_err(|_| Error::bad_database("Invalid room_id in event in database."))?; + + if event_room_id != body.room_id { + return Err(Error::BadRequest(ErrorKind::InvalidParam, "Event from wrong room.")); + } + + if body.earliest_events.contains(&queued_events[i]) { + i = i.saturating_add(1); + continue; + } + + if !services + .rooms + .state_accessor + .server_can_see_event(body.origin(), &body.room_id, &queued_events[i]) + .await + { + i = i.saturating_add(1); + continue; + } + + let prev_events = pdu + .get("prev_events") + .and_then(CanonicalJsonValue::as_array) + .unwrap_or_default(); + + queued_events.extend( + prev_events + .iter() + .map(<&EventId>::try_from) + .filter_map(Result::ok) + .map(ToOwned::to_owned), + ); + + events.push( + services + .sending + .convert_to_outgoing_federation_event(pdu) + .await, ); - i = i.saturating_add(1); - continue; } - - let Ok(event) = to_canonical_object(&pdu) else { - debug_error!( - ?body.origin, - "Failed to convert PDU in database to canonical JSON: {pdu:?}" - ); - i = i.saturating_add(1); - continue; - }; - - let prev_events = pdu.prev_events.iter().map(ToOwned::to_owned); - - let event = services - .sending - .convert_to_outgoing_federation_event(event) - .await; - - queued_events.extend(prev_events); - events.push(event); + i = i.saturating_add(1); } Ok(get_missing_events::v1::Response { events }) diff --git a/src/api/server/hierarchy.rs b/src/api/server/hierarchy.rs index 42c348f9..c759c8ea 100644 --- a/src/api/server/hierarchy.rs +++ b/src/api/server/hierarchy.rs @@ -3,11 +3,9 @@ use conduwuit::{ Err, Result, utils::stream::{BroadbandExt, IterStream}, }; -use conduwuit_service::rooms::spaces::{ - Identifier, SummaryAccessibility, get_parent_children_via, -}; use futures::{FutureExt, StreamExt}; use ruma::api::federation::space::get_hierarchy; +use service::rooms::spaces::{Identifier, SummaryAccessibility, get_parent_children_via}; use crate::Ruma; diff --git a/src/api/server/invite.rs b/src/api/server/invite.rs index edd6ac16..463cb9ab 100644 --- a/src/api/server/invite.rs +++ b/src/api/server/invite.rs @@ -1,15 +1,14 @@ use axum::extract::State; use axum_client_ip::InsecureClientIp; use base64::{Engine as _, engine::general_purpose}; -use conduwuit::{ - Err, Error, PduEvent, Result, err, pdu::gen_event_id, utils, utils::hash::sha256, warn, -}; +use conduwuit::{Err, Error, PduEvent, Result, err, utils, utils::hash::sha256, warn}; use ruma::{ CanonicalJsonValue, OwnedUserId, UserId, api::{client::error::ErrorKind, federation::membership::create_invite}, events::room::member::{MembershipState, RoomMemberEventContent}, serde::JsonObject, }; +use service::pdu::gen_event_id; use crate::Ruma; @@ -38,18 +37,20 @@ pub(crate) async fn create_invite_route( if let Some(server) = body.room_id.server_name() { if services + .server .config .forbidden_remote_server_names - .is_match(server.host()) + .contains(&server.to_owned()) { return Err!(Request(Forbidden("Server is banned on this homeserver."))); } } if services + .server .config .forbidden_remote_server_names - .is_match(body.origin().host()) + .contains(body.origin()) { warn!( "Received federated/remote invite from banned server {} for room ID {}. Rejecting.", @@ -102,7 +103,8 @@ pub(crate) async fn create_invite_route( return Err!(Request(Forbidden("This room is banned on this homeserver."))); } - if services.config.block_non_admin_invites && !services.users.is_admin(&invited_user).await { + if services.globals.block_non_admin_invites() && !services.users.is_admin(&invited_user).await + { return Err!(Request(Forbidden("This server does not allow room invites."))); } diff --git a/src/api/server/make_join.rs b/src/api/server/make_join.rs index ac2c5485..f18d1304 100644 --- a/src/api/server/make_join.rs +++ b/src/api/server/make_join.rs @@ -1,8 +1,5 @@ use axum::extract::State; -use conduwuit::{ - Err, Error, Result, debug_info, matrix::pdu::PduBuilder, utils::IterStream, warn, -}; -use conduwuit_service::Services; +use conduwuit::{Err, debug_info, utils::IterStream, warn}; use futures::StreamExt; use ruma::{ CanonicalJsonObject, OwnedUserId, RoomId, RoomVersionId, UserId, @@ -17,7 +14,10 @@ use ruma::{ }; use serde_json::value::to_raw_value; -use crate::Ruma; +use crate::{ + Error, Result, Ruma, + service::{Services, pdu::PduBuilder}, +}; /// # `GET /_matrix/federation/v1/make_join/{roomId}/{userId}` /// @@ -42,9 +42,10 @@ pub(crate) async fn create_join_event_template_route( .await?; if services + .server .config .forbidden_remote_server_names - .is_match(body.origin().host()) + .contains(body.origin()) { warn!( "Server {} for remote user {} tried joining room ID {} which has a server name that \ @@ -58,9 +59,10 @@ pub(crate) async fn create_join_event_template_route( if let Some(server) = body.room_id.server_name() { if services + .server .config .forbidden_remote_server_names - .is_match(server.host()) + .contains(&server.to_owned()) { return Err!(Request(Forbidden(warn!( "Room ID server name {server} is banned on this homeserver." diff --git a/src/api/server/make_knock.rs b/src/api/server/make_knock.rs index 511c13b2..71536439 100644 --- a/src/api/server/make_knock.rs +++ b/src/api/server/make_knock.rs @@ -1,14 +1,15 @@ use RoomVersionId::*; use axum::extract::State; -use conduwuit::{Err, Error, Result, debug_warn, matrix::pdu::PduBuilder, warn}; +use conduwuit::{Err, debug_warn}; use ruma::{ RoomVersionId, api::{client::error::ErrorKind, federation::knock::create_knock_event_template}, events::room::member::{MembershipState, RoomMemberEventContent}, }; use serde_json::value::to_raw_value; +use tracing::warn; -use crate::Ruma; +use crate::{Error, Result, Ruma, service::pdu::PduBuilder}; /// # `GET /_matrix/federation/v1/make_knock/{roomId}/{userId}` /// @@ -33,9 +34,10 @@ pub(crate) async fn create_knock_event_template_route( .await?; if services + .server .config .forbidden_remote_server_names - .is_match(body.origin().host()) + .contains(body.origin()) { warn!( "Server {} for remote user {} tried knocking room ID {} which has a server name \ @@ -49,9 +51,10 @@ pub(crate) async fn create_knock_event_template_route( if let Some(server) = body.room_id.server_name() { if services + .server .config .forbidden_remote_server_names - .is_match(server.host()) + .contains(&server.to_owned()) { return Err!(Request(Forbidden("Server is banned on this homeserver."))); } diff --git a/src/api/server/make_leave.rs b/src/api/server/make_leave.rs index cb6bd2fa..1ed02785 100644 --- a/src/api/server/make_leave.rs +++ b/src/api/server/make_leave.rs @@ -1,5 +1,5 @@ use axum::extract::State; -use conduwuit::{Err, Result, matrix::pdu::PduBuilder}; +use conduwuit::{Err, Result}; use ruma::{ api::federation::membership::prepare_leave_event, events::room::member::{MembershipState, RoomMemberEventContent}, @@ -7,7 +7,7 @@ use ruma::{ use serde_json::value::to_raw_value; use super::make_join::maybe_strip_event_id; -use crate::Ruma; +use crate::{Ruma, service::pdu::PduBuilder}; /// # `GET /_matrix/federation/v1/make_leave/{roomId}/{eventId}` /// diff --git a/src/api/server/openid.rs b/src/api/server/openid.rs index a09cd7ad..4833fbe1 100644 --- a/src/api/server/openid.rs +++ b/src/api/server/openid.rs @@ -1,8 +1,7 @@ use axum::extract::State; -use conduwuit::Result; use ruma::api::federation::openid::get_openid_userinfo; -use crate::Ruma; +use crate::{Result, Ruma}; /// # `GET /_matrix/federation/v1/openid/userinfo` /// diff --git a/src/api/server/publicrooms.rs b/src/api/server/publicrooms.rs index cf66ea71..ff74574a 100644 --- a/src/api/server/publicrooms.rs +++ b/src/api/server/publicrooms.rs @@ -1,6 +1,5 @@ use axum::extract::State; use axum_client_ip::InsecureClientIp; -use conduwuit::{Error, Result}; use ruma::{ api::{ client::error::ErrorKind, @@ -9,7 +8,7 @@ use ruma::{ directory::Filter, }; -use crate::Ruma; +use crate::{Error, Result, Ruma}; /// # `POST /_matrix/federation/v1/publicRooms` /// diff --git a/src/api/server/send.rs b/src/api/server/send.rs index 9c5bfd2b..1f467dac 100644 --- a/src/api/server/send.rs +++ b/src/api/server/send.rs @@ -9,15 +9,11 @@ use conduwuit::{ result::LogErr, trace, utils::{ - IterStream, ReadyExt, millis_since_unix_epoch, + IterStream, ReadyExt, stream::{BroadbandExt, TryBroadbandExt, automatic_width}, }, warn, }; -use conduwuit_service::{ - Services, - sending::{EDU_LIMIT, PDU_LIMIT}, -}; use futures::{FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt}; use itertools::Itertools; use ruma::{ @@ -37,8 +33,16 @@ use ruma::{ serde::Raw, to_device::DeviceIdOrAllDevices, }; +use service::{ + Services, + sending::{EDU_LIMIT, PDU_LIMIT}, +}; +use utils::millis_since_unix_epoch; -use crate::Ruma; +use crate::{ + Ruma, + utils::{self}, +}; type ResolvedMap = BTreeMap; type Pdu = (OwnedRoomId, OwnedEventId, CanonicalJsonObject); diff --git a/src/api/server/send_join.rs b/src/api/server/send_join.rs index a66d8890..c1749835 100644 --- a/src/api/server/send_join.rs +++ b/src/api/server/send_join.rs @@ -9,7 +9,6 @@ use conduwuit::{ utils::stream::{IterStream, TryBroadbandExt}, warn, }; -use conduwuit_service::Services; use futures::{FutureExt, StreamExt, TryStreamExt}; use ruma::{ CanonicalJsonValue, OwnedEventId, OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, @@ -21,6 +20,7 @@ use ruma::{ }, }; use serde_json::value::{RawValue as RawJsonValue, to_raw_value}; +use service::Services; use crate::Ruma; @@ -268,9 +268,10 @@ pub(crate) async fn create_join_event_v1_route( body: Ruma, ) -> Result { if services + .server .config .forbidden_remote_server_names - .is_match(body.origin().host()) + .contains(body.origin()) { warn!( "Server {} tried joining room ID {} through us who has a server name that is \ @@ -283,9 +284,10 @@ pub(crate) async fn create_join_event_v1_route( if let Some(server) = body.room_id.server_name() { if services + .server .config .forbidden_remote_server_names - .is_match(server.host()) + .contains(&server.to_owned()) { warn!( "Server {} tried joining room ID {} through us which has a server name that is \ @@ -314,18 +316,20 @@ pub(crate) async fn create_join_event_v2_route( body: Ruma, ) -> Result { if services + .server .config .forbidden_remote_server_names - .is_match(body.origin().host()) + .contains(body.origin()) { return Err!(Request(Forbidden("Server is banned on this homeserver."))); } if let Some(server) = body.room_id.server_name() { if services + .server .config .forbidden_remote_server_names - .is_match(server.host()) + .contains(&server.to_owned()) { warn!( "Server {} tried joining room ID {} through us which has a server name that is \ diff --git a/src/api/server/send_knock.rs b/src/api/server/send_knock.rs index ee7b6cba..f7bb0735 100644 --- a/src/api/server/send_knock.rs +++ b/src/api/server/send_knock.rs @@ -1,9 +1,5 @@ use axum::extract::State; -use conduwuit::{ - Err, Result, err, - matrix::pdu::{PduEvent, gen_event_id_canonical_json}, - warn, -}; +use conduwuit::{Err, PduEvent, Result, err, pdu::gen_event_id_canonical_json, warn}; use futures::FutureExt; use ruma::{ OwnedServerName, OwnedUserId, @@ -26,9 +22,10 @@ pub(crate) async fn create_knock_event_v1_route( body: Ruma, ) -> Result { if services + .server .config .forbidden_remote_server_names - .is_match(body.origin().host()) + .contains(body.origin()) { warn!( "Server {} tried knocking room ID {} who has a server name that is globally \ @@ -41,9 +38,10 @@ pub(crate) async fn create_knock_event_v1_route( if let Some(server) = body.room_id.server_name() { if services + .server .config .forbidden_remote_server_names - .is_match(server.host()) + .contains(&server.to_owned()) { warn!( "Server {} tried knocking room ID {} which has a server name that is globally \ diff --git a/src/api/server/send_leave.rs b/src/api/server/send_leave.rs index d3dc994c..71516553 100644 --- a/src/api/server/send_leave.rs +++ b/src/api/server/send_leave.rs @@ -1,8 +1,7 @@ #![allow(deprecated)] use axum::extract::State; -use conduwuit::{Err, Result, err, matrix::pdu::gen_event_id_canonical_json}; -use conduwuit_service::Services; +use conduwuit::{Err, Result, err}; use futures::FutureExt; use ruma::{ OwnedRoomId, OwnedUserId, RoomId, ServerName, @@ -14,7 +13,10 @@ use ruma::{ }; use serde_json::value::RawValue as RawJsonValue; -use crate::Ruma; +use crate::{ + Ruma, + service::{Services, pdu::gen_event_id_canonical_json}, +}; /// # `PUT /_matrix/federation/v1/send_leave/{roomId}/{eventId}` /// diff --git a/src/api/server/version.rs b/src/api/server/version.rs index b08ff77a..036b61f7 100644 --- a/src/api/server/version.rs +++ b/src/api/server/version.rs @@ -1,7 +1,6 @@ -use conduwuit::Result; use ruma::api::federation::discovery::get_server_version; -use crate::Ruma; +use crate::{Result, Ruma}; /// # `GET /_matrix/federation/v1/version` /// diff --git a/src/api/server/well_known.rs b/src/api/server/well_known.rs index 75c7cf5d..48caa7d6 100644 --- a/src/api/server/well_known.rs +++ b/src/api/server/well_known.rs @@ -1,8 +1,7 @@ use axum::extract::State; -use conduwuit::{Error, Result}; use ruma::api::{client::error::ErrorKind, federation::discovery::discover_homeserver}; -use crate::Ruma; +use crate::{Error, Result, Ruma}; /// # `GET /.well-known/matrix/server` /// diff --git a/src/core/Cargo.toml b/src/core/Cargo.toml index 4848e742..b40dd3ad 100644 --- a/src/core/Cargo.toml +++ b/src/core/Cargo.toml @@ -59,7 +59,6 @@ conduwuit_mods = [ argon2.workspace = true arrayvec.workspace = true axum.workspace = true -axum-extra.workspace = true bytes.workspace = true bytesize.workspace = true cargo_toml.workspace = true diff --git a/src/core/alloc/je.rs b/src/core/alloc/je.rs index 2424e99c..6870c1c0 100644 --- a/src/core/alloc/je.rs +++ b/src/core/alloc/je.rs @@ -8,6 +8,7 @@ use std::{ }; use arrayvec::ArrayVec; +use const_str::concat_bytes; use tikv_jemalloc_ctl as mallctl; use tikv_jemalloc_sys as ffi; use tikv_jemallocator as jemalloc; @@ -19,7 +20,7 @@ use crate::{ #[cfg(feature = "jemalloc_conf")] #[unsafe(no_mangle)] -pub static malloc_conf: &[u8] = const_str::concat_bytes!( +pub static malloc_conf: &[u8] = concat_bytes!( "lg_extent_max_active_fit:4", ",oversize_threshold:16777216", ",tcache_max:2097152", @@ -335,12 +336,6 @@ where Ok(res) } -#[tracing::instrument( - name = "get", - level = "trace" - skip_all, - fields(?key) -)] fn get(key: &Key) -> Result where T: Copy + Debug, @@ -352,12 +347,6 @@ where unsafe { mallctl::raw::read_mib(key.as_slice()) }.map_err(map_err) } -#[tracing::instrument( - name = "xchg", - level = "trace" - skip_all, - fields(?key, ?val) -)] fn xchg(key: &Key, val: T) -> Result where T: Copy + Debug, diff --git a/src/core/config/mod.rs b/src/core/config/mod.rs index 0ca6bbaf..6b669ad3 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -3,7 +3,7 @@ pub mod manager; pub mod proxy; use std::{ - collections::{BTreeMap, BTreeSet}, + collections::{BTreeMap, BTreeSet, HashSet}, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, path::{Path, PathBuf}, }; @@ -252,6 +252,14 @@ pub struct Config { #[serde(default = "default_servernameevent_data_cache_capacity")] pub servernameevent_data_cache_capacity: u32, + /// default: varies by system + #[serde(default = "default_server_visibility_cache_capacity")] + pub server_visibility_cache_capacity: u32, + + /// default: varies by system + #[serde(default = "default_user_visibility_cache_capacity")] + pub user_visibility_cache_capacity: u32, + /// default: varies by system #[serde(default = "default_stateinfo_cache_capacity")] pub stateinfo_cache_capacity: u32, @@ -640,9 +648,9 @@ pub struct Config { /// Default room version conduwuit will create rooms with. /// - /// Per spec, room version 11 is the default. + /// Per spec, room version 10 is the default. /// - /// default: 11 + /// default: 10 #[serde(default = "default_default_room_version")] pub default_room_version: RoomVersionId, @@ -715,7 +723,7 @@ pub struct Config { /// Currently, conduwuit doesn't support inbound batched key requests, so /// this list should only contain other Synapse servers. /// - /// example: ["matrix.org", "tchncs.de"] + /// example: ["matrix.org", "envs.net", "tchncs.de"] /// /// default: ["matrix.org"] #[serde(default = "default_trusted_servers")] @@ -1361,18 +1369,15 @@ pub struct Config { #[serde(default)] pub prune_missing_media: bool, - /// Vector list of regex patterns of server names that conduwuit will refuse - /// to download remote media from. - /// - /// example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"] + /// Vector list of servers that conduwuit will refuse to download remote + /// media from. /// /// default: [] - #[serde(default, with = "serde_regex")] - pub prevent_media_downloads_from: RegexSet, + #[serde(default)] + pub prevent_media_downloads_from: HashSet, - /// List of forbidden server names via regex patterns that we will block - /// incoming AND outgoing federation with, and block client room joins / - /// remote user invites. + /// List of forbidden server names that we will block incoming AND outgoing + /// federation with, and block client room joins / remote user invites. /// /// This check is applied on the room ID, room alias, sender server name, /// sender user's server name, inbound federation X-Matrix origin, and @@ -1380,21 +1385,17 @@ pub struct Config { /// /// Basically "global" ACLs. /// - /// example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"] - /// /// default: [] - #[serde(default, with = "serde_regex")] - pub forbidden_remote_server_names: RegexSet, + #[serde(default)] + pub forbidden_remote_server_names: HashSet, - /// List of forbidden server names via regex patterns that we will block all - /// outgoing federated room directory requests for. Useful for preventing - /// our users from wandering into bad servers or spaces. - /// - /// example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"] + /// List of forbidden server names that we will block all outgoing federated + /// room directory requests for. Useful for preventing our users from + /// wandering into bad servers or spaces. /// /// default: [] - #[serde(default, with = "serde_regex")] - pub forbidden_remote_room_directory_server_names: RegexSet, + #[serde(default = "HashSet::new")] + pub forbidden_remote_room_directory_server_names: HashSet, /// Vector list of IPv4 and IPv6 CIDR ranges / subnets *in quotes* that you /// do not want conduwuit to send outbound requests to. Defaults to @@ -1515,10 +1516,11 @@ pub struct Config { /// used, and startup as warnings if any room aliases in your database have /// a forbidden room alias/ID. /// - /// example: ["19dollarfortnitecards", "b[4a]droom", "badphrase"] + /// example: ["19dollarfortnitecards", "b[4a]droom"] /// /// default: [] - #[serde(default, with = "serde_regex")] + #[serde(default)] + #[serde(with = "serde_regex")] pub forbidden_alias_names: RegexSet, /// List of forbidden username patterns/strings. @@ -1530,10 +1532,11 @@ pub struct Config { /// startup as warnings if any local users in your database have a forbidden /// username. /// - /// example: ["administrator", "b[a4]dusernam[3e]", "badphrase"] + /// example: ["administrator", "b[a4]dusernam[3e]"] /// /// default: [] - #[serde(default, with = "serde_regex")] + #[serde(default)] + #[serde(with = "serde_regex")] pub forbidden_usernames: RegexSet, /// Retry failed and incomplete messages to remote servers immediately upon @@ -2032,6 +2035,10 @@ fn default_servernameevent_data_cache_capacity() -> u32 { parallelism_scaled_u32(100_000).saturating_add(500_000) } +fn default_server_visibility_cache_capacity() -> u32 { parallelism_scaled_u32(500) } + +fn default_user_visibility_cache_capacity() -> u32 { parallelism_scaled_u32(1000) } + fn default_stateinfo_cache_capacity() -> u32 { parallelism_scaled_u32(100) } fn default_roomid_spacehierarchy_cache_capacity() -> u32 { parallelism_scaled_u32(1000) } @@ -2151,12 +2158,7 @@ fn default_rocksdb_max_log_file_size() -> usize { fn default_rocksdb_parallelism_threads() -> usize { 0 } -fn default_rocksdb_compression_algo() -> String { - cfg!(feature = "zstd_compression") - .then_some("zstd") - .unwrap_or("none") - .to_owned() -} +fn default_rocksdb_compression_algo() -> String { "zstd".to_owned() } /// Default RocksDB compression level is 32767, which is internally read by /// RocksDB as the default magic number and translated to the library's default @@ -2175,7 +2177,7 @@ fn default_rocksdb_stats_level() -> u8 { 1 } // I know, it's a great name #[must_use] #[inline] -pub fn default_default_room_version() -> RoomVersionId { RoomVersionId::V11 } +pub fn default_default_room_version() -> RoomVersionId { RoomVersionId::V10 } fn default_ip_range_denylist() -> Vec { vec![ diff --git a/src/core/error/err.rs b/src/core/error/err.rs index 9c24d3b4..0962c4ee 100644 --- a/src/core/error/err.rs +++ b/src/core/error/err.rs @@ -136,7 +136,6 @@ macro_rules! err_log { } #[macro_export] -#[collapse_debuginfo(yes)] macro_rules! err_lev { (debug_warn) => { if $crate::debug::logging() { diff --git a/src/core/error/mod.rs b/src/core/error/mod.rs index e46edf09..02ab6fa3 100644 --- a/src/core/error/mod.rs +++ b/src/core/error/mod.rs @@ -81,8 +81,6 @@ pub enum Error { #[error("Tracing reload error: {0}")] TracingReload(#[from] tracing_subscriber::reload::Error), #[error(transparent)] - TypedHeader(#[from] axum_extra::typed_header::TypedHeaderRejection), - #[error(transparent)] Yaml(#[from] serde_yaml::Error), // ruma/conduwuit diff --git a/src/core/error/response.rs b/src/core/error/response.rs index ae6fce62..00ade5ae 100644 --- a/src/core/error/response.rs +++ b/src/core/error/response.rs @@ -86,7 +86,7 @@ pub(super) fn bad_request_code(kind: &ErrorKind) -> StatusCode { pub(super) fn ruma_error_message(error: &ruma::api::client::error::Error) -> String { if let ErrorBody::Standard { message, .. } = &error.body { - return message.clone(); + return message.to_string(); } format!("{error}") diff --git a/src/core/matrix/mod.rs b/src/core/matrix/mod.rs deleted file mode 100644 index 8c978173..00000000 --- a/src/core/matrix/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Core Matrix Library - -pub mod event; -pub mod pdu; -pub mod state_res; - -pub use event::Event; -pub use pdu::{PduBuilder, PduCount, PduEvent, PduId, RawPduId, StateKey}; -pub use state_res::{EventTypeExt, RoomVersion, StateMap, TypeStateKey}; diff --git a/src/core/matrix/state_res/benches.rs b/src/core/matrix/state_res/benches.rs deleted file mode 100644 index 7a1ae5bf..00000000 --- a/src/core/matrix/state_res/benches.rs +++ /dev/null @@ -1,672 +0,0 @@ -#[cfg(conduwuit_bench)] -extern crate test; - -use std::{ - borrow::Borrow, - collections::{HashMap, HashSet}, - sync::{ - Arc, - atomic::{AtomicU64, Ordering::SeqCst}, - }, -}; - -use futures::{future, future::ready}; -use maplit::{btreemap, hashmap, hashset}; -use ruma::{ - EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, Signatures, UserId, - events::{ - StateEventType, TimelineEventType, - pdu::{EventHash, Pdu, RoomV3Pdu}, - room::{ - join_rules::{JoinRule, RoomJoinRulesEventContent}, - member::{MembershipState, RoomMemberEventContent}, - }, - }, - int, room_id, uint, user_id, -}; -use serde_json::{ - json, - value::{RawValue as RawJsonValue, to_raw_value as to_raw_json_value}, -}; - -use self::event::PduEvent; -use crate::state_res::{self as state_res, Error, Event, Result, StateMap}; - -static SERVER_TIMESTAMP: AtomicU64 = AtomicU64::new(0); - -#[cfg(conduwuit_bench)] -#[cfg_attr(conduwuit_bench, bench)] -fn lexico_topo_sort(c: &mut test::Bencher) { - let graph = hashmap! { - event_id("l") => hashset![event_id("o")], - event_id("m") => hashset![event_id("n"), event_id("o")], - event_id("n") => hashset![event_id("o")], - event_id("o") => hashset![], // "o" has zero outgoing edges but 4 incoming edges - event_id("p") => hashset![event_id("o")], - }; - - c.iter(|| { - let _ = state_res::lexicographical_topological_sort(&graph, &|_| { - future::ok((int!(0), MilliSecondsSinceUnixEpoch(uint!(0)))) - }); - }); -} - -#[cfg(conduwuit_bench)] -#[cfg_attr(conduwuit_bench, bench)] -fn resolution_shallow_auth_chain(c: &mut test::Bencher) { - let parallel_fetches = 32; - let mut store = TestStore(hashmap! {}); - - // build up the DAG - let (state_at_bob, state_at_charlie, _) = store.set_up(); - - c.iter(|| async { - let ev_map = store.0.clone(); - let state_sets = [&state_at_bob, &state_at_charlie]; - let fetch = |id: OwnedEventId| ready(ev_map.get(&id).map(Arc::clone)); - let exists = |id: OwnedEventId| ready(ev_map.get(&id).is_some()); - let auth_chain_sets: Vec> = state_sets - .iter() - .map(|map| { - store - .auth_event_ids(room_id(), map.values().cloned().collect()) - .unwrap() - }) - .collect(); - - let _ = match state_res::resolve( - &RoomVersionId::V6, - state_sets.into_iter(), - &auth_chain_sets, - &fetch, - &exists, - parallel_fetches, - ) - .await - { - | Ok(state) => state, - | Err(e) => panic!("{e}"), - }; - }); -} - -#[cfg(conduwuit_bench)] -#[cfg_attr(conduwuit_bench, bench)] -fn resolve_deeper_event_set(c: &mut test::Bencher) { - let parallel_fetches = 32; - let mut inner = INITIAL_EVENTS(); - let ban = BAN_STATE_SET(); - - inner.extend(ban); - let store = TestStore(inner.clone()); - - let state_set_a = [ - inner.get(&event_id("CREATE")).unwrap(), - inner.get(&event_id("IJR")).unwrap(), - inner.get(&event_id("IMA")).unwrap(), - inner.get(&event_id("IMB")).unwrap(), - inner.get(&event_id("IMC")).unwrap(), - inner.get(&event_id("MB")).unwrap(), - inner.get(&event_id("PA")).unwrap(), - ] - .iter() - .map(|ev| { - ( - (ev.event_type().clone().into(), ev.state_key().unwrap().into()), - ev.event_id().to_owned(), - ) - }) - .collect::>(); - - let state_set_b = [ - inner.get(&event_id("CREATE")).unwrap(), - inner.get(&event_id("IJR")).unwrap(), - inner.get(&event_id("IMA")).unwrap(), - inner.get(&event_id("IMB")).unwrap(), - inner.get(&event_id("IMC")).unwrap(), - inner.get(&event_id("IME")).unwrap(), - inner.get(&event_id("PA")).unwrap(), - ] - .iter() - .map(|ev| { - ( - (ev.event_type().clone().into(), ev.state_key().unwrap().into()), - ev.event_id().to_owned(), - ) - }) - .collect::>(); - - c.iter(|| async { - let state_sets = [&state_set_a, &state_set_b]; - let auth_chain_sets: Vec> = state_sets - .iter() - .map(|map| { - store - .auth_event_ids(room_id(), map.values().cloned().collect()) - .unwrap() - }) - .collect(); - - let fetch = |id: OwnedEventId| ready(inner.get(&id).map(Arc::clone)); - let exists = |id: OwnedEventId| ready(inner.get(&id).is_some()); - let _ = match state_res::resolve( - &RoomVersionId::V6, - state_sets.into_iter(), - &auth_chain_sets, - &fetch, - &exists, - parallel_fetches, - ) - .await - { - | Ok(state) => state, - | Err(_) => panic!("resolution failed during benchmarking"), - }; - }); -} - -//*///////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION DETAILS AHEAD -// -/////////////////////////////////////////////////////////////////////*/ -struct TestStore(HashMap>); - -#[allow(unused)] -impl TestStore { - fn get_event(&self, room_id: &RoomId, event_id: &EventId) -> Result> { - self.0 - .get(event_id) - .map(Arc::clone) - .ok_or_else(|| Error::NotFound(format!("{} not found", event_id))) - } - - /// Returns the events that correspond to the `event_ids` sorted in the same - /// order. - fn get_events(&self, room_id: &RoomId, event_ids: &[OwnedEventId]) -> Result>> { - let mut events = vec![]; - for id in event_ids { - events.push(self.get_event(room_id, id)?); - } - Ok(events) - } - - /// Returns a Vec of the related auth events to the given `event`. - fn auth_event_ids(&self, room_id: &RoomId, event_ids: Vec) -> Result> { - let mut result = HashSet::new(); - let mut stack = event_ids; - - // DFS for auth event chain - while !stack.is_empty() { - let ev_id = stack.pop().unwrap(); - if result.contains(&ev_id) { - continue; - } - - result.insert(ev_id.clone()); - - let event = self.get_event(room_id, ev_id.borrow())?; - - stack.extend(event.auth_events().map(ToOwned::to_owned)); - } - - Ok(result) - } - - /// Returns a vector representing the difference in auth chains of the given - /// `events`. - fn auth_chain_diff( - &self, - room_id: &RoomId, - event_ids: Vec>, - ) -> Result> { - let mut auth_chain_sets = vec![]; - for ids in event_ids { - // TODO state store `auth_event_ids` returns self in the event ids list - // when an event returns `auth_event_ids` self is not contained - let chain = self - .auth_event_ids(room_id, ids)? - .into_iter() - .collect::>(); - auth_chain_sets.push(chain); - } - - if let Some(first) = auth_chain_sets.first().cloned() { - let common = auth_chain_sets - .iter() - .skip(1) - .fold(first, |a, b| a.intersection(b).cloned().collect::>()); - - Ok(auth_chain_sets - .into_iter() - .flatten() - .filter(|id| !common.contains(id.borrow())) - .collect()) - } else { - Ok(vec![]) - } - } -} - -impl TestStore { - #[allow(clippy::type_complexity)] - fn set_up( - &mut self, - ) -> (StateMap, StateMap, StateMap) { - let create_event = to_pdu_event::<&EventId>( - "CREATE", - alice(), - TimelineEventType::RoomCreate, - Some(""), - to_raw_json_value(&json!({ "creator": alice() })).unwrap(), - &[], - &[], - ); - let cre = create_event.event_id().to_owned(); - self.0.insert(cre.clone(), Arc::clone(&create_event)); - - let alice_mem = to_pdu_event( - "IMA", - alice(), - TimelineEventType::RoomMember, - Some(alice().to_string().as_str()), - member_content_join(), - &[cre.clone()], - &[cre.clone()], - ); - self.0 - .insert(alice_mem.event_id().to_owned(), Arc::clone(&alice_mem)); - - let join_rules = to_pdu_event( - "IJR", - alice(), - TimelineEventType::RoomJoinRules, - Some(""), - to_raw_json_value(&RoomJoinRulesEventContent::new(JoinRule::Public)).unwrap(), - &[cre.clone(), alice_mem.event_id().to_owned()], - &[alice_mem.event_id().to_owned()], - ); - self.0 - .insert(join_rules.event_id().to_owned(), join_rules.clone()); - - // Bob and Charlie join at the same time, so there is a fork - // this will be represented in the state_sets when we resolve - let bob_mem = to_pdu_event( - "IMB", - bob(), - TimelineEventType::RoomMember, - Some(bob().to_string().as_str()), - member_content_join(), - &[cre.clone(), join_rules.event_id().to_owned()], - &[join_rules.event_id().to_owned()], - ); - self.0 - .insert(bob_mem.event_id().to_owned(), bob_mem.clone()); - - let charlie_mem = to_pdu_event( - "IMC", - charlie(), - TimelineEventType::RoomMember, - Some(charlie().to_string().as_str()), - member_content_join(), - &[cre, join_rules.event_id().to_owned()], - &[join_rules.event_id().to_owned()], - ); - self.0 - .insert(charlie_mem.event_id().to_owned(), charlie_mem.clone()); - - let state_at_bob = [&create_event, &alice_mem, &join_rules, &bob_mem] - .iter() - .map(|ev| { - ( - (ev.event_type().clone().into(), ev.state_key().unwrap().into()), - ev.event_id().to_owned(), - ) - }) - .collect::>(); - - let state_at_charlie = [&create_event, &alice_mem, &join_rules, &charlie_mem] - .iter() - .map(|ev| { - ( - (ev.event_type().clone().into(), ev.state_key().unwrap().into()), - ev.event_id().to_owned(), - ) - }) - .collect::>(); - - let expected = [&create_event, &alice_mem, &join_rules, &bob_mem, &charlie_mem] - .iter() - .map(|ev| { - ( - (ev.event_type().clone().into(), ev.state_key().unwrap().into()), - ev.event_id().to_owned(), - ) - }) - .collect::>(); - - (state_at_bob, state_at_charlie, expected) - } -} - -fn event_id(id: &str) -> OwnedEventId { - if id.contains('$') { - return id.try_into().unwrap(); - } - format!("${}:foo", id).try_into().unwrap() -} - -fn alice() -> &'static UserId { user_id!("@alice:foo") } - -fn bob() -> &'static UserId { user_id!("@bob:foo") } - -fn charlie() -> &'static UserId { user_id!("@charlie:foo") } - -fn ella() -> &'static UserId { user_id!("@ella:foo") } - -fn room_id() -> &'static RoomId { room_id!("!test:foo") } - -fn member_content_ban() -> Box { - to_raw_json_value(&RoomMemberEventContent::new(MembershipState::Ban)).unwrap() -} - -fn member_content_join() -> Box { - to_raw_json_value(&RoomMemberEventContent::new(MembershipState::Join)).unwrap() -} - -fn to_pdu_event( - id: &str, - sender: &UserId, - ev_type: TimelineEventType, - state_key: Option<&str>, - content: Box, - auth_events: &[S], - prev_events: &[S], -) -> Arc -where - S: AsRef, -{ - // We don't care if the addition happens in order just that it is atomic - // (each event has its own value) - let ts = SERVER_TIMESTAMP.fetch_add(1, SeqCst); - let id = if id.contains('$') { - id.to_owned() - } else { - format!("${}:foo", id) - }; - let auth_events = auth_events - .iter() - .map(AsRef::as_ref) - .map(event_id) - .collect::>(); - let prev_events = prev_events - .iter() - .map(AsRef::as_ref) - .map(event_id) - .collect::>(); - - let state_key = state_key.map(ToOwned::to_owned); - Arc::new(PduEvent { - event_id: id.try_into().unwrap(), - rest: Pdu::RoomV3Pdu(RoomV3Pdu { - room_id: room_id().to_owned(), - sender: sender.to_owned(), - origin_server_ts: MilliSecondsSinceUnixEpoch(ts.try_into().unwrap()), - state_key, - kind: ev_type, - content, - redacts: None, - unsigned: btreemap! {}, - auth_events, - prev_events, - depth: uint!(0), - hashes: EventHash::new(String::new()), - signatures: Signatures::new(), - }), - }) -} - -// all graphs start with these input events -#[allow(non_snake_case)] -fn INITIAL_EVENTS() -> HashMap> { - vec![ - to_pdu_event::<&EventId>( - "CREATE", - alice(), - TimelineEventType::RoomCreate, - Some(""), - to_raw_json_value(&json!({ "creator": alice() })).unwrap(), - &[], - &[], - ), - to_pdu_event( - "IMA", - alice(), - TimelineEventType::RoomMember, - Some(alice().as_str()), - member_content_join(), - &["CREATE"], - &["CREATE"], - ), - to_pdu_event( - "IPOWER", - alice(), - TimelineEventType::RoomPowerLevels, - Some(""), - to_raw_json_value(&json!({ "users": { alice(): 100 } })).unwrap(), - &["CREATE", "IMA"], - &["IMA"], - ), - to_pdu_event( - "IJR", - alice(), - TimelineEventType::RoomJoinRules, - Some(""), - to_raw_json_value(&RoomJoinRulesEventContent::new(JoinRule::Public)).unwrap(), - &["CREATE", "IMA", "IPOWER"], - &["IPOWER"], - ), - to_pdu_event( - "IMB", - bob(), - TimelineEventType::RoomMember, - Some(bob().to_string().as_str()), - member_content_join(), - &["CREATE", "IJR", "IPOWER"], - &["IJR"], - ), - to_pdu_event( - "IMC", - charlie(), - TimelineEventType::RoomMember, - Some(charlie().to_string().as_str()), - member_content_join(), - &["CREATE", "IJR", "IPOWER"], - &["IMB"], - ), - to_pdu_event::<&EventId>( - "START", - charlie(), - TimelineEventType::RoomTopic, - Some(""), - to_raw_json_value(&json!({})).unwrap(), - &[], - &[], - ), - to_pdu_event::<&EventId>( - "END", - charlie(), - TimelineEventType::RoomTopic, - Some(""), - to_raw_json_value(&json!({})).unwrap(), - &[], - &[], - ), - ] - .into_iter() - .map(|ev| (ev.event_id().to_owned(), ev)) - .collect() -} - -// all graphs start with these input events -#[allow(non_snake_case)] -fn BAN_STATE_SET() -> HashMap> { - vec![ - to_pdu_event( - "PA", - alice(), - TimelineEventType::RoomPowerLevels, - Some(""), - to_raw_json_value(&json!({ "users": { alice(): 100, bob(): 50 } })).unwrap(), - &["CREATE", "IMA", "IPOWER"], // auth_events - &["START"], // prev_events - ), - to_pdu_event( - "PB", - alice(), - TimelineEventType::RoomPowerLevels, - Some(""), - to_raw_json_value(&json!({ "users": { alice(): 100, bob(): 50 } })).unwrap(), - &["CREATE", "IMA", "IPOWER"], - &["END"], - ), - to_pdu_event( - "MB", - alice(), - TimelineEventType::RoomMember, - Some(ella().as_str()), - member_content_ban(), - &["CREATE", "IMA", "PB"], - &["PA"], - ), - to_pdu_event( - "IME", - ella(), - TimelineEventType::RoomMember, - Some(ella().as_str()), - member_content_join(), - &["CREATE", "IJR", "PA"], - &["MB"], - ), - ] - .into_iter() - .map(|ev| (ev.event_id().to_owned(), ev)) - .collect() -} - -/// Convenience trait for adding event type plus state key to state maps. -trait EventTypeExt { - fn with_state_key(self, state_key: impl Into) -> (StateEventType, String); -} - -impl EventTypeExt for &TimelineEventType { - fn with_state_key(self, state_key: impl Into) -> (StateEventType, String) { - (self.to_string().into(), state_key.into()) - } -} - -mod event { - use ruma::{ - MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId, - events::{TimelineEventType, pdu::Pdu}, - }; - use serde::{Deserialize, Serialize}; - use serde_json::value::RawValue as RawJsonValue; - - use super::Event; - - impl Event for PduEvent { - type Id = OwnedEventId; - - fn event_id(&self) -> &Self::Id { &self.event_id } - - fn room_id(&self) -> &RoomId { - match &self.rest { - | Pdu::RoomV1Pdu(ev) => &ev.room_id, - | Pdu::RoomV3Pdu(ev) => &ev.room_id, - #[cfg(not(feature = "unstable-exhaustive-types"))] - | _ => unreachable!("new PDU version"), - } - } - - fn sender(&self) -> &UserId { - match &self.rest { - | Pdu::RoomV1Pdu(ev) => &ev.sender, - | Pdu::RoomV3Pdu(ev) => &ev.sender, - #[cfg(not(feature = "unstable-exhaustive-types"))] - | _ => unreachable!("new PDU version"), - } - } - - fn event_type(&self) -> &TimelineEventType { - match &self.rest { - | Pdu::RoomV1Pdu(ev) => &ev.kind, - | Pdu::RoomV3Pdu(ev) => &ev.kind, - #[cfg(not(feature = "unstable-exhaustive-types"))] - | _ => unreachable!("new PDU version"), - } - } - - fn content(&self) -> &RawJsonValue { - match &self.rest { - | Pdu::RoomV1Pdu(ev) => &ev.content, - | Pdu::RoomV3Pdu(ev) => &ev.content, - #[cfg(not(feature = "unstable-exhaustive-types"))] - | _ => unreachable!("new PDU version"), - } - } - - fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch { - match &self.rest { - | Pdu::RoomV1Pdu(ev) => ev.origin_server_ts, - | Pdu::RoomV3Pdu(ev) => ev.origin_server_ts, - #[cfg(not(feature = "unstable-exhaustive-types"))] - | _ => unreachable!("new PDU version"), - } - } - - fn state_key(&self) -> Option<&str> { - match &self.rest { - | Pdu::RoomV1Pdu(ev) => ev.state_key.as_deref(), - | Pdu::RoomV3Pdu(ev) => ev.state_key.as_deref(), - #[cfg(not(feature = "unstable-exhaustive-types"))] - | _ => unreachable!("new PDU version"), - } - } - - fn prev_events(&self) -> Box + Send + '_> { - match &self.rest { - | Pdu::RoomV1Pdu(ev) => Box::new(ev.prev_events.iter().map(|(id, _)| id)), - | Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter()), - #[cfg(not(feature = "unstable-exhaustive-types"))] - | _ => unreachable!("new PDU version"), - } - } - - fn auth_events(&self) -> Box + Send + '_> { - match &self.rest { - | Pdu::RoomV1Pdu(ev) => Box::new(ev.auth_events.iter().map(|(id, _)| id)), - | Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter()), - #[cfg(not(feature = "unstable-exhaustive-types"))] - | _ => unreachable!("new PDU version"), - } - } - - fn redacts(&self) -> Option<&Self::Id> { - match &self.rest { - | Pdu::RoomV1Pdu(ev) => ev.redacts.as_ref(), - | Pdu::RoomV3Pdu(ev) => ev.redacts.as_ref(), - #[cfg(not(feature = "unstable-exhaustive-types"))] - | _ => unreachable!("new PDU version"), - } - } - } - - #[derive(Clone, Debug, Deserialize, Serialize)] - pub(crate) struct PduEvent { - pub(crate) event_id: OwnedEventId, - #[serde(flatten)] - pub(crate) rest: Pdu, - } -} diff --git a/src/core/mod.rs b/src/core/mod.rs index b91cdf0b..cd56774a 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,15 +1,14 @@ -#![type_length_limit = "12288"] - pub mod alloc; pub mod config; pub mod debug; pub mod error; pub mod info; pub mod log; -pub mod matrix; pub mod metrics; pub mod mods; +pub mod pdu; pub mod server; +pub mod state_res; pub mod utils; pub use ::arrayvec; @@ -22,8 +21,9 @@ pub use ::tracing; pub use config::Config; pub use error::Error; pub use info::{rustc_flags_capture, version, version::version}; -pub use matrix::{Event, EventTypeExt, PduCount, PduEvent, PduId, RoomVersion, pdu, state_res}; +pub use pdu::{Event, PduBuilder, PduCount, PduEvent, PduId, RawPduId, StateKey}; pub use server::Server; +pub use state_res::{EventTypeExt, RoomVersion, StateMap, TypeStateKey}; pub use utils::{ctor, dtor, implement, result, result::Result}; pub use crate as conduwuit_core; diff --git a/src/core/matrix/pdu/builder.rs b/src/core/pdu/builder.rs similarity index 100% rename from src/core/matrix/pdu/builder.rs rename to src/core/pdu/builder.rs diff --git a/src/core/matrix/pdu/content.rs b/src/core/pdu/content.rs similarity index 100% rename from src/core/matrix/pdu/content.rs rename to src/core/pdu/content.rs diff --git a/src/core/matrix/pdu/count.rs b/src/core/pdu/count.rs similarity index 100% rename from src/core/matrix/pdu/count.rs rename to src/core/pdu/count.rs diff --git a/src/core/pdu/event.rs b/src/core/pdu/event.rs new file mode 100644 index 00000000..09ad1666 --- /dev/null +++ b/src/core/pdu/event.rs @@ -0,0 +1,35 @@ +use ruma::{MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId, events::TimelineEventType}; +use serde_json::value::RawValue as RawJsonValue; + +use super::Pdu; +pub use crate::state_res::Event; + +impl Event for Pdu { + type Id = OwnedEventId; + + fn event_id(&self) -> &Self::Id { &self.event_id } + + fn room_id(&self) -> &RoomId { &self.room_id } + + fn sender(&self) -> &UserId { &self.sender } + + fn event_type(&self) -> &TimelineEventType { &self.kind } + + fn content(&self) -> &RawJsonValue { &self.content } + + fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch { + MilliSecondsSinceUnixEpoch(self.origin_server_ts) + } + + fn state_key(&self) -> Option<&str> { self.state_key.as_deref() } + + fn prev_events(&self) -> impl DoubleEndedIterator + Send + '_ { + self.prev_events.iter() + } + + fn auth_events(&self) -> impl DoubleEndedIterator + Send + '_ { + self.auth_events.iter() + } + + fn redacts(&self) -> Option<&Self::Id> { self.redacts.as_ref() } +} diff --git a/src/core/matrix/pdu/event_id.rs b/src/core/pdu/event_id.rs similarity index 100% rename from src/core/matrix/pdu/event_id.rs rename to src/core/pdu/event_id.rs diff --git a/src/core/matrix/pdu/filter.rs b/src/core/pdu/filter.rs similarity index 100% rename from src/core/matrix/pdu/filter.rs rename to src/core/pdu/filter.rs diff --git a/src/core/matrix/pdu/id.rs b/src/core/pdu/id.rs similarity index 100% rename from src/core/matrix/pdu/id.rs rename to src/core/pdu/id.rs diff --git a/src/core/matrix/pdu.rs b/src/core/pdu/mod.rs similarity index 72% rename from src/core/matrix/pdu.rs rename to src/core/pdu/mod.rs index 7e1ecfa8..9fb2a3da 100644 --- a/src/core/matrix/pdu.rs +++ b/src/core/pdu/mod.rs @@ -1,6 +1,7 @@ mod builder; mod content; mod count; +mod event; mod event_id; mod filter; mod id; @@ -16,8 +17,8 @@ mod unsigned; use std::cmp::Ordering; use ruma::{ - CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, - OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, UInt, UserId, events::TimelineEventType, + CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, OwnedServerName, + OwnedUserId, UInt, events::TimelineEventType, }; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue as RawJsonValue; @@ -26,12 +27,12 @@ pub use self::{ Count as PduCount, Id as PduId, Pdu as PduEvent, RawId as RawPduId, builder::{Builder, Builder as PduBuilder}, count::Count, + event::Event, event_id::*, id::*, raw_id::*, state_key::{ShortStateKey, StateKey}, }; -use super::Event; use crate::Result; /// Persistent Data Unit (Event) @@ -78,36 +79,6 @@ impl Pdu { } } -impl Event for Pdu { - type Id = OwnedEventId; - - fn event_id(&self) -> &Self::Id { &self.event_id } - - fn room_id(&self) -> &RoomId { &self.room_id } - - fn sender(&self) -> &UserId { &self.sender } - - fn event_type(&self) -> &TimelineEventType { &self.kind } - - fn content(&self) -> &RawJsonValue { &self.content } - - fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch { - MilliSecondsSinceUnixEpoch(self.origin_server_ts) - } - - fn state_key(&self) -> Option<&str> { self.state_key.as_deref() } - - fn prev_events(&self) -> impl DoubleEndedIterator + Send + '_ { - self.prev_events.iter() - } - - fn auth_events(&self) -> impl DoubleEndedIterator + Send + '_ { - self.auth_events.iter() - } - - fn redacts(&self) -> Option<&Self::Id> { self.redacts.as_ref() } -} - /// Prevent derived equality which wouldn't limit itself to event_id impl Eq for Pdu {} @@ -116,12 +87,12 @@ impl PartialEq for Pdu { fn eq(&self, other: &Self) -> bool { self.event_id == other.event_id } } -/// Ordering determined by the Pdu's ID, not the memory representations. -impl Ord for Pdu { - fn cmp(&self, other: &Self) -> Ordering { self.event_id.cmp(&other.event_id) } -} - /// Ordering determined by the Pdu's ID, not the memory representations. impl PartialOrd for Pdu { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } + +/// Ordering determined by the Pdu's ID, not the memory representations. +impl Ord for Pdu { + fn cmp(&self, other: &Self) -> Ordering { self.event_id.cmp(&other.event_id) } +} diff --git a/src/core/matrix/pdu/raw_id.rs b/src/core/pdu/raw_id.rs similarity index 100% rename from src/core/matrix/pdu/raw_id.rs rename to src/core/pdu/raw_id.rs diff --git a/src/core/matrix/pdu/redact.rs b/src/core/pdu/redact.rs similarity index 100% rename from src/core/matrix/pdu/redact.rs rename to src/core/pdu/redact.rs diff --git a/src/core/matrix/pdu/relation.rs b/src/core/pdu/relation.rs similarity index 100% rename from src/core/matrix/pdu/relation.rs rename to src/core/pdu/relation.rs diff --git a/src/core/matrix/pdu/state_key.rs b/src/core/pdu/state_key.rs similarity index 100% rename from src/core/matrix/pdu/state_key.rs rename to src/core/pdu/state_key.rs diff --git a/src/core/matrix/pdu/strip.rs b/src/core/pdu/strip.rs similarity index 63% rename from src/core/matrix/pdu/strip.rs rename to src/core/pdu/strip.rs index 3683caaa..4e7c5b83 100644 --- a/src/core/matrix/pdu/strip.rs +++ b/src/core/pdu/strip.rs @@ -10,133 +10,9 @@ use serde_json::{json, value::Value as JsonValue}; use crate::implement; -/// This only works for events that are also AnyRoomEvents. #[must_use] #[implement(super::Pdu)] -pub fn into_any_event(self) -> Raw { - serde_json::from_value(self.into_any_event_value()).expect("Raw::from_value always works") -} - -/// This only works for events that are also AnyRoomEvents. -#[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn into_any_event_value(self) -> JsonValue { - let (redacts, content) = self.copy_redacts(); - let mut json = json!({ - "content": content, - "type": self.kind, - "event_id": self.event_id, - "sender": self.sender, - "origin_server_ts": self.origin_server_ts, - "room_id": self.room_id, - }); - - if let Some(unsigned) = &self.unsigned { - json["unsigned"] = json!(unsigned); - } - if let Some(state_key) = &self.state_key { - json["state_key"] = json!(state_key); - } - if let Some(redacts) = &redacts { - json["redacts"] = json!(redacts); - } - - json -} - -#[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn into_room_event(self) -> Raw { self.to_room_event() } - -#[implement(super::Pdu)] -#[must_use] -pub fn to_room_event(&self) -> Raw { - serde_json::from_value(self.to_room_event_value()).expect("Raw::from_value always works") -} - -#[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn to_room_event_value(&self) -> JsonValue { - let (redacts, content) = self.copy_redacts(); - let mut json = json!({ - "content": content, - "type": self.kind, - "event_id": self.event_id, - "sender": self.sender, - "origin_server_ts": self.origin_server_ts, - "room_id": self.room_id, - }); - - if let Some(unsigned) = &self.unsigned { - json["unsigned"] = json!(unsigned); - } - if let Some(state_key) = &self.state_key { - json["state_key"] = json!(state_key); - } - if let Some(redacts) = &redacts { - json["redacts"] = json!(redacts); - } - - json -} - -#[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn into_message_like_event(self) -> Raw { self.to_message_like_event() } - -#[implement(super::Pdu)] -#[must_use] -pub fn to_message_like_event(&self) -> Raw { - serde_json::from_value(self.to_message_like_event_value()) - .expect("Raw::from_value always works") -} - -#[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn to_message_like_event_value(&self) -> JsonValue { - let (redacts, content) = self.copy_redacts(); - let mut json = json!({ - "content": content, - "type": self.kind, - "event_id": self.event_id, - "sender": self.sender, - "origin_server_ts": self.origin_server_ts, - "room_id": self.room_id, - }); - - if let Some(unsigned) = &self.unsigned { - json["unsigned"] = json!(unsigned); - } - if let Some(state_key) = &self.state_key { - json["state_key"] = json!(state_key); - } - if let Some(redacts) = &redacts { - json["redacts"] = json!(redacts); - } - - json -} - -#[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn into_sync_room_event(self) -> Raw { self.to_sync_room_event() } - -#[implement(super::Pdu)] -#[must_use] pub fn to_sync_room_event(&self) -> Raw { - serde_json::from_value(self.to_sync_room_event_value()).expect("Raw::from_value always works") -} - -#[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn to_sync_room_event_value(&self) -> JsonValue { let (redacts, content) = self.copy_redacts(); let mut json = json!({ "content": content, @@ -156,18 +32,90 @@ pub fn to_sync_room_event_value(&self) -> JsonValue { json["redacts"] = json!(redacts); } - json + serde_json::from_value(json).expect("Raw::from_value always works") } -#[implement(super::Pdu)] +/// This only works for events that are also AnyRoomEvents. #[must_use] -pub fn into_state_event(self) -> Raw { - serde_json::from_value(self.into_state_event_value()).expect("Raw::from_value always works") +#[implement(super::Pdu)] +pub fn to_any_event(&self) -> Raw { + let (redacts, content) = self.copy_redacts(); + let mut json = json!({ + "content": content, + "type": self.kind, + "event_id": self.event_id, + "sender": self.sender, + "origin_server_ts": self.origin_server_ts, + "room_id": self.room_id, + }); + + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } + if let Some(state_key) = &self.state_key { + json["state_key"] = json!(state_key); + } + if let Some(redacts) = &redacts { + json["redacts"] = json!(redacts); + } + + serde_json::from_value(json).expect("Raw::from_value always works") } -#[implement(super::Pdu)] #[must_use] -#[inline] +#[implement(super::Pdu)] +pub fn to_room_event(&self) -> Raw { + let (redacts, content) = self.copy_redacts(); + let mut json = json!({ + "content": content, + "type": self.kind, + "event_id": self.event_id, + "sender": self.sender, + "origin_server_ts": self.origin_server_ts, + "room_id": self.room_id, + }); + + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } + if let Some(state_key) = &self.state_key { + json["state_key"] = json!(state_key); + } + if let Some(redacts) = &redacts { + json["redacts"] = json!(redacts); + } + + serde_json::from_value(json).expect("Raw::from_value always works") +} + +#[must_use] +#[implement(super::Pdu)] +pub fn to_message_like_event(&self) -> Raw { + let (redacts, content) = self.copy_redacts(); + let mut json = json!({ + "content": content, + "type": self.kind, + "event_id": self.event_id, + "sender": self.sender, + "origin_server_ts": self.origin_server_ts, + "room_id": self.room_id, + }); + + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } + if let Some(state_key) = &self.state_key { + json["state_key"] = json!(state_key); + } + if let Some(redacts) = &redacts { + json["redacts"] = json!(redacts); + } + + serde_json::from_value(json).expect("Raw::from_value always works") +} + +#[must_use] +#[implement(super::Pdu)] pub fn into_state_event_value(self) -> JsonValue { let mut json = json!({ "content": self.content, @@ -186,17 +134,15 @@ pub fn into_state_event_value(self) -> JsonValue { json } -#[implement(super::Pdu)] #[must_use] -pub fn into_sync_state_event(self) -> Raw { - serde_json::from_value(self.into_sync_state_event_value()) - .expect("Raw::from_value always works") +#[implement(super::Pdu)] +pub fn into_state_event(self) -> Raw { + serde_json::from_value(self.into_state_event_value()).expect("Raw::from_value always works") } -#[implement(super::Pdu)] #[must_use] -#[inline] -pub fn into_sync_state_event_value(self) -> JsonValue { +#[implement(super::Pdu)] +pub fn to_sync_state_event(&self) -> Raw { let mut json = json!({ "content": self.content, "type": self.kind, @@ -210,65 +156,39 @@ pub fn into_sync_state_event_value(self) -> JsonValue { json["unsigned"] = json!(unsigned); } - json + serde_json::from_value(json).expect("Raw::from_value always works") } -#[implement(super::Pdu)] #[must_use] -#[inline] -pub fn into_stripped_state_event(self) -> Raw { - self.to_stripped_state_event() -} - #[implement(super::Pdu)] -#[must_use] pub fn to_stripped_state_event(&self) -> Raw { - serde_json::from_value(self.to_stripped_state_event_value()) - .expect("Raw::from_value always works") -} - -#[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn to_stripped_state_event_value(&self) -> JsonValue { - json!({ + let json = json!({ "content": self.content, "type": self.kind, "sender": self.sender, "state_key": self.state_key, - }) + }); + + serde_json::from_value(json).expect("Raw::from_value always works") } -#[implement(super::Pdu)] #[must_use] -pub fn into_stripped_spacechild_state_event(self) -> Raw { - serde_json::from_value(self.into_stripped_spacechild_state_event_value()) - .expect("Raw::from_value always works") -} - #[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn into_stripped_spacechild_state_event_value(self) -> JsonValue { - json!({ +pub fn to_stripped_spacechild_state_event(&self) -> Raw { + let json = json!({ "content": self.content, "type": self.kind, "sender": self.sender, "state_key": self.state_key, "origin_server_ts": self.origin_server_ts, - }) + }); + + serde_json::from_value(json).expect("Raw::from_value always works") } -#[implement(super::Pdu)] #[must_use] +#[implement(super::Pdu)] pub fn into_member_event(self) -> Raw> { - serde_json::from_value(self.into_member_event_value()).expect("Raw::from_value always works") -} - -#[implement(super::Pdu)] -#[must_use] -#[inline] -pub fn into_member_event_value(self) -> JsonValue { let mut json = json!({ "content": self.content, "type": self.kind, @@ -284,5 +204,5 @@ pub fn into_member_event_value(self) -> JsonValue { json["unsigned"] = json!(unsigned); } - json + serde_json::from_value(json).expect("Raw::from_value always works") } diff --git a/src/core/matrix/pdu/tests.rs b/src/core/pdu/tests.rs similarity index 100% rename from src/core/matrix/pdu/tests.rs rename to src/core/pdu/tests.rs diff --git a/src/core/matrix/pdu/unsigned.rs b/src/core/pdu/unsigned.rs similarity index 100% rename from src/core/matrix/pdu/unsigned.rs rename to src/core/pdu/unsigned.rs diff --git a/src/core/server.rs b/src/core/server.rs index 4b673f32..b67759d6 100644 --- a/src/core/server.rs +++ b/src/core/server.rs @@ -69,6 +69,10 @@ impl Server { return Err!("Reloading not enabled"); } + #[cfg(all(feature = "systemd", target_os = "linux"))] + sd_notify::notify(true, &[sd_notify::NotifyState::Reloading]) + .expect("failed to notify systemd of reloading state"); + if self.reloading.swap(true, Ordering::AcqRel) { return Err!("Reloading already in progress"); } @@ -94,6 +98,10 @@ impl Server { } pub fn shutdown(&self) -> Result { + #[cfg(all(feature = "systemd", target_os = "linux"))] + sd_notify::notify(true, &[sd_notify::NotifyState::Stopping]) + .expect("failed to notify systemd of stopping state"); + if self.stopping.swap(true, Ordering::AcqRel) { return Err!("Shutdown already in progress"); } @@ -136,16 +144,7 @@ impl Server { } #[inline] - pub fn running(&self) -> bool { !self.is_stopping() } - - #[inline] - pub fn is_stopping(&self) -> bool { self.stopping.load(Ordering::Relaxed) } - - #[inline] - pub fn is_reloading(&self) -> bool { self.reloading.load(Ordering::Relaxed) } - - #[inline] - pub fn is_restarting(&self) -> bool { self.restarting.load(Ordering::Relaxed) } + pub fn running(&self) -> bool { !self.stopping.load(Ordering::Acquire) } #[inline] pub fn is_ours(&self, name: &str) -> bool { name == self.config.server_name } diff --git a/src/core/matrix/state_res/LICENSE b/src/core/state_res/LICENSE similarity index 100% rename from src/core/matrix/state_res/LICENSE rename to src/core/state_res/LICENSE diff --git a/src/core/matrix/state_res/error.rs b/src/core/state_res/error.rs similarity index 100% rename from src/core/matrix/state_res/error.rs rename to src/core/state_res/error.rs diff --git a/src/core/matrix/state_res/event_auth.rs b/src/core/state_res/event_auth.rs similarity index 100% rename from src/core/matrix/state_res/event_auth.rs rename to src/core/state_res/event_auth.rs diff --git a/src/core/matrix/state_res/mod.rs b/src/core/state_res/mod.rs similarity index 99% rename from src/core/matrix/state_res/mod.rs rename to src/core/state_res/mod.rs index 93c00d15..6bff0cf8 100644 --- a/src/core/matrix/state_res/mod.rs +++ b/src/core/state_res/mod.rs @@ -4,13 +4,11 @@ pub(crate) mod error; pub mod event_auth; mod power_levels; mod room_version; +mod state_event; #[cfg(test)] mod test_utils; -#[cfg(test)] -mod benches; - use std::{ borrow::Borrow, cmp::{Ordering, Reverse}, @@ -35,12 +33,9 @@ use self::power_levels::PowerLevelsContentFields; pub use self::{ event_auth::{auth_check, auth_types_for_event}, room_version::RoomVersion, + state_event::Event, }; -use crate::{ - debug, - matrix::{event::Event, pdu::StateKey}, - trace, warn, -}; +use crate::{debug, pdu::StateKey, trace, warn}; /// A mapping of event type and state_key to some value `T`, usually an /// `EventId`. @@ -151,6 +146,7 @@ where &event_fetch, parallel_fetches, ) + .boxed() .await?; debug!(count = sorted_control_levels.len(), "power events"); @@ -165,6 +161,7 @@ where &event_fetch, parallel_fetches, ) + .boxed() .await?; debug!(count = resolved_control.len(), "resolved power events"); @@ -192,6 +189,7 @@ where let sorted_left_events = mainline_sort(&events_to_resolve, power_event.cloned(), &event_fetch, parallel_fetches) + .boxed() .await?; trace!(list = ?sorted_left_events, "events left, sorted"); @@ -203,6 +201,7 @@ where &event_fetch, parallel_fetches, ) + .boxed() .await?; // Add unconflicted state to the resolved state diff --git a/src/core/matrix/state_res/outcomes.txt b/src/core/state_res/outcomes.txt similarity index 100% rename from src/core/matrix/state_res/outcomes.txt rename to src/core/state_res/outcomes.txt diff --git a/src/core/matrix/state_res/power_levels.rs b/src/core/state_res/power_levels.rs similarity index 99% rename from src/core/matrix/state_res/power_levels.rs rename to src/core/state_res/power_levels.rs index 19ba8fb9..045b1666 100644 --- a/src/core/matrix/state_res/power_levels.rs +++ b/src/core/state_res/power_levels.rs @@ -11,9 +11,9 @@ use ruma::{ }; use serde::Deserialize; use serde_json::{Error, from_str as from_json_str}; +use tracing::error; use super::{Result, RoomVersion}; -use crate::error; #[derive(Deserialize)] struct IntRoomPowerLevelsEventContent { diff --git a/src/core/matrix/state_res/room_version.rs b/src/core/state_res/room_version.rs similarity index 100% rename from src/core/matrix/state_res/room_version.rs rename to src/core/state_res/room_version.rs diff --git a/src/core/matrix/event.rs b/src/core/state_res/state_event.rs similarity index 100% rename from src/core/matrix/event.rs rename to src/core/state_res/state_event.rs diff --git a/src/core/state_res/state_res_bench.rs b/src/core/state_res/state_res_bench.rs new file mode 100644 index 00000000..a2bd2c23 --- /dev/null +++ b/src/core/state_res/state_res_bench.rs @@ -0,0 +1,648 @@ +// Because of criterion `cargo bench` works, +// but if you use `cargo bench -- --save-baseline ` +// or pass any other args to it, it fails with the error +// `cargo bench unknown option --save-baseline`. +// To pass args to criterion, use this form +// `cargo bench --bench -- --save-baseline `. + +#![allow(clippy::exhaustive_structs)] + +use std::{ + borrow::Borrow, + collections::{HashMap, HashSet}, + sync::{ + atomic::{AtomicU64, Ordering::SeqCst}, + Arc, + }, +}; + +use criterion::{criterion_group, criterion_main, Criterion}; +use event::PduEvent; +use futures::{future, future::ready}; +use ruma::{int, uint}; +use maplit::{btreemap, hashmap, hashset}; +use ruma::{ + room_id, user_id, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, + Signatures, UserId, +}; +use ruma::events::{ + pdu::{EventHash, Pdu, RoomV3Pdu}, + room::{ + join_rules::{JoinRule, RoomJoinRulesEventContent}, + member::{MembershipState, RoomMemberEventContent}, + }, + StateEventType, TimelineEventType, +}; +use conduwuit::state_res::{self as state_res, Error, Event, Result, StateMap}; +use serde_json::{ + json, + value::{to_raw_value as to_raw_json_value, RawValue as RawJsonValue}, +}; + +static SERVER_TIMESTAMP: AtomicU64 = AtomicU64::new(0); + +fn lexico_topo_sort(c: &mut Criterion) { + c.bench_function("lexicographical topological sort", |b| { + let graph = hashmap! { + event_id("l") => hashset![event_id("o")], + event_id("m") => hashset![event_id("n"), event_id("o")], + event_id("n") => hashset![event_id("o")], + event_id("o") => hashset![], // "o" has zero outgoing edges but 4 incoming edges + event_id("p") => hashset![event_id("o")], + }; + b.iter(|| { + let _ = state_res::lexicographical_topological_sort(&graph, &|_| { + future::ok((int!(0), MilliSecondsSinceUnixEpoch(uint!(0)))) + }); + }); + }); +} + +fn resolution_shallow_auth_chain(c: &mut Criterion) { + c.bench_function("resolve state of 5 events one fork", |b| { + let mut store = TestStore(hashmap! {}); + + // build up the DAG + let (state_at_bob, state_at_charlie, _) = store.set_up(); + + b.iter(|| async { + let ev_map = store.0.clone(); + let state_sets = [&state_at_bob, &state_at_charlie]; + let fetch = |id: OwnedEventId| ready(ev_map.get(&id).map(Arc::clone)); + let exists = |id: OwnedEventId| ready(ev_map.get(&id).is_some()); + let auth_chain_sets = state_sets + .iter() + .map(|map| { + store.auth_event_ids(room_id(), map.values().cloned().collect()).unwrap() + }) + .collect(); + + let _ = match state_res::resolve( + &RoomVersionId::V6, + state_sets.into_iter(), + &auth_chain_sets, + &fetch, + &exists, + ) + .await + { + Ok(state) => state, + Err(e) => panic!("{e}"), + }; + }); + }); +} + +fn resolve_deeper_event_set(c: &mut Criterion) { + c.bench_function("resolve state of 10 events 3 conflicting", |b| { + let mut inner = INITIAL_EVENTS(); + let ban = BAN_STATE_SET(); + + inner.extend(ban); + let store = TestStore(inner.clone()); + + let state_set_a = [ + inner.get(&event_id("CREATE")).unwrap(), + inner.get(&event_id("IJR")).unwrap(), + inner.get(&event_id("IMA")).unwrap(), + inner.get(&event_id("IMB")).unwrap(), + inner.get(&event_id("IMC")).unwrap(), + inner.get(&event_id("MB")).unwrap(), + inner.get(&event_id("PA")).unwrap(), + ] + .iter() + .map(|ev| { + (ev.event_type().with_state_key(ev.state_key().unwrap()), ev.event_id().to_owned()) + }) + .collect::>(); + + let state_set_b = [ + inner.get(&event_id("CREATE")).unwrap(), + inner.get(&event_id("IJR")).unwrap(), + inner.get(&event_id("IMA")).unwrap(), + inner.get(&event_id("IMB")).unwrap(), + inner.get(&event_id("IMC")).unwrap(), + inner.get(&event_id("IME")).unwrap(), + inner.get(&event_id("PA")).unwrap(), + ] + .iter() + .map(|ev| { + (ev.event_type().with_state_key(ev.state_key().unwrap()), ev.event_id().to_owned()) + }) + .collect::>(); + + b.iter(|| async { + let state_sets = [&state_set_a, &state_set_b]; + let auth_chain_sets = state_sets + .iter() + .map(|map| { + store.auth_event_ids(room_id(), map.values().cloned().collect()).unwrap() + }) + .collect(); + + let fetch = |id: OwnedEventId| ready(inner.get(&id).map(Arc::clone)); + let exists = |id: OwnedEventId| ready(inner.get(&id).is_some()); + let _ = match state_res::resolve( + &RoomVersionId::V6, + state_sets.into_iter(), + &auth_chain_sets, + &fetch, + &exists, + ) + .await + { + Ok(state) => state, + Err(_) => panic!("resolution failed during benchmarking"), + }; + }); + }); +} + +criterion_group!( + benches, + lexico_topo_sort, + resolution_shallow_auth_chain, + resolve_deeper_event_set +); + +criterion_main!(benches); + +//*///////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION DETAILS AHEAD +// +/////////////////////////////////////////////////////////////////////*/ +struct TestStore(HashMap>); + +#[allow(unused)] +impl TestStore { + fn get_event(&self, room_id: &RoomId, event_id: &EventId) -> Result> { + self.0 + .get(event_id) + .map(Arc::clone) + .ok_or_else(|| Error::NotFound(format!("{} not found", event_id))) + } + + /// Returns the events that correspond to the `event_ids` sorted in the same order. + fn get_events(&self, room_id: &RoomId, event_ids: &[OwnedEventId]) -> Result>> { + let mut events = vec![]; + for id in event_ids { + events.push(self.get_event(room_id, id)?); + } + Ok(events) + } + + /// Returns a Vec of the related auth events to the given `event`. + fn auth_event_ids(&self, room_id: &RoomId, event_ids: Vec) -> Result> { + let mut result = HashSet::new(); + let mut stack = event_ids; + + // DFS for auth event chain + while !stack.is_empty() { + let ev_id = stack.pop().unwrap(); + if result.contains(&ev_id) { + continue; + } + + result.insert(ev_id.clone()); + + let event = self.get_event(room_id, ev_id.borrow())?; + + stack.extend(event.auth_events().map(ToOwned::to_owned)); + } + + Ok(result) + } + + /// Returns a vector representing the difference in auth chains of the given `events`. + fn auth_chain_diff(&self, room_id: &RoomId, event_ids: Vec>) -> Result> { + let mut auth_chain_sets = vec![]; + for ids in event_ids { + // TODO state store `auth_event_ids` returns self in the event ids list + // when an event returns `auth_event_ids` self is not contained + let chain = self.auth_event_ids(room_id, ids)?.into_iter().collect::>(); + auth_chain_sets.push(chain); + } + + if let Some(first) = auth_chain_sets.first().cloned() { + let common = auth_chain_sets + .iter() + .skip(1) + .fold(first, |a, b| a.intersection(b).cloned().collect::>()); + + Ok(auth_chain_sets + .into_iter() + .flatten() + .filter(|id| !common.contains(id.borrow())) + .collect()) + } else { + Ok(vec![]) + } + } +} + +impl TestStore { + #[allow(clippy::type_complexity)] + fn set_up( + &mut self, + ) -> (StateMap, StateMap, StateMap) { + let create_event = to_pdu_event::<&EventId>( + "CREATE", + alice(), + TimelineEventType::RoomCreate, + Some(""), + to_raw_json_value(&json!({ "creator": alice() })).unwrap(), + &[], + &[], + ); + let cre = create_event.event_id().to_owned(); + self.0.insert(cre.clone(), Arc::clone(&create_event)); + + let alice_mem = to_pdu_event( + "IMA", + alice(), + TimelineEventType::RoomMember, + Some(alice().to_string().as_str()), + member_content_join(), + &[cre.clone()], + &[cre.clone()], + ); + self.0.insert(alice_mem.event_id().to_owned(), Arc::clone(&alice_mem)); + + let join_rules = to_pdu_event( + "IJR", + alice(), + TimelineEventType::RoomJoinRules, + Some(""), + to_raw_json_value(&RoomJoinRulesEventContent::new(JoinRule::Public)).unwrap(), + &[cre.clone(), alice_mem.event_id().to_owned()], + &[alice_mem.event_id().to_owned()], + ); + self.0.insert(join_rules.event_id().to_owned(), join_rules.clone()); + + // Bob and Charlie join at the same time, so there is a fork + // this will be represented in the state_sets when we resolve + let bob_mem = to_pdu_event( + "IMB", + bob(), + TimelineEventType::RoomMember, + Some(bob().to_string().as_str()), + member_content_join(), + &[cre.clone(), join_rules.event_id().to_owned()], + &[join_rules.event_id().to_owned()], + ); + self.0.insert(bob_mem.event_id().to_owned(), bob_mem.clone()); + + let charlie_mem = to_pdu_event( + "IMC", + charlie(), + TimelineEventType::RoomMember, + Some(charlie().to_string().as_str()), + member_content_join(), + &[cre, join_rules.event_id().to_owned()], + &[join_rules.event_id().to_owned()], + ); + self.0.insert(charlie_mem.event_id().to_owned(), charlie_mem.clone()); + + let state_at_bob = [&create_event, &alice_mem, &join_rules, &bob_mem] + .iter() + .map(|e| { + (e.event_type().with_state_key(e.state_key().unwrap()), e.event_id().to_owned()) + }) + .collect::>(); + + let state_at_charlie = [&create_event, &alice_mem, &join_rules, &charlie_mem] + .iter() + .map(|e| { + (e.event_type().with_state_key(e.state_key().unwrap()), e.event_id().to_owned()) + }) + .collect::>(); + + let expected = [&create_event, &alice_mem, &join_rules, &bob_mem, &charlie_mem] + .iter() + .map(|e| { + (e.event_type().with_state_key(e.state_key().unwrap()), e.event_id().to_owned()) + }) + .collect::>(); + + (state_at_bob, state_at_charlie, expected) + } +} + +fn event_id(id: &str) -> OwnedEventId { + if id.contains('$') { + return id.try_into().unwrap(); + } + format!("${}:foo", id).try_into().unwrap() +} + +fn alice() -> &'static UserId { + user_id!("@alice:foo") +} + +fn bob() -> &'static UserId { + user_id!("@bob:foo") +} + +fn charlie() -> &'static UserId { + user_id!("@charlie:foo") +} + +fn ella() -> &'static UserId { + user_id!("@ella:foo") +} + +fn room_id() -> &'static RoomId { + room_id!("!test:foo") +} + +fn member_content_ban() -> Box { + to_raw_json_value(&RoomMemberEventContent::new(MembershipState::Ban)).unwrap() +} + +fn member_content_join() -> Box { + to_raw_json_value(&RoomMemberEventContent::new(MembershipState::Join)).unwrap() +} + +fn to_pdu_event( + id: &str, + sender: &UserId, + ev_type: TimelineEventType, + state_key: Option<&str>, + content: Box, + auth_events: &[S], + prev_events: &[S], +) -> Arc +where + S: AsRef, +{ + // We don't care if the addition happens in order just that it is atomic + // (each event has its own value) + let ts = SERVER_TIMESTAMP.fetch_add(1, SeqCst); + let id = if id.contains('$') { id.to_owned() } else { format!("${}:foo", id) }; + let auth_events = auth_events.iter().map(AsRef::as_ref).map(event_id).collect::>(); + let prev_events = prev_events.iter().map(AsRef::as_ref).map(event_id).collect::>(); + + let state_key = state_key.map(ToOwned::to_owned); + Arc::new(PduEvent { + event_id: id.try_into().unwrap(), + rest: Pdu::RoomV3Pdu(RoomV3Pdu { + room_id: room_id().to_owned(), + sender: sender.to_owned(), + origin_server_ts: MilliSecondsSinceUnixEpoch(ts.try_into().unwrap()), + state_key, + kind: ev_type, + content, + redacts: None, + unsigned: btreemap! {}, + auth_events, + prev_events, + depth: uint!(0), + hashes: EventHash::new(String::new()), + signatures: Signatures::new(), + }), + }) +} + +// all graphs start with these input events +#[allow(non_snake_case)] +fn INITIAL_EVENTS() -> HashMap> { + vec![ + to_pdu_event::<&EventId>( + "CREATE", + alice(), + TimelineEventType::RoomCreate, + Some(""), + to_raw_json_value(&json!({ "creator": alice() })).unwrap(), + &[], + &[], + ), + to_pdu_event( + "IMA", + alice(), + TimelineEventType::RoomMember, + Some(alice().as_str()), + member_content_join(), + &["CREATE"], + &["CREATE"], + ), + to_pdu_event( + "IPOWER", + alice(), + TimelineEventType::RoomPowerLevels, + Some(""), + to_raw_json_value(&json!({ "users": { alice(): 100 } })).unwrap(), + &["CREATE", "IMA"], + &["IMA"], + ), + to_pdu_event( + "IJR", + alice(), + TimelineEventType::RoomJoinRules, + Some(""), + to_raw_json_value(&RoomJoinRulesEventContent::new(JoinRule::Public)).unwrap(), + &["CREATE", "IMA", "IPOWER"], + &["IPOWER"], + ), + to_pdu_event( + "IMB", + bob(), + TimelineEventType::RoomMember, + Some(bob().to_string().as_str()), + member_content_join(), + &["CREATE", "IJR", "IPOWER"], + &["IJR"], + ), + to_pdu_event( + "IMC", + charlie(), + TimelineEventType::RoomMember, + Some(charlie().to_string().as_str()), + member_content_join(), + &["CREATE", "IJR", "IPOWER"], + &["IMB"], + ), + to_pdu_event::<&EventId>( + "START", + charlie(), + TimelineEventType::RoomTopic, + Some(""), + to_raw_json_value(&json!({})).unwrap(), + &[], + &[], + ), + to_pdu_event::<&EventId>( + "END", + charlie(), + TimelineEventType::RoomTopic, + Some(""), + to_raw_json_value(&json!({})).unwrap(), + &[], + &[], + ), + ] + .into_iter() + .map(|ev| (ev.event_id().to_owned(), ev)) + .collect() +} + +// all graphs start with these input events +#[allow(non_snake_case)] +fn BAN_STATE_SET() -> HashMap> { + vec![ + to_pdu_event( + "PA", + alice(), + TimelineEventType::RoomPowerLevels, + Some(""), + to_raw_json_value(&json!({ "users": { alice(): 100, bob(): 50 } })).unwrap(), + &["CREATE", "IMA", "IPOWER"], // auth_events + &["START"], // prev_events + ), + to_pdu_event( + "PB", + alice(), + TimelineEventType::RoomPowerLevels, + Some(""), + to_raw_json_value(&json!({ "users": { alice(): 100, bob(): 50 } })).unwrap(), + &["CREATE", "IMA", "IPOWER"], + &["END"], + ), + to_pdu_event( + "MB", + alice(), + TimelineEventType::RoomMember, + Some(ella().as_str()), + member_content_ban(), + &["CREATE", "IMA", "PB"], + &["PA"], + ), + to_pdu_event( + "IME", + ella(), + TimelineEventType::RoomMember, + Some(ella().as_str()), + member_content_join(), + &["CREATE", "IJR", "PA"], + &["MB"], + ), + ] + .into_iter() + .map(|ev| (ev.event_id().to_owned(), ev)) + .collect() +} + +/// Convenience trait for adding event type plus state key to state maps. +trait EventTypeExt { + fn with_state_key(self, state_key: impl Into) -> (StateEventType, String); +} + +impl EventTypeExt for &TimelineEventType { + fn with_state_key(self, state_key: impl Into) -> (StateEventType, String) { + (self.to_string().into(), state_key.into()) + } +} + +mod event { + use ruma_common::{MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId}; + use ruma_events::{pdu::Pdu, TimelineEventType}; + use ruma_state_res::Event; + use serde::{Deserialize, Serialize}; + use serde_json::value::RawValue as RawJsonValue; + + impl Event for PduEvent { + type Id = OwnedEventId; + + fn event_id(&self) -> &Self::Id { + &self.event_id + } + + fn room_id(&self) -> &RoomId { + match &self.rest { + Pdu::RoomV1Pdu(ev) => &ev.room_id, + Pdu::RoomV3Pdu(ev) => &ev.room_id, + #[cfg(not(feature = "unstable-exhaustive-types"))] + _ => unreachable!("new PDU version"), + } + } + + fn sender(&self) -> &UserId { + match &self.rest { + Pdu::RoomV1Pdu(ev) => &ev.sender, + Pdu::RoomV3Pdu(ev) => &ev.sender, + #[cfg(not(feature = "unstable-exhaustive-types"))] + _ => unreachable!("new PDU version"), + } + } + + fn event_type(&self) -> &TimelineEventType { + match &self.rest { + Pdu::RoomV1Pdu(ev) => &ev.kind, + Pdu::RoomV3Pdu(ev) => &ev.kind, + #[cfg(not(feature = "unstable-exhaustive-types"))] + _ => unreachable!("new PDU version"), + } + } + + fn content(&self) -> &RawJsonValue { + match &self.rest { + Pdu::RoomV1Pdu(ev) => &ev.content, + Pdu::RoomV3Pdu(ev) => &ev.content, + #[cfg(not(feature = "unstable-exhaustive-types"))] + _ => unreachable!("new PDU version"), + } + } + + fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch { + match &self.rest { + Pdu::RoomV1Pdu(ev) => ev.origin_server_ts, + Pdu::RoomV3Pdu(ev) => ev.origin_server_ts, + #[cfg(not(feature = "unstable-exhaustive-types"))] + _ => unreachable!("new PDU version"), + } + } + + fn state_key(&self) -> Option<&str> { + match &self.rest { + Pdu::RoomV1Pdu(ev) => ev.state_key.as_deref(), + Pdu::RoomV3Pdu(ev) => ev.state_key.as_deref(), + #[cfg(not(feature = "unstable-exhaustive-types"))] + _ => unreachable!("new PDU version"), + } + } + + fn prev_events(&self) -> Box + Send + '_> { + match &self.rest { + Pdu::RoomV1Pdu(ev) => Box::new(ev.prev_events.iter().map(|(id, _)| id)), + Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter()), + #[cfg(not(feature = "unstable-exhaustive-types"))] + _ => unreachable!("new PDU version"), + } + } + + fn auth_events(&self) -> Box + Send + '_> { + match &self.rest { + Pdu::RoomV1Pdu(ev) => Box::new(ev.auth_events.iter().map(|(id, _)| id)), + Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter()), + #[cfg(not(feature = "unstable-exhaustive-types"))] + _ => unreachable!("new PDU version"), + } + } + + fn redacts(&self) -> Option<&Self::Id> { + match &self.rest { + Pdu::RoomV1Pdu(ev) => ev.redacts.as_ref(), + Pdu::RoomV3Pdu(ev) => ev.redacts.as_ref(), + #[cfg(not(feature = "unstable-exhaustive-types"))] + _ => unreachable!("new PDU version"), + } + } + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub(crate) struct PduEvent { + pub(crate) event_id: OwnedEventId, + #[serde(flatten)] + pub(crate) rest: Pdu, + } +} diff --git a/src/core/matrix/state_res/test_utils.rs b/src/core/state_res/test_utils.rs similarity index 99% rename from src/core/matrix/state_res/test_utils.rs rename to src/core/state_res/test_utils.rs index f2ee4238..d96ee927 100644 --- a/src/core/matrix/state_res/test_utils.rs +++ b/src/core/state_res/test_utils.rs @@ -28,10 +28,7 @@ use serde_json::{ pub(crate) use self::event::PduEvent; use super::auth_types_for_event; -use crate::{ - Result, info, - matrix::{Event, EventTypeExt, StateMap}, -}; +use crate::{Event, EventTypeExt, Result, StateMap, info}; static SERVER_TIMESTAMP: AtomicU64 = AtomicU64::new(0); diff --git a/src/core/utils/bytes.rs b/src/core/utils/bytes.rs index 507b9b9a..04101be4 100644 --- a/src/core/utils/bytes.rs +++ b/src/core/utils/bytes.rs @@ -17,13 +17,15 @@ pub fn from_str(str: &str) -> Result { Ok(bytes) } -/// Output a human-readable size string w/ iec-unit suffix +/// Output a human-readable size string w/ si-unit suffix #[inline] #[must_use] pub fn pretty(bytes: usize) -> String { + const SI_UNITS: bool = true; + let bytes: u64 = bytes.try_into().expect("failed to convert usize to u64"); - ByteSize::b(bytes).display().iec().to_string() + bytesize::to_string(bytes, SI_UNITS) } #[inline] diff --git a/src/core/utils/future/mod.rs b/src/core/utils/future/mod.rs index 4edd0102..e1d96941 100644 --- a/src/core/utils/future/mod.rs +++ b/src/core/utils/future/mod.rs @@ -1,11 +1,9 @@ mod bool_ext; mod ext_ext; mod option_ext; -mod option_stream; mod try_ext_ext; pub use bool_ext::{BoolExt, and, or}; pub use ext_ext::ExtExt; pub use option_ext::OptionExt; -pub use option_stream::OptionStream; pub use try_ext_ext::TryExtExt; diff --git a/src/core/utils/future/option_ext.rs b/src/core/utils/future/option_ext.rs index 920dd044..d553e5dc 100644 --- a/src/core/utils/future/option_ext.rs +++ b/src/core/utils/future/option_ext.rs @@ -11,14 +11,11 @@ pub trait OptionExt { impl OptionExt for OptionFuture where Fut: Future + Send, - T: Send, { - #[inline] fn is_none_or(self, f: impl FnOnce(&T) -> bool + Send) -> impl Future + Send { self.map(|o| o.as_ref().is_none_or(f)) } - #[inline] fn is_some_and(self, f: impl FnOnce(&T) -> bool + Send) -> impl Future + Send { self.map(|o| o.as_ref().is_some_and(f)) } diff --git a/src/core/utils/future/option_stream.rs b/src/core/utils/future/option_stream.rs deleted file mode 100644 index 81130c87..00000000 --- a/src/core/utils/future/option_stream.rs +++ /dev/null @@ -1,25 +0,0 @@ -use futures::{Future, FutureExt, Stream, StreamExt, future::OptionFuture}; - -use super::super::IterStream; - -pub trait OptionStream { - fn stream(self) -> impl Stream + Send; -} - -impl OptionStream for OptionFuture -where - Fut: Future + Send, - S: Stream + Send, - O: IntoIterator + Send, - ::IntoIter: Send, - T: Send, -{ - #[inline] - fn stream(self) -> impl Stream + Send { - self.map(|opt| opt.map(|(curr, next)| curr.into_iter().stream().chain(next))) - .map(Option::into_iter) - .map(IterStream::stream) - .flatten_stream() - .flatten() - } -} diff --git a/src/core/utils/mod.rs b/src/core/utils/mod.rs index 117fb739..53460c59 100644 --- a/src/core/utils/mod.rs +++ b/src/core/utils/mod.rs @@ -49,10 +49,10 @@ pub fn exchange(state: &mut T, source: T) -> T { std::mem::replace(state, sou #[macro_export] macro_rules! extract_variant { - ( $e:expr_2021, $( $variant:path )|* ) => { + ($e:expr_2021, $variant:path) => { match $e { - $( $variant(value) => Some(value), )* - _ => None, + | $variant(value) => Some(value), + | _ => None, } }; } @@ -173,7 +173,6 @@ macro_rules! is_equal { /// Functor for |x| *x.$i #[macro_export] -#[collapse_debuginfo(yes)] macro_rules! deref_at { ($idx:tt) => { |t| *t.$idx @@ -182,7 +181,6 @@ macro_rules! deref_at { /// Functor for |ref x| x.$i #[macro_export] -#[collapse_debuginfo(yes)] macro_rules! ref_at { ($idx:tt) => { |ref t| &t.$idx @@ -191,7 +189,6 @@ macro_rules! ref_at { /// Functor for |&x| x.$i #[macro_export] -#[collapse_debuginfo(yes)] macro_rules! val_at { ($idx:tt) => { |&t| t.$idx @@ -200,7 +197,6 @@ macro_rules! val_at { /// Functor for |x| x.$i #[macro_export] -#[collapse_debuginfo(yes)] macro_rules! at { ($idx:tt) => { |t| t.$idx diff --git a/src/core/utils/sys/storage.rs b/src/core/utils/sys/storage.rs index 452b04b2..b11df7bb 100644 --- a/src/core/utils/sys/storage.rs +++ b/src/core/utils/sys/storage.rs @@ -123,7 +123,10 @@ pub fn dev_from_path(path: &Path) -> Result<(dev_t, dev_t)> { let stat = fs::metadata(path)?; let dev_id = stat.dev().try_into()?; - let (major, minor) = (libc::major(dev_id), libc::minor(dev_id)); + + // SAFETY: These functions may not need to be marked as unsafe. + // see: https://github.com/rust-lang/libc/issues/3759 + let (major, minor) = unsafe { (libc::major(dev_id), libc::minor(dev_id)) }; Ok((major.try_into()?, minor.try_into()?)) } diff --git a/src/database/benches.rs b/src/database/benches.rs deleted file mode 100644 index 56d1411c..00000000 --- a/src/database/benches.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[cfg(conduwuit_bench)] -extern crate test; - -#[cfg(conduwuit_bench)] -#[cfg_attr(conduwuit_bench, bench)] -fn ser_str(b: &mut test::Bencher) { - use conduwuit::ruma::{RoomId, UserId}; - - use crate::ser::serialize_to_vec; - - let user_id: &UserId = "@user:example.com".try_into().unwrap(); - let room_id: &RoomId = "!room:example.com".try_into().unwrap(); - b.iter(|| { - let key = (user_id, room_id); - let _s = serialize_to_vec(key).expect("failed to serialize user_id"); - }); -} diff --git a/src/database/engine/cf_opts.rs b/src/database/engine/cf_opts.rs index 7ceec722..5ddb9473 100644 --- a/src/database/engine/cf_opts.rs +++ b/src/database/engine/cf_opts.rs @@ -1,8 +1,8 @@ use conduwuit::{Config, Result, err, utils::math::Expected}; use rocksdb::{ BlockBasedIndexType, BlockBasedOptions, BlockBasedPinningTier, Cache, - DBCompressionType as CompressionType, DataBlockIndexType, FifoCompactOptions, - LruCacheOptions, Options, UniversalCompactOptions, UniversalCompactionStopStyle, + DBCompressionType as CompressionType, DataBlockIndexType, LruCacheOptions, Options, + UniversalCompactOptions, UniversalCompactionStopStyle, }; use super::descriptor::{CacheDisp, Descriptor}; @@ -16,7 +16,7 @@ pub(super) const SENTINEL_COMPRESSION_LEVEL: i32 = 32767; pub(crate) fn cf_options(ctx: &Context, opts: Options, desc: &Descriptor) -> Result { let cache = get_cache(ctx, desc); let config = &ctx.server.config; - descriptor_cf_options(opts, *desc, config, cache.as_ref()) + descriptor_cf_options(opts, desc.clone(), config, cache.as_ref()) } fn descriptor_cf_options( @@ -46,7 +46,6 @@ fn descriptor_cf_options( opts.set_compaction_style(desc.compaction); opts.set_compaction_pri(desc.compaction_pri); opts.set_universal_compaction_options(&uc_options(&desc)); - opts.set_fifo_compaction_options(&fifo_options(&desc)); let compression_shape: Vec<_> = desc .compression_shape @@ -143,13 +142,6 @@ fn set_compression(desc: &mut Descriptor, config: &Config) { } } -fn fifo_options(desc: &Descriptor) -> FifoCompactOptions { - let mut opts = FifoCompactOptions::default(); - opts.set_max_table_files_size(desc.limit_size); - - opts -} - fn uc_options(desc: &Descriptor) -> UniversalCompactOptions { let mut opts = UniversalCompactOptions::default(); opts.set_stop_style(UniversalCompactionStopStyle::Total); diff --git a/src/database/engine/descriptor.rs b/src/database/engine/descriptor.rs index 2274da9c..816555d2 100644 --- a/src/database/engine/descriptor.rs +++ b/src/database/engine/descriptor.rs @@ -6,8 +6,14 @@ use rocksdb::{ use super::cf_opts::SENTINEL_COMPRESSION_LEVEL; -/// Column Descriptor #[derive(Debug, Clone, Copy)] +pub(crate) enum CacheDisp { + Unique, + Shared, + SharedWith(&'static str), +} + +#[derive(Debug, Clone)] pub(crate) struct Descriptor { pub(crate) name: &'static str, pub(crate) dropped: bool, @@ -24,7 +30,6 @@ pub(crate) struct Descriptor { pub(crate) file_shape: i32, pub(crate) level0_width: i32, pub(crate) merge_width: (i32, i32), - pub(crate) limit_size: u64, pub(crate) ttl: u64, pub(crate) compaction: CompactionStyle, pub(crate) compaction_pri: CompactionPri, @@ -41,16 +46,7 @@ pub(crate) struct Descriptor { pub(crate) auto_readahead_max: usize, } -/// Cache Disposition -#[derive(Debug, Clone, Copy)] -pub(crate) enum CacheDisp { - Unique, - Shared, - SharedWith(&'static str), -} - -/// Base descriptor supplying common defaults to all derived descriptors. -static BASE: Descriptor = Descriptor { +pub(crate) static BASE: Descriptor = Descriptor { name: EMPTY, dropped: false, cache_disp: CacheDisp::Shared, @@ -66,7 +62,6 @@ static BASE: Descriptor = Descriptor { file_shape: 2, level0_width: 2, merge_width: (2, 16), - limit_size: 0, ttl: 60 * 60 * 24 * 21, compaction: CompactionStyle::Level, compaction_pri: CompactionPri::MinOverlappingRatio, @@ -83,10 +78,6 @@ static BASE: Descriptor = Descriptor { auto_readahead_max: 1024 * 1024 * 2, }; -/// Tombstone descriptor for columns which have been or will be deleted. -pub(crate) static DROPPED: Descriptor = Descriptor { dropped: true, ..BASE }; - -/// Descriptor for large datasets with random updates across the keyspace. pub(crate) static RANDOM: Descriptor = Descriptor { compaction_pri: CompactionPri::OldestSmallestSeqFirst, write_size: 1024 * 1024 * 32, @@ -97,7 +88,6 @@ pub(crate) static RANDOM: Descriptor = Descriptor { ..BASE }; -/// Descriptor for large datasets with updates to the end of the keyspace. pub(crate) static SEQUENTIAL: Descriptor = Descriptor { compaction_pri: CompactionPri::OldestLargestSeqFirst, write_size: 1024 * 1024 * 64, @@ -111,7 +101,6 @@ pub(crate) static SEQUENTIAL: Descriptor = Descriptor { ..BASE }; -/// Descriptor for small datasets with random updates across the keyspace. pub(crate) static RANDOM_SMALL: Descriptor = Descriptor { compaction: CompactionStyle::Universal, write_size: 1024 * 1024 * 16, @@ -128,7 +117,6 @@ pub(crate) static RANDOM_SMALL: Descriptor = Descriptor { ..RANDOM }; -/// Descriptor for small datasets with updates to the end of the keyspace. pub(crate) static SEQUENTIAL_SMALL: Descriptor = Descriptor { compaction: CompactionStyle::Universal, write_size: 1024 * 1024 * 16, @@ -144,14 +132,3 @@ pub(crate) static SEQUENTIAL_SMALL: Descriptor = Descriptor { compressed_index: false, ..SEQUENTIAL }; - -/// Descriptor for small persistent caches with random updates. Oldest entries -/// are deleted after limit_size reached. -pub(crate) static RANDOM_SMALL_CACHE: Descriptor = Descriptor { - compaction: CompactionStyle::Fifo, - cache_disp: CacheDisp::Unique, - limit_size: 1024 * 1024 * 64, - ttl: 60 * 60 * 24 * 14, - file_shape: 2, - ..RANDOM_SMALL -}; diff --git a/src/database/engine/open.rs b/src/database/engine/open.rs index 84e59a6a..24010c3a 100644 --- a/src/database/engine/open.rs +++ b/src/database/engine/open.rs @@ -101,11 +101,13 @@ fn configure_cfds( debug!("Creating new column {name:?} not previously found in existing database."); }); - let missing_descriptors = missing.clone().map(|_| descriptor::DROPPED); + let missing_descriptors = missing + .clone() + .map(|_| Descriptor { dropped: true, ..descriptor::BASE }); let cfopts: Vec<_> = desc .iter() - .copied() + .cloned() .chain(missing_descriptors) .map(|ref desc| cf_options(ctx, db_opts.clone(), desc)) .collect::>()?; diff --git a/src/database/map.rs b/src/database/map.rs index ed38e1fc..c5a908ba 100644 --- a/src/database/map.rs +++ b/src/database/map.rs @@ -1,4 +1,3 @@ -mod clear; pub mod compact; mod contains; mod count; diff --git a/src/database/map/clear.rs b/src/database/map/clear.rs deleted file mode 100644 index 321ec79c..00000000 --- a/src/database/map/clear.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::sync::Arc; - -use conduwuit::{ - Result, implement, - utils::stream::{ReadyExt, TryIgnore}, -}; -use futures::{Stream, TryStreamExt}; - -use crate::keyval::Key; - -/// Delete all data stored in this map. !!! USE WITH CAUTION !!! -/// -/// See for_clear() with additional details. -#[implement(super::Map)] -#[tracing::instrument(level = "trace")] -pub async fn clear(self: &Arc) { - self.for_clear().ignore_err().ready_for_each(|_| ()).await; -} - -/// Delete all data stored in this map. !!! USE WITH CAUTION !!! -/// -/// Provides stream of keys undergoing deletion along with any errors. -/// -/// Note this operation applies to a snapshot of the data when invoked. -/// Additional data written during or after this call may be missed. -#[implement(super::Map)] -#[tracing::instrument(level = "trace")] -pub fn for_clear(self: &Arc) -> impl Stream>> + Send { - self.raw_keys().inspect_ok(|key| self.remove(key)) -} diff --git a/src/database/maps.rs b/src/database/maps.rs index 19f9ced4..138bb038 100644 --- a/src/database/maps.rs +++ b/src/database/maps.rs @@ -121,18 +121,14 @@ pub(super) static MAPS: &[Descriptor] = &[ index_size: 512, ..descriptor::SEQUENTIAL }, - Descriptor { - name: "publicroomids", - ..descriptor::RANDOM_SMALL - }, - Descriptor { - name: "pushkey_deviceid", - ..descriptor::RANDOM_SMALL - }, Descriptor { name: "presenceid_presence", ..descriptor::SEQUENTIAL_SMALL }, + Descriptor { + name: "publicroomids", + ..descriptor::RANDOM_SMALL + }, Descriptor { name: "readreceiptid_readreceipt", ..descriptor::RANDOM @@ -233,7 +229,7 @@ pub(super) static MAPS: &[Descriptor] = &[ }, Descriptor { name: "servername_destination", - ..descriptor::RANDOM_SMALL_CACHE + ..descriptor::RANDOM_SMALL }, Descriptor { name: "servername_educount", @@ -241,7 +237,7 @@ pub(super) static MAPS: &[Descriptor] = &[ }, Descriptor { name: "servername_override", - ..descriptor::RANDOM_SMALL_CACHE + ..descriptor::RANDOM_SMALL }, Descriptor { name: "servernameevent_data", diff --git a/src/database/mod.rs b/src/database/mod.rs index ffcefee9..0481d1bd 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -1,5 +1,3 @@ -#![type_length_limit = "3072"] - extern crate conduwuit_core as conduwuit; extern crate rust_rocksdb as rocksdb; @@ -7,8 +5,6 @@ conduwuit::mod_ctor! {} conduwuit::mod_dtor! {} conduwuit::rustc_flags_capture! {} -#[cfg(test)] -mod benches; mod cork; mod de; mod deserialized; diff --git a/src/database/pool.rs b/src/database/pool.rs index 0fa742d1..47e61c30 100644 --- a/src/database/pool.rs +++ b/src/database/pool.rs @@ -12,7 +12,7 @@ use std::{ use async_channel::{QueueStrategy, Receiver, RecvError, Sender}; use conduwuit::{ - Error, Result, Server, debug, err, error, implement, + Error, Result, Server, debug, debug_warn, err, error, implement, result::DebugInspect, smallvec::SmallVec, trace, @@ -245,6 +245,13 @@ async fn execute(&self, queue: &Sender, cmd: Cmd) -> Result { self.queued_max.fetch_max(queue.len(), Ordering::Relaxed); } + if queue.is_full() { + debug_warn!( + capacity = ?queue.capacity(), + "pool queue is full" + ); + } + queue .send(cmd) .await diff --git a/src/database/tests.rs b/src/database/tests.rs index c1a9f47c..140bc56d 100644 --- a/src/database/tests.rs +++ b/src/database/tests.rs @@ -152,8 +152,8 @@ fn ser_json_macro() { let content = serde_json::to_value(content).expect("failed to serialize content"); let sender: &UserId = "@foo:example.com".try_into().unwrap(); let serialized = serialize_to_vec(Json(json!({ - "content": content, "sender": sender, + "content": content, }))) .expect("failed to serialize value"); @@ -325,8 +325,8 @@ fn ser_array() { assert_eq!(&s, &v, "vec serialization does not match"); } +#[cfg(todo)] #[test] -#[ignore] fn de_array() { let a: u64 = 123_456; let b: u64 = 987_654; @@ -357,8 +357,8 @@ fn de_array() { assert_eq!(vec[1], b, "deserialized vec [1] does not match"); } +#[cfg(todo)] #[test] -#[ignore] fn de_complex() { type Key<'a> = (&'a UserId, ArrayVec, &'a RoomId); diff --git a/src/main/clap.rs b/src/main/clap.rs index 707a1c76..c7f33bfe 100644 --- a/src/main/clap.rs +++ b/src/main/clap.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use clap::{ArgAction, Parser}; -use conduwuit_core::{ +use conduwuit::{ Err, Result, config::{Figment, FigmentValue}, err, toml, @@ -12,12 +12,7 @@ use conduwuit_core::{ /// Commandline arguments #[derive(Parser, Debug)] -#[clap( - about, - long_about = None, - name = "conduwuit", - version = conduwuit_core::version(), -)] +#[clap(version = conduwuit::version(), about, long_about = None, name = "conduwuit")] pub(crate) struct Args { #[arg(short, long)] /// Path to the config TOML file (optional) @@ -27,14 +22,6 @@ pub(crate) struct Args { #[arg(long, short('O'))] pub(crate) option: Vec, - /// Run in a stricter read-only --maintenance mode. - #[arg(long)] - pub(crate) read_only: bool, - - /// Run in maintenance mode while refusing connections. - #[arg(long)] - pub(crate) maintenance: bool, - #[cfg(feature = "console")] /// Activate admin command console automatically after startup. #[arg(long, num_args(0))] @@ -129,15 +116,6 @@ pub(super) fn parse() -> Args { Args::parse() } /// Synthesize any command line options with configuration file options. pub(crate) fn update(mut config: Figment, args: &Args) -> Result { - if args.read_only { - config = config.join(("rocksdb_read_only", true)); - } - - if args.maintenance || args.read_only { - config = config.join(("startup_netburst", false)); - config = config.join(("listening", false)); - } - #[cfg(feature = "console")] // Indicate the admin console should be spawned automatically if the // configuration file hasn't already. diff --git a/src/main/logging.rs b/src/main/logging.rs index eeeda127..7ce86d56 100644 --- a/src/main/logging.rs +++ b/src/main/logging.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use conduwuit_core::{ +use conduwuit::{ Result, config::Config, debug_warn, err, diff --git a/src/main/main.rs b/src/main/main.rs index 1a9d3fe4..2bfc3c06 100644 --- a/src/main/main.rs +++ b/src/main/main.rs @@ -1,5 +1,3 @@ -#![type_length_limit = "49152"] //TODO: reduce me - pub(crate) mod clap; mod logging; mod mods; @@ -9,21 +7,24 @@ mod sentry; mod server; mod signal; +extern crate conduwuit_core as conduwuit; + use std::sync::{Arc, atomic::Ordering}; -use conduwuit_core::{Error, Result, debug_info, error, rustc_flags_capture}; +use conduwuit::{Error, Result, debug_info, error, rustc_flags_capture}; use server::Server; rustc_flags_capture! {} -fn main() -> Result { +fn main() -> Result<(), Error> { let args = clap::parse(); let runtime = runtime::new(&args)?; let server = Server::new(&args, Some(runtime.handle()))?; - runtime.spawn(signal::signal(server.clone())); runtime.block_on(async_main(&server))?; - runtime::shutdown(&server, runtime); + + // explicit drop here to trace thread and tls dtors + drop(runtime); #[cfg(unix)] if server.server.restarting.load(Ordering::Acquire) { diff --git a/src/main/mods.rs b/src/main/mods.rs index d585a381..6dc79b2f 100644 --- a/src/main/mods.rs +++ b/src/main/mods.rs @@ -9,13 +9,13 @@ use std::{ sync::{Arc, atomic::Ordering}, }; -use conduwuit_core::{Error, Result, debug, error, mods}; +use conduwuit::{Error, Result, debug, error, mods}; use conduwuit_service::Services; use crate::Server; type StartFuncResult = Pin>> + Send>>; -type StartFuncProto = fn(&Arc) -> StartFuncResult; +type StartFuncProto = fn(&Arc) -> StartFuncResult; type RunFuncResult = Pin> + Send>>; type RunFuncProto = fn(&Arc) -> RunFuncResult; @@ -34,8 +34,8 @@ const MODULE_NAMES: &[&str] = &[ ]; #[cfg(panic_trap)] -conduwuit_core::mod_init! {{ - conduwuit_core::debug::set_panic_trap(); +conduwuit::mod_init! {{ + conduwuit::debug::set_panic_trap(); }} pub(crate) async fn run(server: &Arc, starts: bool) -> Result<(bool, bool), Error> { diff --git a/src/main/restart.rs b/src/main/restart.rs index b9d1dc94..e6f45b82 100644 --- a/src/main/restart.rs +++ b/src/main/restart.rs @@ -2,7 +2,7 @@ use std::{env, os::unix::process::CommandExt, process::Command}; -use conduwuit_core::{debug, info, utils}; +use conduwuit::{debug, info, utils}; #[cold] pub(super) fn restart() -> ! { diff --git a/src/main/runtime.rs b/src/main/runtime.rs index 1c58ea81..b3174e9c 100644 --- a/src/main/runtime.rs +++ b/src/main/runtime.rs @@ -1,7 +1,7 @@ use std::{ iter::once, sync::{ - Arc, OnceLock, + OnceLock, atomic::{AtomicUsize, Ordering}, }, thread, @@ -9,20 +9,19 @@ use std::{ }; #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] -use conduwuit_core::result::LogDebugErr; -use conduwuit_core::{ - Result, debug, is_true, +use conduwuit::result::LogDebugErr; +use conduwuit::{ + Result, is_true, utils::sys::compute::{nth_core_available, set_affinity}, }; use tokio::runtime::Builder; -use crate::{clap::Args, server::Server}; +use crate::clap::Args; const WORKER_NAME: &str = "conduwuit:worker"; const WORKER_MIN: usize = 2; const WORKER_KEEPALIVE: u64 = 36; const MAX_BLOCKING_THREADS: usize = 1024; -const SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(10000); #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] const DISABLE_MUZZY_THRESHOLD: usize = 4; @@ -62,8 +61,6 @@ pub(super) fn new(args: &Args) -> Result { #[cfg(tokio_unstable)] builder .on_task_spawn(task_spawn) - .on_before_task_poll(task_enter) - .on_after_task_poll(task_leave) .on_task_terminate(task_terminate); #[cfg(tokio_unstable)] @@ -84,42 +81,6 @@ fn enable_histogram(builder: &mut Builder, args: &Args) { .metrics_poll_time_histogram_configuration(linear); } -#[cfg(tokio_unstable)] -#[tracing::instrument(name = "stop", level = "info", skip_all)] -pub(super) fn shutdown(server: &Arc, runtime: tokio::runtime::Runtime) { - use conduwuit_core::event; - use tracing::Level; - - // The final metrics output is promoted to INFO when tokio_unstable is active in - // a release/bench mode and DEBUG is likely optimized out - const LEVEL: Level = if cfg!(debug_assertions) { - Level::DEBUG - } else { - Level::INFO - }; - - debug!( - timeout = ?SHUTDOWN_TIMEOUT, - "Waiting for runtime..." - ); - - runtime.shutdown_timeout(SHUTDOWN_TIMEOUT); - let runtime_metrics = server.server.metrics.runtime_interval().unwrap_or_default(); - - event!(LEVEL, ?runtime_metrics, "Final runtime metrics"); -} - -#[cfg(not(tokio_unstable))] -#[tracing::instrument(name = "stop", level = "info", skip_all)] -pub(super) fn shutdown(_server: &Arc, runtime: tokio::runtime::Runtime) { - debug!( - timeout = ?SHUTDOWN_TIMEOUT, - "Waiting for runtime..." - ); - - runtime.shutdown_timeout(SHUTDOWN_TIMEOUT); -} - #[tracing::instrument( name = "fork", level = "debug", @@ -161,7 +122,7 @@ fn set_worker_affinity() { #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] fn set_worker_mallctl(id: usize) { - use conduwuit_core::alloc::je::{ + use conduwuit::alloc::je::{ is_affine_arena, this_thread::{set_arena, set_muzzy_decay}, }; @@ -174,8 +135,7 @@ fn set_worker_mallctl(id: usize) { .get() .expect("GC_MUZZY initialized by runtime::new()"); - let muzzy_auto_disable = - conduwuit_core::utils::available_parallelism() >= DISABLE_MUZZY_THRESHOLD; + let muzzy_auto_disable = conduwuit::utils::available_parallelism() >= DISABLE_MUZZY_THRESHOLD; if matches!(muzzy_option, Some(false) | None if muzzy_auto_disable) { set_muzzy_decay(-1).log_debug_err().ok(); } @@ -228,7 +188,7 @@ fn thread_park() { fn gc_on_park() { #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] - conduwuit_core::alloc::je::this_thread::decay() + conduwuit::alloc::je::this_thread::decay() .log_debug_err() .ok(); } @@ -254,25 +214,3 @@ fn task_spawn(meta: &tokio::runtime::TaskMeta<'_>) {} ), )] fn task_terminate(meta: &tokio::runtime::TaskMeta<'_>) {} - -#[cfg(tokio_unstable)] -#[tracing::instrument( - name = "enter", - level = "trace", - skip_all, - fields( - id = %meta.id() - ), -)] -fn task_enter(meta: &tokio::runtime::TaskMeta<'_>) {} - -#[cfg(tokio_unstable)] -#[tracing::instrument( - name = "leave", - level = "trace", - skip_all, - fields( - id = %meta.id() - ), -)] -fn task_leave(meta: &tokio::runtime::TaskMeta<'_>) {} diff --git a/src/main/sentry.rs b/src/main/sentry.rs index 68f12eb7..1ea1f3ae 100644 --- a/src/main/sentry.rs +++ b/src/main/sentry.rs @@ -5,7 +5,7 @@ use std::{ sync::{Arc, OnceLock}, }; -use conduwuit_core::{config::Config, debug, trace}; +use conduwuit::{config::Config, debug, trace}; use sentry::{ Breadcrumb, ClientOptions, Level, types::{ @@ -43,7 +43,7 @@ fn options(config: &Config) -> ClientOptions { traces_sample_rate: config.sentry_traces_sample_rate, debug: cfg!(debug_assertions), release: sentry::release_name!(), - user_agent: conduwuit_core::version::user_agent().into(), + user_agent: conduwuit::version::user_agent().into(), attach_stacktrace: config.sentry_attach_stacktrace, before_send: Some(Arc::new(before_send)), before_breadcrumb: Some(Arc::new(before_breadcrumb)), diff --git a/src/main/server.rs b/src/main/server.rs index 8f697ca4..44ca69b0 100644 --- a/src/main/server.rs +++ b/src/main/server.rs @@ -1,6 +1,6 @@ use std::{path::PathBuf, sync::Arc}; -use conduwuit_core::{ +use conduwuit::{ Error, Result, config::Config, info, @@ -14,7 +14,7 @@ use crate::{clap::Args, logging::TracingFlameGuard}; /// Server runtime state; complete pub(crate) struct Server { /// Server runtime state; public portion - pub(crate) server: Arc, + pub(crate) server: Arc, pub(crate) services: Mutex>>, @@ -25,7 +25,7 @@ pub(crate) struct Server { #[cfg(all(conduwuit_mods, feature = "conduwuit_mods"))] // Module instances; TODO: move to mods::loaded mgmt vector - pub(crate) mods: tokio::sync::RwLock>, + pub(crate) mods: tokio::sync::RwLock>, } impl Server { @@ -66,11 +66,11 @@ impl Server { database_path = ?config.database_path, log_levels = %config.log, "{}", - conduwuit_core::version(), + conduwuit::version(), ); Ok(Arc::new(Self { - server: Arc::new(conduwuit_core::Server::new(config, runtime.cloned(), Log { + server: Arc::new(conduwuit::Server::new(config, runtime.cloned(), Log { reload: tracing_reload_handle, capture, })), diff --git a/src/main/signal.rs b/src/main/signal.rs index a5d07774..343b95c9 100644 --- a/src/main/signal.rs +++ b/src/main/signal.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use conduwuit_core::{debug_error, trace, warn}; +use conduwuit::{debug_error, trace, warn}; use tokio::signal; use super::server::Server; diff --git a/src/router/mod.rs b/src/router/mod.rs index 7038c5df..f64dcb67 100644 --- a/src/router/mod.rs +++ b/src/router/mod.rs @@ -1,5 +1,3 @@ -#![type_length_limit = "32768"] //TODO: reduce me - mod layers; mod request; mod router; diff --git a/src/router/request.rs b/src/router/request.rs index dba90324..00769b3f 100644 --- a/src/router/request.rs +++ b/src/router/request.rs @@ -37,7 +37,7 @@ pub(crate) async fn handle( let parent = Span::current(); let task = services.server.runtime().spawn(async move { tokio::select! { - response = execute(&services_, req, next, &parent) => response, + response = execute(&services_, req, next, parent) => response, response = services_.server.until_shutdown() .then(|()| { let timeout = services_.server.config.client_shutdown_timeout; @@ -79,7 +79,7 @@ async fn execute( services: &Arc, req: http::Request, next: axum::middleware::Next, - parent: &Span, + parent: Span, ) -> Response { #[cfg(debug_assertions)] conduwuit::defer! {{ diff --git a/src/router/run.rs b/src/router/run.rs index ff54594f..31789626 100644 --- a/src/router/run.rs +++ b/src/router/run.rs @@ -77,10 +77,6 @@ pub(crate) async fn start(server: Arc) -> Result> { pub(crate) async fn stop(services: Arc) -> Result<()> { debug!("Shutting down..."); - #[cfg(all(feature = "systemd", target_os = "linux"))] - sd_notify::notify(true, &[sd_notify::NotifyState::Stopping]) - .expect("failed to notify systemd of stopping state"); - // Wait for all completions before dropping or we'll lose them to the module // unload and explode. services.stop().await; diff --git a/src/service/admin/grant.rs b/src/service/admin/grant.rs index 6780b7ae..5173987a 100644 --- a/src/service/admin/grant.rs +++ b/src/service/admin/grant.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use conduwuit::{Err, Result, debug_info, debug_warn, error, implement, matrix::pdu::PduBuilder}; +use conduwuit::{Err, Result, debug_info, debug_warn, error, implement}; use ruma::{ RoomId, UserId, events::{ @@ -14,6 +14,8 @@ use ruma::{ }, }; +use crate::pdu::PduBuilder; + /// Invite the user to the conduwuit admin room. /// /// This is equivalent to granting server admin privileges. diff --git a/src/service/client/mod.rs b/src/service/client/mod.rs index 1aeeb492..d51e5721 100644 --- a/src/service/client/mod.rs +++ b/src/service/client/mod.rs @@ -56,7 +56,7 @@ impl crate::Service for Service { .build()?, well_known: base(config)? - .dns_resolver(resolver.resolver.clone()) + .dns_resolver(resolver.resolver.hooked.clone()) .connect_timeout(Duration::from_secs(config.well_known_conn_timeout)) .read_timeout(Duration::from_secs(config.well_known_timeout)) .timeout(Duration::from_secs(config.well_known_timeout)) diff --git a/src/service/federation/execute.rs b/src/service/federation/execute.rs index 97314ffb..63f2ccfb 100644 --- a/src/service/federation/execute.rs +++ b/src/service/federation/execute.rs @@ -69,7 +69,7 @@ where .server .config .forbidden_remote_server_names - .is_match(dest.host()) + .contains(dest) { return Err!(Request(Forbidden(debug_warn!("Federation with {dest} is not allowed.")))); } diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index a7a9be9d..74f83228 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -7,7 +7,6 @@ use std::{ time::Instant, }; -use async_trait::async_trait; use conduwuit::{Result, Server, error, utils::bytes::pretty}; use data::Data; use regex::RegexSet; @@ -28,7 +27,6 @@ pub struct Service { type RateLimitState = (Instant, u32); // Time if last failed try, number of failed tries -#[async_trait] impl crate::Service for Service { fn build(args: crate::Args<'_>) -> Result> { let db = Data::new(&args); @@ -75,7 +73,7 @@ impl crate::Service for Service { })) } - async fn memory_usage(&self, out: &mut (dyn Write + Send)) -> Result { + fn memory_usage(&self, out: &mut dyn Write) -> Result { let (ber_count, ber_bytes) = self.bad_event_ratelimiter.read()?.iter().fold( (0_usize, 0_usize), |(mut count, mut bytes), (event_id, _)| { @@ -91,7 +89,7 @@ impl crate::Service for Service { Ok(()) } - async fn clear_cache(&self) { + fn clear_cache(&self) { self.bad_event_ratelimiter .write() .expect("locked for writing") @@ -111,6 +109,20 @@ impl Service { #[inline] pub fn server_name(&self) -> &ServerName { self.server.name.as_ref() } + pub fn allow_registration(&self) -> bool { self.server.config.allow_registration } + + pub fn allow_guest_registration(&self) -> bool { self.server.config.allow_guest_registration } + + pub fn allow_guests_auto_join_rooms(&self) -> bool { + self.server.config.allow_guests_auto_join_rooms + } + + pub fn log_guest_registrations(&self) -> bool { self.server.config.log_guest_registrations } + + pub fn allow_encryption(&self) -> bool { self.server.config.allow_encryption } + + pub fn allow_federation(&self) -> bool { self.server.config.allow_federation } + pub fn allow_public_room_directory_over_federation(&self) -> bool { self.server .config @@ -169,6 +181,22 @@ impl Service { pub fn forbidden_usernames(&self) -> &RegexSet { &self.server.config.forbidden_usernames } + pub fn allow_local_presence(&self) -> bool { self.server.config.allow_local_presence } + + pub fn allow_incoming_presence(&self) -> bool { self.server.config.allow_incoming_presence } + + pub fn allow_outgoing_presence(&self) -> bool { self.server.config.allow_outgoing_presence } + + pub fn allow_incoming_read_receipts(&self) -> bool { + self.server.config.allow_incoming_read_receipts + } + + pub fn allow_outgoing_read_receipts(&self) -> bool { + self.server.config.allow_outgoing_read_receipts + } + + pub fn block_non_admin_invites(&self) -> bool { self.server.config.block_non_admin_invites } + /// checks if `user_id` is local to us via server_name comparison #[inline] pub fn user_is_local(&self, user_id: &UserId) -> bool { diff --git a/src/service/media/preview.rs b/src/service/media/preview.rs index 91660a58..ba5be7d4 100644 --- a/src/service/media/preview.rs +++ b/src/service/media/preview.rs @@ -256,7 +256,7 @@ pub fn url_preview_allowed(&self, url: &Url) -> bool { if allowlist_url_contains .iter() - .any(|url_s| url.to_string().contains(url_s)) + .any(|url_s| url.to_string().contains(&url_s.to_string())) { debug!("URL {} is allowed by url_preview_url_contains_allowlist (check 4/4)", &host); return true; diff --git a/src/service/media/remote.rs b/src/service/media/remote.rs index cdcb429e..b6c853d2 100644 --- a/src/service/media/remote.rs +++ b/src/service/media/remote.rs @@ -426,13 +426,7 @@ fn check_fetch_authorized(&self, mxc: &Mxc<'_>) -> Result<()> { .server .config .prevent_media_downloads_from - .is_match(mxc.server_name.host()) - || self - .services - .server - .config - .forbidden_remote_server_names - .is_match(mxc.server_name.host()) + .contains(mxc.server_name) { // we'll lie to the client and say the blocked server's media was not found and // log. the client has no way of telling anyways so this is a security bonus. diff --git a/src/service/mod.rs b/src/service/mod.rs index 63a51213..0bde0255 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -1,4 +1,3 @@ -#![type_length_limit = "2048"] #![allow(refining_impl_trait)] mod manager; @@ -31,6 +30,7 @@ pub mod users; extern crate conduwuit_core as conduwuit; extern crate conduwuit_database as database; +pub use conduwuit::{PduBuilder, PduCount, PduEvent, pdu}; pub(crate) use service::{Args, Dep, Service}; pub use crate::services::Services; diff --git a/src/service/pusher/mod.rs b/src/service/pusher/mod.rs index 27490fb8..2b269b3d 100644 --- a/src/service/pusher/mod.rs +++ b/src/service/pusher/mod.rs @@ -10,7 +10,7 @@ use database::{Deserialized, Ignore, Interfix, Json, Map}; use futures::{Stream, StreamExt}; use ipaddress::IPAddress; use ruma::{ - DeviceId, OwnedDeviceId, RoomId, UInt, UserId, + RoomId, UInt, UserId, api::{ IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken, client::push::{Pusher, PusherKind, set_pusher}, @@ -48,7 +48,6 @@ struct Services { struct Data { senderkey_pusher: Arc, - pushkey_deviceid: Arc, } impl crate::Service for Service { @@ -56,7 +55,6 @@ impl crate::Service for Service { Ok(Arc::new(Self { db: Data { senderkey_pusher: args.db["senderkey_pusher"].clone(), - pushkey_deviceid: args.db["pushkey_deviceid"].clone(), }, services: Services { globals: args.depend::("globals"), @@ -77,7 +75,6 @@ impl Service { pub async fn set_pusher( &self, sender: &UserId, - sender_device: &DeviceId, pusher: &set_pusher::v3::PusherAction, ) -> Result { match pusher { @@ -126,35 +123,24 @@ impl Service { } } - let pushkey = data.pusher.ids.pushkey.as_str(); - let key = (sender, pushkey); + let key = (sender, data.pusher.ids.pushkey.as_str()); self.db.senderkey_pusher.put(key, Json(pusher)); - self.db.pushkey_deviceid.insert(pushkey, sender_device); }, | set_pusher::v3::PusherAction::Delete(ids) => { - self.delete_pusher(sender, ids.pushkey.as_str()).await; + let key = (sender, ids.pushkey.as_str()); + self.db.senderkey_pusher.del(key); + + self.services + .sending + .cleanup_events(None, Some(sender), Some(ids.pushkey.as_str())) + .await + .ok(); }, } Ok(()) } - pub async fn delete_pusher(&self, sender: &UserId, pushkey: &str) { - let key = (sender, pushkey); - self.db.senderkey_pusher.del(key); - self.db.pushkey_deviceid.remove(pushkey); - - self.services - .sending - .cleanup_events(None, Some(sender), Some(pushkey)) - .await - .ok(); - } - - pub async fn get_pusher_device(&self, pushkey: &str) -> Result { - self.db.pushkey_deviceid.get(pushkey).await.deserialized() - } - pub async fn get_pusher(&self, sender: &UserId, pushkey: &str) -> Result { let senderkey = (sender, pushkey); self.db diff --git a/src/service/resolver/actual.rs b/src/service/resolver/actual.rs index 0151c4d7..b037cf77 100644 --- a/src/service/resolver/actual.rs +++ b/src/service/resolver/actual.rs @@ -3,9 +3,9 @@ use std::{ net::{IpAddr, SocketAddr}, }; -use conduwuit::{Err, Result, debug, debug_info, err, error, trace}; +use conduwuit::{Err, Result, debug, debug_error, debug_info, debug_warn, err, error, trace}; use futures::{FutureExt, TryFutureExt}; -use hickory_resolver::ResolveError; +use hickory_resolver::error::ResolveError; use ipaddress::IPAddress; use ruma::ServerName; @@ -72,9 +72,6 @@ impl super::Service { if let Some(pos) = dest.as_str().find(':') { self.actual_dest_2(dest, cache, pos).await? } else { - self.conditional_query_and_cache(dest.as_str(), 8448, true) - .await?; - self.services.server.check_running()?; match self.request_well_known(dest.as_str()).await? { | Some(delegated) => self.actual_dest_3(&mut host, cache, delegated).await?, @@ -246,6 +243,56 @@ impl super::Service { Ok(add_port_to_hostname(dest.as_str())) } + #[tracing::instrument(name = "well-known", level = "debug", skip(self, dest))] + async fn request_well_known(&self, dest: &str) -> Result> { + self.conditional_query_and_cache(dest, 8448, true).await?; + + self.services.server.check_running()?; + trace!("Requesting well known for {dest}"); + let response = self + .services + .client + .well_known + .get(format!("https://{dest}/.well-known/matrix/server")) + .send() + .await; + + trace!("response: {response:?}"); + if let Err(e) = &response { + debug!("error: {e:?}"); + return Ok(None); + } + + let response = response?; + if !response.status().is_success() { + debug!("response not 2XX"); + return Ok(None); + } + + let text = response.text().await?; + trace!("response text: {text:?}"); + if text.len() >= 12288 { + debug_warn!("response contains junk"); + return Ok(None); + } + + let body: serde_json::Value = serde_json::from_str(&text).unwrap_or_default(); + + let m_server = body + .get("m.server") + .unwrap_or(&serde_json::Value::Null) + .as_str() + .unwrap_or_default(); + + if ruma::identifiers_validation::server_name::validate(m_server).is_err() { + debug_error!("response content missing or invalid"); + return Ok(None); + } + + debug_info!("{dest:?} found at {m_server:?}"); + Ok(Some(m_server.to_owned())) + } + #[inline] async fn conditional_query_and_cache( &self, @@ -334,28 +381,25 @@ impl super::Service { } fn handle_resolve_error(e: &ResolveError, host: &'_ str) -> Result<()> { - use hickory_resolver::{ResolveErrorKind::Proto, proto::ProtoErrorKind}; + use hickory_resolver::error::ResolveErrorKind; - match e.kind() { - | Proto(e) => match e.kind() { - | ProtoErrorKind::NoRecordsFound { .. } => { - // Raise to debug_warn if we can find out the result wasn't from cache - debug!(%host, "No DNS records found: {e}"); - Ok(()) - }, - | ProtoErrorKind::Timeout => { - Err!(warn!(%host, "DNS {e}")) - }, - | ProtoErrorKind::NoConnections => { - error!( - "Your DNS server is overloaded and has ran out of connections. It is \ - strongly recommended you remediate this issue to ensure proper \ - federation connectivity." - ); + match *e.kind() { + | ResolveErrorKind::NoRecordsFound { .. } => { + // Raise to debug_warn if we can find out the result wasn't from cache + debug!(%host, "No DNS records found: {e}"); + Ok(()) + }, + | ResolveErrorKind::Timeout => { + Err!(warn!(%host, "DNS {e}")) + }, + | ResolveErrorKind::NoConnections => { + error!( + "Your DNS server is overloaded and has ran out of connections. It is \ + strongly recommended you remediate this issue to ensure proper federation \ + connectivity." + ); - Err!(error!(%host, "DNS error: {e}")) - }, - | _ => Err!(error!(%host, "DNS error: {e}")), + Err!(error!(%host, "DNS error: {e}")) }, | _ => Err!(error!(%host, "DNS error: {e}")), } diff --git a/src/service/resolver/cache.rs b/src/service/resolver/cache.rs index cfea7187..6b05c00c 100644 --- a/src/service/resolver/cache.rs +++ b/src/service/resolver/cache.rs @@ -7,7 +7,7 @@ use conduwuit::{ utils::{math::Expected, rand, stream::TryIgnore}, }; use database::{Cbor, Deserialized, Map}; -use futures::{Stream, StreamExt, future::join}; +use futures::{Stream, StreamExt}; use ruma::ServerName; use serde::{Deserialize, Serialize}; @@ -45,21 +45,6 @@ impl Cache { } } -#[implement(Cache)] -pub async fn clear(&self) { join(self.clear_destinations(), self.clear_overrides()).await; } - -#[implement(Cache)] -pub async fn clear_destinations(&self) { self.destinations.clear().await; } - -#[implement(Cache)] -pub async fn clear_overrides(&self) { self.overrides.clear().await; } - -#[implement(Cache)] -pub fn del_destination(&self, name: &ServerName) { self.destinations.remove(name); } - -#[implement(Cache)] -pub fn del_override(&self, name: &ServerName) { self.overrides.remove(name); } - #[implement(Cache)] pub fn set_destination(&self, name: &ServerName, dest: &CachedDest) { self.destinations.raw_put(name, Cbor(dest)); diff --git a/src/service/resolver/dns.rs b/src/service/resolver/dns.rs index 3a0b2551..98ad7e60 100644 --- a/src/service/resolver/dns.rs +++ b/src/service/resolver/dns.rs @@ -2,19 +2,19 @@ use std::{net::SocketAddr, sync::Arc, time::Duration}; use conduwuit::{Result, Server, err}; use futures::FutureExt; -use hickory_resolver::{TokioResolver, lookup_ip::LookupIp}; +use hickory_resolver::{TokioAsyncResolver, lookup_ip::LookupIp}; use reqwest::dns::{Addrs, Name, Resolve, Resolving}; use super::cache::{Cache, CachedOverride}; pub struct Resolver { - pub(crate) resolver: Arc, + pub(crate) resolver: Arc, pub(crate) hooked: Arc, server: Arc, } pub(crate) struct Hooked { - resolver: Arc, + resolver: Arc, cache: Arc, server: Arc, } @@ -42,7 +42,7 @@ impl Resolver { let mut ns = sys_conf.clone(); if config.query_over_tcp_only { - ns.protocol = hickory_resolver::proto::xfer::Protocol::Tcp; + ns.protocol = hickory_resolver::config::Protocol::Tcp; } ns.trust_negative_responses = !config.query_all_nameservers; @@ -51,7 +51,6 @@ impl Resolver { } opts.cache_size = config.dns_cache_entries as usize; - opts.preserve_intermediates = true; opts.negative_min_ttl = Some(Duration::from_secs(config.dns_min_ttl_nxdomain)); opts.negative_max_ttl = Some(Duration::from_secs(60 * 60 * 24 * 30)); opts.positive_min_ttl = Some(Duration::from_secs(config.dns_min_ttl)); @@ -61,7 +60,8 @@ impl Resolver { opts.try_tcp_on_error = config.dns_tcp_fallback; opts.num_concurrent_reqs = 1; opts.edns0 = true; - opts.case_randomization = true; + opts.shuffle_dns_servers = true; + opts.rotate = true; opts.ip_strategy = match config.ip_lookup_strategy { | 1 => hickory_resolver::config::LookupIpStrategy::Ipv4Only, | 2 => hickory_resolver::config::LookupIpStrategy::Ipv6Only, @@ -69,23 +69,15 @@ impl Resolver { | 4 => hickory_resolver::config::LookupIpStrategy::Ipv6thenIpv4, | _ => hickory_resolver::config::LookupIpStrategy::Ipv4thenIpv6, }; + opts.authentic_data = false; - let rt_prov = hickory_resolver::proto::runtime::TokioRuntimeProvider::new(); - let conn_prov = hickory_resolver::name_server::TokioConnectionProvider::new(rt_prov); - let mut builder = TokioResolver::builder_with_config(conf, conn_prov); - *builder.options_mut() = opts; - let resolver = Arc::new(builder.build()); - + let resolver = Arc::new(TokioAsyncResolver::tokio(conf, opts)); Ok(Arc::new(Self { resolver: resolver.clone(), hooked: Arc::new(Hooked { resolver, cache, server: server.clone() }), server: server.clone(), })) } - - /// Clear the in-memory hickory-dns caches - #[inline] - pub fn clear_cache(&self) { self.resolver.clear_cache(); } } impl Resolve for Resolver { @@ -109,7 +101,7 @@ impl Resolve for Hooked { async fn hooked_resolve( cache: Arc, server: Arc, - resolver: Arc, + resolver: Arc, name: Name, ) -> Result> { match cache.get_override(name.as_str()).await { @@ -133,7 +125,7 @@ async fn hooked_resolve( async fn resolve_to_reqwest( server: Arc, - resolver: Arc, + resolver: Arc, name: Name, ) -> ResolvingResult { use std::{io, io::ErrorKind::Interrupted}; diff --git a/src/service/resolver/mod.rs b/src/service/resolver/mod.rs index c513cec9..2ec9c0ef 100644 --- a/src/service/resolver/mod.rs +++ b/src/service/resolver/mod.rs @@ -2,13 +2,10 @@ pub mod actual; pub mod cache; mod dns; pub mod fed; -#[cfg(test)] mod tests; -mod well_known; use std::sync::Arc; -use async_trait::async_trait; use conduwuit::{Result, Server, arrayvec::ArrayString, utils::MutexMap}; use self::{cache::Cache, dns::Resolver}; @@ -29,7 +26,6 @@ struct Services { type Resolving = MutexMap; type NameBuf = ArrayString<256>; -#[async_trait] impl crate::Service for Service { #[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)] fn build(args: crate::Args<'_>) -> Result> { @@ -45,10 +41,5 @@ impl crate::Service for Service { })) } - async fn clear_cache(&self) { - self.resolver.clear_cache(); - self.cache.clear().await; - } - fn name(&self) -> &str { crate::service::make_name(std::module_path!()) } } diff --git a/src/service/resolver/tests.rs b/src/service/resolver/tests.rs index 068e08bd..6e9d0e71 100644 --- a/src/service/resolver/tests.rs +++ b/src/service/resolver/tests.rs @@ -1,3 +1,5 @@ +#![cfg(test)] + use super::fed::{FedDest, add_port_to_hostname, get_ip_with_port}; #[test] diff --git a/src/service/resolver/well_known.rs b/src/service/resolver/well_known.rs deleted file mode 100644 index 68a8e620..00000000 --- a/src/service/resolver/well_known.rs +++ /dev/null @@ -1,49 +0,0 @@ -use conduwuit::{Result, debug, debug_error, debug_info, debug_warn, implement, trace}; - -#[implement(super::Service)] -#[tracing::instrument(name = "well-known", level = "debug", skip(self, dest))] -pub(super) async fn request_well_known(&self, dest: &str) -> Result> { - trace!("Requesting well known for {dest}"); - let response = self - .services - .client - .well_known - .get(format!("https://{dest}/.well-known/matrix/server")) - .send() - .await; - - trace!("response: {response:?}"); - if let Err(e) = &response { - debug!("error: {e:?}"); - return Ok(None); - } - - let response = response?; - if !response.status().is_success() { - debug!("response not 2XX"); - return Ok(None); - } - - let text = response.text().await?; - trace!("response text: {text:?}"); - if text.len() >= 12288 { - debug_warn!("response contains junk"); - return Ok(None); - } - - let body: serde_json::Value = serde_json::from_str(&text).unwrap_or_default(); - - let m_server = body - .get("m.server") - .unwrap_or(&serde_json::Value::Null) - .as_str() - .unwrap_or_default(); - - if ruma::identifiers_validation::server_name::validate(m_server).is_err() { - debug_error!("response content missing or invalid"); - return Ok(None); - } - - debug_info!("{dest:?} found at {m_server:?}"); - Ok(Some(m_server.to_owned())) -} diff --git a/src/service/rooms/event_handler/fetch_and_handle_outliers.rs b/src/service/rooms/event_handler/fetch_and_handle_outliers.rs index b0a7d827..80e91eff 100644 --- a/src/service/rooms/event_handler/fetch_and_handle_outliers.rs +++ b/src/service/rooms/event_handler/fetch_and_handle_outliers.rs @@ -1,5 +1,6 @@ use std::{ collections::{BTreeMap, HashSet, VecDeque, hash_map}, + sync::Arc, time::Instant, }; @@ -7,6 +8,7 @@ use conduwuit::{ PduEvent, debug, debug_error, debug_warn, implement, pdu, trace, utils::continue_exponential_backoff_secs, warn, }; +use futures::TryFutureExt; use ruma::{ CanonicalJsonValue, OwnedEventId, RoomId, ServerName, api::federation::event::get_event, }; @@ -29,7 +31,7 @@ pub(super) async fn fetch_and_handle_outliers<'a>( events: &'a [OwnedEventId], create_event: &'a PduEvent, room_id: &'a RoomId, -) -> Vec<(PduEvent, Option>)> { +) -> Vec<(Arc, Option>)> { let back_off = |id| match self .services .globals @@ -51,7 +53,7 @@ pub(super) async fn fetch_and_handle_outliers<'a>( // a. Look in the main timeline (pduid_pdu tree) // b. Look at outlier pdu tree // (get_pdu_json checks both) - if let Ok(local_pdu) = self.services.timeline.get_pdu(id).await { + if let Ok(local_pdu) = self.services.timeline.get_pdu(id).map_ok(Arc::new).await { trace!("Found {id} in db"); events_with_auth_events.push((id, Some(local_pdu), vec![])); continue; diff --git a/src/service/rooms/event_handler/fetch_prev.rs b/src/service/rooms/event_handler/fetch_prev.rs index 0f92d6e6..e817430b 100644 --- a/src/service/rooms/event_handler/fetch_prev.rs +++ b/src/service/rooms/event_handler/fetch_prev.rs @@ -1,4 +1,7 @@ -use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; +use std::{ + collections::{BTreeMap, HashMap, HashSet, VecDeque}, + sync::Arc, +}; use conduwuit::{ PduEvent, Result, debug_warn, err, implement, @@ -28,7 +31,7 @@ pub(super) async fn fetch_prev( initial_set: Vec, ) -> Result<( Vec, - HashMap)>, + HashMap, BTreeMap)>, )> { let mut graph: HashMap = HashMap::with_capacity(initial_set.len()); let mut eventid_info = HashMap::new(); diff --git a/src/service/rooms/event_handler/handle_incoming_pdu.rs b/src/service/rooms/event_handler/handle_incoming_pdu.rs index 77cae41d..b437bf2e 100644 --- a/src/service/rooms/event_handler/handle_incoming_pdu.rs +++ b/src/service/rooms/event_handler/handle_incoming_pdu.rs @@ -3,12 +3,9 @@ use std::{ time::Instant, }; -use conduwuit::{ - Err, Result, debug, debug::INFO_SPAN_LEVEL, defer, err, implement, utils::stream::IterStream, - warn, -}; +use conduwuit::{Err, Result, debug, debug::INFO_SPAN_LEVEL, err, implement, warn}; use futures::{ - FutureExt, TryFutureExt, TryStreamExt, + FutureExt, future::{OptionFuture, try_join5}, }; use ruma::{CanonicalJsonValue, EventId, RoomId, ServerName, UserId, events::StateEventType}; @@ -89,7 +86,7 @@ pub async fn handle_incoming_pdu<'a>( .state_accessor .room_state_get(room_id, &StateEventType::RoomCreate, ""); - let (meta_exists, is_disabled, (), (), ref create_event) = try_join5( + let (meta_exists, is_disabled, (), (), create_event) = try_join5( meta_exists, is_disabled, origin_acl_check, @@ -107,7 +104,7 @@ pub async fn handle_incoming_pdu<'a>( } let (incoming_pdu, val) = self - .handle_outlier_pdu(origin, create_event, event_id, room_id, value, false) + .handle_outlier_pdu(origin, &create_event, event_id, room_id, value, false) .await?; // 8. if not timeline event: stop @@ -132,71 +129,66 @@ pub async fn handle_incoming_pdu<'a>( let (sorted_prev_events, mut eventid_info) = self .fetch_prev( origin, - create_event, + &create_event, room_id, first_ts_in_room, incoming_pdu.prev_events.clone(), ) .await?; - debug!( - events = ?sorted_prev_events, - "Handling previous events" - ); - - sorted_prev_events - .iter() - .try_stream() - .map_ok(AsRef::as_ref) - .try_for_each(|prev_id| { - self.handle_prev_pdu( + debug!(events = ?sorted_prev_events, "Got previous events"); + for prev_id in sorted_prev_events { + self.services.server.check_running()?; + if let Err(e) = self + .handle_prev_pdu( origin, event_id, room_id, - eventid_info.remove(prev_id), - create_event, + &mut eventid_info, + &create_event, first_ts_in_room, - prev_id, + &prev_id, ) - .inspect_err(move |e| { - warn!("Prev {prev_id} failed: {e}"); - match self - .services - .globals - .bad_event_ratelimiter - .write() - .expect("locked") - .entry(prev_id.into()) - { - | hash_map::Entry::Vacant(e) => { - e.insert((Instant::now(), 1)); - }, - | hash_map::Entry::Occupied(mut e) => { - let tries = e.get().1.saturating_add(1); - *e.get_mut() = (Instant::now(), tries); - }, - } - }) - .map(|_| self.services.server.check_running()) - }) - .boxed() - .await?; + .await + { + use hash_map::Entry; + + let now = Instant::now(); + warn!("Prev event {prev_id} failed: {e}"); + + match self + .services + .globals + .bad_event_ratelimiter + .write() + .expect("locked") + .entry(prev_id) + { + | Entry::Vacant(e) => { + e.insert((now, 1)); + }, + | Entry::Occupied(mut e) => { + *e.get_mut() = (now, e.get().1.saturating_add(1)); + }, + } + } + } // Done with prev events, now handling the incoming event let start_time = Instant::now(); self.federation_handletime .write() .expect("locked") - .insert(room_id.into(), (event_id.to_owned(), start_time)); + .insert(room_id.to_owned(), (event_id.to_owned(), start_time)); - defer! {{ - self.federation_handletime - .write() - .expect("locked") - .remove(room_id); - }}; + let r = self + .upgrade_outlier_to_timeline_pdu(incoming_pdu, val, &create_event, origin, room_id) + .await; - self.upgrade_outlier_to_timeline_pdu(incoming_pdu, val, create_event, origin, room_id) - .boxed() - .await + self.federation_handletime + .write() + .expect("locked") + .remove(&room_id.to_owned()); + + r } diff --git a/src/service/rooms/event_handler/handle_outlier_pdu.rs b/src/service/rooms/event_handler/handle_outlier_pdu.rs index 5339249d..99e90a50 100644 --- a/src/service/rooms/event_handler/handle_outlier_pdu.rs +++ b/src/service/rooms/event_handler/handle_outlier_pdu.rs @@ -1,9 +1,12 @@ -use std::collections::{BTreeMap, HashMap, hash_map}; +use std::{ + collections::{BTreeMap, HashMap, hash_map}, + sync::Arc, +}; use conduwuit::{ Err, Error, PduEvent, Result, debug, debug_info, err, implement, state_res, trace, warn, }; -use futures::future::ready; +use futures::{TryFutureExt, future::ready}; use ruma::{ CanonicalJsonObject, CanonicalJsonValue, EventId, RoomId, ServerName, api::client::error::ErrorKind, events::StateEventType, @@ -21,7 +24,7 @@ pub(super) async fn handle_outlier_pdu<'a>( room_id: &'a RoomId, mut value: CanonicalJsonObject, auth_events_known: bool, -) -> Result<(PduEvent, BTreeMap)> { +) -> Result<(Arc, BTreeMap)> { // 1. Remove unsigned field value.remove("unsigned"); @@ -92,7 +95,7 @@ pub(super) async fn handle_outlier_pdu<'a>( // Build map of auth events let mut auth_events = HashMap::with_capacity(incoming_pdu.auth_events.len()); for id in &incoming_pdu.auth_events { - let Ok(auth_event) = self.services.timeline.get_pdu(id).await else { + let Ok(auth_event) = self.services.timeline.get_pdu(id).map_ok(Arc::new).await else { warn!("Could not find auth event {id}"); continue; }; @@ -120,10 +123,15 @@ pub(super) async fn handle_outlier_pdu<'a>( // The original create event must be in the auth events if !matches!( - auth_events.get(&(StateEventType::RoomCreate, String::new().into())), + auth_events + .get(&(StateEventType::RoomCreate, String::new().into())) + .map(AsRef::as_ref), Some(_) | None ) { - return Err!(Request(InvalidParam("Incoming event refers to wrong create event."))); + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "Incoming event refers to wrong create event.", + )); } let state_fetch = |ty: &StateEventType, sk: &str| { @@ -153,5 +161,5 @@ pub(super) async fn handle_outlier_pdu<'a>( trace!("Added pdu as outlier."); - Ok((incoming_pdu, val)) + Ok((Arc::new(incoming_pdu), val)) } diff --git a/src/service/rooms/event_handler/handle_prev_pdu.rs b/src/service/rooms/event_handler/handle_prev_pdu.rs index d612b2bf..cf69a515 100644 --- a/src/service/rooms/event_handler/handle_prev_pdu.rs +++ b/src/service/rooms/event_handler/handle_prev_pdu.rs @@ -1,10 +1,14 @@ -use std::{collections::BTreeMap, time::Instant}; +use std::{ + collections::{BTreeMap, HashMap}, + sync::Arc, + time::Instant, +}; use conduwuit::{ - Err, PduEvent, Result, debug, debug::INFO_SPAN_LEVEL, defer, implement, + Err, PduEvent, Result, debug, debug::INFO_SPAN_LEVEL, implement, utils::continue_exponential_backoff_secs, }; -use ruma::{CanonicalJsonValue, EventId, RoomId, ServerName, UInt}; +use ruma::{CanonicalJsonValue, EventId, OwnedEventId, RoomId, ServerName, UInt}; #[implement(super::Service)] #[allow(clippy::type_complexity)] @@ -20,10 +24,13 @@ pub(super) async fn handle_prev_pdu<'a>( origin: &'a ServerName, event_id: &'a EventId, room_id: &'a RoomId, - eventid_info: Option<(PduEvent, BTreeMap)>, - create_event: &'a PduEvent, + eventid_info: &mut HashMap< + OwnedEventId, + (Arc, BTreeMap), + >, + create_event: &PduEvent, first_ts_in_room: UInt, - prev_id: &'a EventId, + prev_id: &EventId, ) -> Result { // Check for disabled again because it might have changed if self.services.metadata.is_disabled(room_id).await { @@ -54,35 +61,31 @@ pub(super) async fn handle_prev_pdu<'a>( } } - let Some((pdu, json)) = eventid_info else { - return Ok(()); - }; + if let Some((pdu, json)) = eventid_info.remove(prev_id) { + // Skip old events + if pdu.origin_server_ts < first_ts_in_room { + return Ok(()); + } - // Skip old events - if pdu.origin_server_ts < first_ts_in_room { - return Ok(()); - } - - let start_time = Instant::now(); - self.federation_handletime - .write() - .expect("locked") - .insert(room_id.into(), ((*prev_id).to_owned(), start_time)); - - defer! {{ + let start_time = Instant::now(); self.federation_handletime .write() .expect("locked") - .remove(room_id); - }}; + .insert(room_id.to_owned(), ((*prev_id).to_owned(), start_time)); - self.upgrade_outlier_to_timeline_pdu(pdu, json, create_event, origin, room_id) - .await?; + self.upgrade_outlier_to_timeline_pdu(pdu, json, create_event, origin, room_id) + .await?; - debug!( - elapsed = ?start_time.elapsed(), - "Handled prev_event", - ); + self.federation_handletime + .write() + .expect("locked") + .remove(&room_id.to_owned()); + + debug!( + elapsed = ?start_time.elapsed(), + "Handled prev_event", + ); + } Ok(()) } diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index 45675da8..e9e79ce4 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -17,8 +17,11 @@ use std::{ time::Instant, }; -use async_trait::async_trait; -use conduwuit::{Err, PduEvent, Result, RoomVersion, Server, utils::MutexMap}; +use conduwuit::{ + Err, PduEvent, Result, RoomVersion, Server, + utils::{MutexMap, TryFutureExtExt}, +}; +use futures::TryFutureExt; use ruma::{ OwnedEventId, OwnedRoomId, RoomId, RoomVersionId, events::room::create::RoomCreateEventContent, @@ -51,7 +54,6 @@ struct Services { type RoomMutexMap = MutexMap; type HandleTimeMap = HashMap; -#[async_trait] impl crate::Service for Service { fn build(args: crate::Args<'_>) -> Result> { Ok(Arc::new(Self { @@ -77,7 +79,7 @@ impl crate::Service for Service { })) } - async fn memory_usage(&self, out: &mut (dyn Write + Send)) -> Result { + fn memory_usage(&self, out: &mut dyn Write) -> Result<()> { let mutex_federation = self.mutex_federation.len(); writeln!(out, "federation_mutex: {mutex_federation}")?; @@ -99,8 +101,13 @@ impl Service { self.services.timeline.pdu_exists(&event_id).await } - async fn event_fetch(&self, event_id: OwnedEventId) -> Option { - self.services.timeline.get_pdu(&event_id).await.ok() + async fn event_fetch(&self, event_id: OwnedEventId) -> Option> { + self.services + .timeline + .get_pdu(&event_id) + .map_ok(Arc::new) + .ok() + .await } } diff --git a/src/service/rooms/event_handler/resolve_state.rs b/src/service/rooms/event_handler/resolve_state.rs index b3a7a71b..9033c3a8 100644 --- a/src/service/rooms/event_handler/resolve_state.rs +++ b/src/service/rooms/event_handler/resolve_state.rs @@ -110,14 +110,12 @@ pub async fn state_resolution<'a, StateSets>( where StateSets: Iterator> + Clone + Send, { - let event_fetch = |event_id| self.event_fetch(event_id); - let event_exists = |event_id| self.event_exists(event_id); state_res::resolve( room_version, state_sets, auth_chain_sets, - &event_fetch, - &event_exists, + &|event_id| self.event_fetch(event_id), + &|event_id| self.event_exists(event_id), automatic_width(), ) .map_err(|e| err!(error!("State resolution failed: {e:?}"))) diff --git a/src/service/rooms/event_handler/state_at_incoming.rs b/src/service/rooms/event_handler/state_at_incoming.rs index eb38c2c3..8326f9da 100644 --- a/src/service/rooms/event_handler/state_at_incoming.rs +++ b/src/service/rooms/event_handler/state_at_incoming.rs @@ -2,12 +2,11 @@ use std::{ borrow::Borrow, collections::{HashMap, HashSet}, iter::Iterator, + sync::Arc, }; use conduwuit::{ - Result, debug, err, implement, - matrix::{PduEvent, StateMap}, - trace, + PduEvent, Result, StateMap, debug, err, implement, trace, utils::stream::{BroadbandExt, IterStream, ReadyExt, TryBroadbandExt, TryWidebandExt}, }; use futures::{FutureExt, StreamExt, TryFutureExt, TryStreamExt, future::try_join}; @@ -21,7 +20,7 @@ use crate::rooms::short::ShortStateHash; #[tracing::instrument(name = "state", level = "debug", skip_all)] pub(super) async fn state_at_incoming_degree_one( &self, - incoming_pdu: &PduEvent, + incoming_pdu: &Arc, ) -> Result>> { let prev_event = &incoming_pdu.prev_events[0]; let Ok(prev_event_sstatehash) = self @@ -68,7 +67,7 @@ pub(super) async fn state_at_incoming_degree_one( #[tracing::instrument(name = "state", level = "debug", skip_all)] pub(super) async fn state_at_incoming_resolved( &self, - incoming_pdu: &PduEvent, + incoming_pdu: &Arc, room_id: &RoomId, room_version_id: &RoomVersionId, ) -> Result>> { diff --git a/src/service/rooms/event_handler/upgrade_outlier_pdu.rs b/src/service/rooms/event_handler/upgrade_outlier_pdu.rs index 97d3df97..c1a1c3eb 100644 --- a/src/service/rooms/event_handler/upgrade_outlier_pdu.rs +++ b/src/service/rooms/event_handler/upgrade_outlier_pdu.rs @@ -1,8 +1,7 @@ use std::{borrow::Borrow, collections::BTreeMap, iter::once, sync::Arc, time::Instant}; use conduwuit::{ - Err, Result, debug, debug_info, err, implement, - matrix::{EventTypeExt, PduEvent, StateKey, state_res}, + Err, EventTypeExt, PduEvent, Result, StateKey, debug, debug_info, err, implement, state_res, trace, utils::stream::{BroadbandExt, ReadyExt}, warn, @@ -19,7 +18,7 @@ use crate::rooms::{ #[implement(super::Service)] pub(super) async fn upgrade_outlier_to_timeline_pdu( &self, - incoming_pdu: PduEvent, + incoming_pdu: Arc, val: BTreeMap, create_event: &PduEvent, origin: &ServerName, diff --git a/src/service/rooms/outlier/mod.rs b/src/service/rooms/outlier/mod.rs index 12b56935..a1b0263a 100644 --- a/src/service/rooms/outlier/mod.rs +++ b/src/service/rooms/outlier/mod.rs @@ -1,9 +1,11 @@ use std::sync::Arc; -use conduwuit::{Result, implement, matrix::pdu::PduEvent}; -use conduwuit_database::{Deserialized, Json, Map}; +use conduwuit::{Result, implement}; +use database::{Deserialized, Json, Map}; use ruma::{CanonicalJsonObject, EventId}; +use crate::PduEvent; + pub struct Service { db: Data, } diff --git a/src/service/rooms/read_receipt/mod.rs b/src/service/rooms/read_receipt/mod.rs index 69e859c4..d6239aee 100644 --- a/src/service/rooms/read_receipt/mod.rs +++ b/src/service/rooms/read_receipt/mod.rs @@ -2,11 +2,7 @@ mod data; use std::{collections::BTreeMap, sync::Arc}; -use conduwuit::{ - Result, debug, err, - matrix::pdu::{PduCount, PduId, RawPduId}, - warn, -}; +use conduwuit::{PduCount, PduId, RawPduId, Result, debug, err, warn}; use futures::{Stream, TryFutureExt, try_join}; use ruma::{ OwnedEventId, OwnedUserId, RoomId, UserId, diff --git a/src/service/rooms/short/mod.rs b/src/service/rooms/short/mod.rs index 06ff6493..3980617e 100644 --- a/src/service/rooms/short/mod.rs +++ b/src/service/rooms/short/mod.rs @@ -1,7 +1,7 @@ use std::{borrow::Borrow, fmt::Debug, mem::size_of_val, sync::Arc}; -pub use conduwuit::matrix::pdu::{ShortEventId, ShortId, ShortRoomId, ShortStateKey}; -use conduwuit::{Result, err, implement, matrix::StateKey, utils, utils::IterStream}; +pub use conduwuit::pdu::{ShortEventId, ShortId, ShortRoomId, ShortStateKey}; +use conduwuit::{Result, StateKey, err, implement, utils, utils::IterStream}; use database::{Deserialized, Get, Map, Qry}; use futures::{Stream, StreamExt}; use ruma::{EventId, RoomId, events::StateEventType}; diff --git a/src/service/rooms/spaces/mod.rs b/src/service/rooms/spaces/mod.rs index ea9756ba..1da38234 100644 --- a/src/service/rooms/spaces/mod.rs +++ b/src/service/rooms/spaces/mod.rs @@ -2,14 +2,13 @@ mod pagination_token; #[cfg(test)] mod tests; -use std::{fmt::Write, sync::Arc}; +use std::sync::Arc; -use async_trait::async_trait; use conduwuit::{ - Err, Error, PduEvent, Result, implement, + Err, Error, Result, implement, utils::{ IterStream, - future::{BoolExt, TryExtExt}, + future::BoolExt, math::usize_from_f64, stream::{BroadbandExt, ReadyExt}, }, @@ -27,6 +26,7 @@ use ruma::{ }, events::{ StateEventType, + room::join_rules::{JoinRule, RoomJoinRulesEventContent}, space::child::{HierarchySpaceChildEvent, SpaceChildEventContent}, }, serde::Raw, @@ -35,7 +35,7 @@ use ruma::{ use tokio::sync::{Mutex, MutexGuard}; pub use self::pagination_token::PaginationToken; -use crate::{Dep, rooms, sending}; +use crate::{Dep, conduwuit::utils::TryFutureExtExt, rooms, sending}; pub struct Service { services: Services, @@ -70,7 +70,6 @@ pub enum Identifier<'a> { type Cache = LruCache>; -#[async_trait] impl crate::Service for Service { fn build(args: crate::Args<'_>) -> Result> { let config = &args.server.config; @@ -91,16 +90,6 @@ impl crate::Service for Service { })) } - async fn memory_usage(&self, out: &mut (dyn Write + Send)) -> Result { - let roomid_spacehierarchy_cache = self.roomid_spacehierarchy_cache.lock().await.len(); - - writeln!(out, "roomid_spacehierarchy_cache: {roomid_spacehierarchy_cache}")?; - - Ok(()) - } - - async fn clear_cache(&self) { self.roomid_spacehierarchy_cache.lock().await.clear(); } - fn name(&self) -> &str { crate::service::make_name(std::module_path!()) } } @@ -121,36 +110,35 @@ pub async fn get_summary_and_children_local( | None => (), // cache miss | Some(None) => return Ok(None), | Some(Some(cached)) => { - let allowed_rooms = cached.summary.allowed_room_ids.iter().map(AsRef::as_ref); - - let is_accessible_child = self.is_accessible_child( - current_room, - &cached.summary.join_rule, - identifier, - allowed_rooms, - ); - - let accessibility = if is_accessible_child.await { - SummaryAccessibility::Accessible(cached.summary.clone()) - } else { - SummaryAccessibility::Inaccessible - }; - - return Ok(Some(accessibility)); + return Ok(Some( + if self + .is_accessible_child( + current_room, + &cached.summary.join_rule, + identifier, + &cached.summary.allowed_room_ids, + ) + .await + { + SummaryAccessibility::Accessible(cached.summary.clone()) + } else { + SummaryAccessibility::Inaccessible + }, + )); }, } let children_pdus: Vec<_> = self - .get_space_child_events(current_room) - .map(PduEvent::into_stripped_spacechild_state_event) + .get_stripped_space_child_events(current_room) .collect() .await; - let Ok(summary) = self + let summary = self .get_room_summary(current_room, children_pdus, identifier) .boxed() - .await - else { + .await; + + let Ok(summary) = summary else { return Ok(None); }; @@ -217,27 +205,28 @@ async fn get_summary_and_children_federation( .await; let identifier = Identifier::UserId(user_id); - let allowed_room_ids = summary.allowed_room_ids.iter().map(AsRef::as_ref); - let is_accessible_child = self - .is_accessible_child(current_room, &summary.join_rule, &identifier, allowed_room_ids) + .is_accessible_child( + current_room, + &summary.join_rule, + &identifier, + &summary.allowed_room_ids, + ) .await; - let accessibility = if is_accessible_child { - SummaryAccessibility::Accessible(summary) - } else { - SummaryAccessibility::Inaccessible - }; + if is_accessible_child { + return Ok(Some(SummaryAccessibility::Accessible(summary))); + } - Ok(Some(accessibility)) + Ok(Some(SummaryAccessibility::Inaccessible)) } /// Simply returns the stripped m.space.child events of a room #[implement(Service)] -fn get_space_child_events<'a>( +fn get_stripped_space_child_events<'a>( &'a self, room_id: &'a RoomId, -) -> impl Stream + Send + 'a { +) -> impl Stream> + 'a { self.services .state .get_room_shortstatehash(room_id) @@ -245,7 +234,6 @@ fn get_space_child_events<'a>( self.services .state_accessor .state_keys_with_ids(current_shortstatehash, &StateEventType::SpaceChild) - .boxed() }) .map(Result::into_iter) .map(IterStream::stream) @@ -256,8 +244,8 @@ fn get_space_child_events<'a>( .timeline .get_pdu(&event_id) .map_ok(move |pdu| (state_key, pdu)) - .ok() .await + .ok() }) .ready_filter_map(move |(state_key, pdu)| { if let Ok(content) = pdu.get_content::() { @@ -266,11 +254,11 @@ fn get_space_child_events<'a>( } } - if RoomId::parse(&state_key).is_err() { - return None; + if RoomId::parse(&state_key).is_ok() { + return Some(pdu.to_stripped_spacechild_state_event()); } - Some(pdu) + None }) } @@ -304,19 +292,25 @@ async fn get_room_summary( children_state: Vec>, identifier: &Identifier<'_>, ) -> Result { - let join_rule = self.services.state_accessor.get_join_rules(room_id).await; + let join_rule = self + .services + .state_accessor + .room_state_get_content(room_id, &StateEventType::RoomJoinRules, "") + .await + .map_or(JoinRule::Invite, |c: RoomJoinRulesEventContent| c.join_rule); + let allowed_room_ids = self + .services + .state_accessor + .allowed_room_ids(join_rule.clone()); + + let join_rule = join_rule.clone().into(); let is_accessible_child = self - .is_accessible_child( - room_id, - &join_rule.clone().into(), - identifier, - join_rule.allowed_rooms(), - ) + .is_accessible_child(room_id, &join_rule, identifier, &allowed_room_ids) .await; if !is_accessible_child { - return Err!(Request(Forbidden("User is not allowed to see the room"))); + return Err!(Request(Forbidden("User is not allowed to see the room",))); } let name = self.services.state_accessor.get_name(room_id).ok(); @@ -347,14 +341,6 @@ async fn get_room_summary( .get_avatar(room_id) .map(|res| res.into_option().unwrap_or_default().url); - let room_version = self.services.state.get_room_version(room_id).ok(); - - let encryption = self - .services - .state_accessor - .get_room_encryption(room_id) - .ok(); - let ( canonical_alias, name, @@ -364,8 +350,6 @@ async fn get_room_summary( guest_can_join, avatar_url, room_type, - room_version, - encryption, ) = futures::join!( canonical_alias, name, @@ -374,12 +358,10 @@ async fn get_room_summary( world_readable, guest_can_join, avatar_url, - room_type, - room_version, - encryption, + room_type ); - let summary = SpaceHierarchyParentSummary { + Ok(SpaceHierarchyParentSummary { canonical_alias, name, topic, @@ -388,29 +370,24 @@ async fn get_room_summary( avatar_url, room_type, children_state, - encryption, - room_version, + allowed_room_ids, + join_rule, room_id: room_id.to_owned(), - num_joined_members: num_joined_members.try_into().unwrap_or_default(), - allowed_room_ids: join_rule.allowed_rooms().map(Into::into).collect(), - join_rule: join_rule.clone().into(), - }; - - Ok(summary) + num_joined_members: num_joined_members + .try_into() + .expect("user count should not be that big"), + }) } /// With the given identifier, checks if a room is accessable #[implement(Service)] -async fn is_accessible_child<'a, I>( +async fn is_accessible_child( &self, current_room: &RoomId, join_rule: &SpaceRoomJoinRule, identifier: &Identifier<'_>, - allowed_rooms: I, -) -> bool -where - I: Iterator + Send, -{ + allowed_room_ids: &[OwnedRoomId], +) -> bool { if let Identifier::ServerName(server_name) = identifier { // Checks if ACLs allow for the server to participate if self @@ -435,18 +412,21 @@ where } } - match *join_rule { + match join_rule { | SpaceRoomJoinRule::Public | SpaceRoomJoinRule::Knock | SpaceRoomJoinRule::KnockRestricted => true, | SpaceRoomJoinRule::Restricted => - allowed_rooms + allowed_room_ids + .iter() .stream() - .any(async |room| match identifier { - | Identifier::UserId(user) => - self.services.state_cache.is_joined(user, room).await, - | Identifier::ServerName(server) => - self.services.state_cache.server_in_room(server, room).await, + .any(|room| async { + match identifier { + | Identifier::UserId(user) => + self.services.state_cache.is_joined(user, room).await, + | Identifier::ServerName(server) => + self.services.state_cache.server_in_room(server, room).await, + } }) .await, @@ -493,8 +473,6 @@ async fn cache_insert( join_rule, room_type, allowed_room_ids, - encryption, - room_version, } = child; let summary = SpaceHierarchyParentSummary { @@ -510,12 +488,9 @@ async fn cache_insert( allowed_room_ids, room_id: room_id.clone(), children_state: self - .get_space_child_events(&room_id) - .map(PduEvent::into_stripped_spacechild_state_event) + .get_stripped_space_child_events(&room_id) .collect() .await, - encryption, - room_version, }; cache.insert(current_room.to_owned(), Some(CachedSpaceHierarchySummary { summary })); @@ -537,9 +512,7 @@ impl From for SpaceHierarchyRoomsChunk { join_rule, room_type, children_state, - allowed_room_ids, - encryption, - room_version, + .. } = value.summary; Self { @@ -554,9 +527,6 @@ impl From for SpaceHierarchyRoomsChunk { join_rule, room_type, children_state, - encryption, - room_version, - allowed_room_ids, } } } @@ -577,9 +547,7 @@ pub fn summary_to_chunk(summary: SpaceHierarchyParentSummary) -> SpaceHierarchyR join_rule, room_type, children_state, - allowed_room_ids, - encryption, - room_version, + .. } = summary; SpaceHierarchyRoomsChunk { @@ -594,8 +562,5 @@ pub fn summary_to_chunk(summary: SpaceHierarchyParentSummary) -> SpaceHierarchyR join_rule, room_type, children_state, - encryption, - room_version, - allowed_room_ids, } } diff --git a/src/service/rooms/state/mod.rs b/src/service/rooms/state/mod.rs index 803ba9d7..8683a3be 100644 --- a/src/service/rooms/state/mod.rs +++ b/src/service/rooms/state/mod.rs @@ -1,6 +1,5 @@ use std::{collections::HashMap, fmt::Write, iter::once, sync::Arc}; -use async_trait::async_trait; use conduwuit::{ PduEvent, Result, err, result::FlatOk, @@ -57,7 +56,6 @@ struct Data { type RoomMutexMap = MutexMap; pub type RoomMutexGuard = MutexMapGuard; -#[async_trait] impl crate::Service for Service { fn build(args: crate::Args<'_>) -> Result> { Ok(Arc::new(Self { @@ -81,7 +79,7 @@ impl crate::Service for Service { })) } - async fn memory_usage(&self, out: &mut (dyn Write + Send)) -> Result { + fn memory_usage(&self, out: &mut dyn Write) -> Result { let mutex = self.mutex.len(); writeln!(out, "state_mutex: {mutex}")?; @@ -341,7 +339,7 @@ impl Service { .await .into_iter() .filter_map(Result::ok) - .map(PduEvent::into_stripped_state_event) + .map(|e| e.to_stripped_state_event()) .chain(once(event.to_stripped_state_event())) .collect() } diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index f719fc7b..7004e35a 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -3,13 +3,20 @@ mod server_can; mod state; mod user_can; -use std::sync::Arc; +use std::{ + fmt::Write, + sync::{Arc, Mutex as StdMutex, Mutex}, +}; -use async_trait::async_trait; -use conduwuit::{Result, err}; +use conduwuit::{ + Result, err, utils, + utils::math::{Expected, usize_from_f64}, +}; use database::Map; +use lru_cache::LruCache; use ruma::{ - EventEncryptionAlgorithm, JsOption, OwnedRoomAliasId, RoomId, UserId, + EventEncryptionAlgorithm, JsOption, OwnedRoomAliasId, OwnedRoomId, OwnedServerName, + OwnedUserId, RoomId, UserId, events::{ StateEventType, room::{ @@ -19,18 +26,21 @@ use ruma::{ encryption::RoomEncryptionEventContent, guest_access::{GuestAccess, RoomGuestAccessEventContent}, history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, - join_rules::{JoinRule, RoomJoinRulesEventContent}, + join_rules::{AllowRule, JoinRule, RoomJoinRulesEventContent, RoomMembership}, member::RoomMemberEventContent, name::RoomNameEventContent, topic::RoomTopicEventContent, }, }, room::RoomType, + space::SpaceRoomJoinRule, }; -use crate::{Dep, rooms}; +use crate::{Dep, rooms, rooms::short::ShortStateHash}; pub struct Service { + pub server_visibility_cache: Mutex>, + pub user_visibility_cache: Mutex>, services: Services, db: Data, } @@ -47,10 +57,21 @@ struct Data { shorteventid_shortstatehash: Arc, } -#[async_trait] impl crate::Service for Service { fn build(args: crate::Args<'_>) -> Result> { + let config = &args.server.config; + let server_visibility_cache_capacity = + f64::from(config.server_visibility_cache_capacity) * config.cache_capacity_modifier; + let user_visibility_cache_capacity = + f64::from(config.user_visibility_cache_capacity) * config.cache_capacity_modifier; + Ok(Arc::new(Self { + server_visibility_cache: StdMutex::new(LruCache::new(usize_from_f64( + server_visibility_cache_capacity, + )?)), + user_visibility_cache: StdMutex::new(LruCache::new(usize_from_f64( + user_visibility_cache_capacity, + )?)), services: Services { state_cache: args.depend::("rooms::state_cache"), timeline: args.depend::("rooms::timeline"), @@ -65,6 +86,44 @@ impl crate::Service for Service { })) } + fn memory_usage(&self, out: &mut dyn Write) -> Result { + use utils::bytes::pretty; + + let (svc_count, svc_bytes) = self.server_visibility_cache.lock()?.iter().fold( + (0_usize, 0_usize), + |(count, bytes), (key, _)| { + ( + count.expected_add(1), + bytes + .expected_add(key.0.capacity()) + .expected_add(size_of_val(&key.1)), + ) + }, + ); + + let (uvc_count, uvc_bytes) = self.user_visibility_cache.lock()?.iter().fold( + (0_usize, 0_usize), + |(count, bytes), (key, _)| { + ( + count.expected_add(1), + bytes + .expected_add(key.0.capacity()) + .expected_add(size_of_val(&key.1)), + ) + }, + ); + + writeln!(out, "server_visibility_cache: {svc_count} ({})", pretty(svc_bytes))?; + writeln!(out, "user_visibility_cache: {uvc_count} ({})", pretty(uvc_bytes))?; + + Ok(()) + } + + fn clear_cache(&self) { + self.server_visibility_cache.lock().expect("locked").clear(); + self.user_visibility_cache.lock().expect("locked").clear(); + } + fn name(&self) -> &str { crate::service::make_name(std::module_path!()) } } @@ -128,12 +187,30 @@ impl Service { .map(|c: RoomTopicEventContent| c.topic) } - /// Returns the join rules for a given room (`JoinRule` type). Will default - /// to Invite if doesnt exist or invalid - pub async fn get_join_rules(&self, room_id: &RoomId) -> JoinRule { + /// Returns the join rule (`SpaceRoomJoinRule`) for a given room + pub async fn get_join_rule( + &self, + room_id: &RoomId, + ) -> Result<(SpaceRoomJoinRule, Vec)> { self.room_state_get_content(room_id, &StateEventType::RoomJoinRules, "") .await - .map_or(JoinRule::Invite, |c: RoomJoinRulesEventContent| c.join_rule) + .map(|c: RoomJoinRulesEventContent| { + (c.join_rule.clone().into(), self.allowed_room_ids(c.join_rule)) + }) + .or_else(|_| Ok((SpaceRoomJoinRule::Invite, vec![]))) + } + + /// Returns an empty vec if not a restricted room + pub fn allowed_room_ids(&self, join_rule: JoinRule) -> Vec { + let mut room_ids = Vec::with_capacity(1); + if let JoinRule::Restricted(r) | JoinRule::KnockRestricted(r) = join_rule { + for rule in r.allow { + if let AllowRule::RoomMembership(RoomMembership { room_id: membership }) = rule { + room_ids.push(membership.clone()); + } + } + } + room_ids } pub async fn get_room_type(&self, room_id: &RoomId) -> Result { diff --git a/src/service/rooms/state_accessor/room_state.rs b/src/service/rooms/state_accessor/room_state.rs index 89fa2a83..ff26b33a 100644 --- a/src/service/rooms/state_accessor/room_state.rs +++ b/src/service/rooms/state_accessor/room_state.rs @@ -1,9 +1,6 @@ use std::borrow::Borrow; -use conduwuit::{ - Result, err, implement, - matrix::{PduEvent, StateKey}, -}; +use conduwuit::{PduEvent, Result, StateKey, err, implement}; use futures::{Stream, StreamExt, TryFutureExt}; use ruma::{EventId, RoomId, events::StateEventType}; use serde::Deserialize; @@ -34,7 +31,7 @@ pub fn room_state_full<'a>( self.services .state .get_room_shortstatehash(room_id) - .map_ok(|shortstatehash| self.state_full(shortstatehash).map(Ok).boxed()) + .map_ok(|shortstatehash| self.state_full(shortstatehash).map(Ok)) .map_err(move |e| err!(Database("Missing state for {room_id:?}: {e:?}"))) .try_flatten_stream() } @@ -49,7 +46,7 @@ pub fn room_state_full_pdus<'a>( self.services .state .get_room_shortstatehash(room_id) - .map_ok(|shortstatehash| self.state_full_pdus(shortstatehash).map(Ok).boxed()) + .map_ok(|shortstatehash| self.state_full_pdus(shortstatehash).map(Ok)) .map_err(move |e| err!(Database("Missing state for {room_id:?}: {e:?}"))) .try_flatten_stream() } diff --git a/src/service/rooms/state_accessor/server_can.rs b/src/service/rooms/state_accessor/server_can.rs index 2befec22..2e8f3325 100644 --- a/src/service/rooms/state_accessor/server_can.rs +++ b/src/service/rooms/state_accessor/server_can.rs @@ -1,4 +1,4 @@ -use conduwuit::{implement, utils::stream::ReadyExt}; +use conduwuit::{error, implement, utils::stream::ReadyExt}; use futures::StreamExt; use ruma::{ EventId, RoomId, ServerName, @@ -22,6 +22,15 @@ pub async fn server_can_see_event( return true; }; + if let Some(visibility) = self + .server_visibility_cache + .lock() + .expect("locked") + .get_mut(&(origin.to_owned(), shortstatehash)) + { + return *visibility; + } + let history_visibility = self .state_get_content(shortstatehash, &StateEventType::RoomHistoryVisibility, "") .await @@ -35,7 +44,8 @@ pub async fn server_can_see_event( .room_members(room_id) .ready_filter(|member| member.server_name() == origin); - match history_visibility { + let visibility = match history_visibility { + | HistoryVisibility::WorldReadable | HistoryVisibility::Shared => true, | HistoryVisibility::Invited => { // Allow if any member on requesting server was AT LEAST invited, else deny current_server_members @@ -48,6 +58,16 @@ pub async fn server_can_see_event( .any(|member| self.user_was_joined(shortstatehash, member)) .await }, - | HistoryVisibility::WorldReadable | HistoryVisibility::Shared | _ => true, - } + | _ => { + error!("Unknown history visibility {history_visibility}"); + false + }, + }; + + self.server_visibility_cache + .lock() + .expect("locked") + .insert((origin.to_owned(), shortstatehash), visibility); + + visibility } diff --git a/src/service/rooms/state_accessor/state.rs b/src/service/rooms/state_accessor/state.rs index 169e69e9..02a6194e 100644 --- a/src/service/rooms/state_accessor/state.rs +++ b/src/service/rooms/state_accessor/state.rs @@ -1,15 +1,13 @@ use std::{borrow::Borrow, ops::Deref, sync::Arc}; use conduwuit::{ - Result, at, err, implement, - matrix::{PduEvent, StateKey}, - pair_of, + PduEvent, Result, StateKey, at, err, implement, pair_of, utils::{ result::FlatOk, stream::{BroadbandExt, IterStream, ReadyExt, TryIgnore}, }, }; -use conduwuit_database::Deserialized; +use database::Deserialized; use futures::{FutureExt, Stream, StreamExt, TryFutureExt, future::try_join, pin_mut}; use ruma::{ EventId, OwnedEventId, UserId, @@ -237,7 +235,6 @@ pub fn state_keys_with_shortids<'a>( .ignore_err() .unzip() .map(|(ssks, sids): (Vec, Vec)| (ssks, sids)) - .boxed() .shared(); let shortstatekeys = short_ids @@ -393,10 +390,8 @@ pub fn state_full_shortids( .map(parse_compressed_state_event) .collect() }) - .map_ok(Vec::into_iter) - .map_ok(IterStream::try_stream) + .map_ok(|vec: Vec<_>| vec.into_iter().try_stream()) .try_flatten_stream() - .boxed() } #[implement(super::Service)] diff --git a/src/service/rooms/state_accessor/user_can.rs b/src/service/rooms/state_accessor/user_can.rs index 67e0b52b..c30e1da8 100644 --- a/src/service/rooms/state_accessor/user_can.rs +++ b/src/service/rooms/state_accessor/user_can.rs @@ -1,4 +1,4 @@ -use conduwuit::{Err, Result, implement, pdu::PduBuilder}; +use conduwuit::{Err, Error, Result, error, implement, pdu::PduBuilder}; use ruma::{ EventId, RoomId, UserId, events::{ @@ -76,8 +76,8 @@ pub async fn user_can_redact( || redacting_event .as_ref() .is_ok_and(|redacting_event| redacting_event.sender == sender)), - | _ => Err!(Database( - "No m.room.power_levels or m.room.create events in database for room" + | _ => Err(Error::bad_database( + "No m.room.power_levels or m.room.create events in database for room", )), } }, @@ -98,6 +98,15 @@ pub async fn user_can_see_event( return true; }; + if let Some(visibility) = self + .user_visibility_cache + .lock() + .expect("locked") + .get_mut(&(user_id.to_owned(), shortstatehash)) + { + return *visibility; + } + let currently_member = self.services.state_cache.is_joined(user_id, room_id).await; let history_visibility = self @@ -107,7 +116,9 @@ pub async fn user_can_see_event( c.history_visibility }); - match history_visibility { + let visibility = match history_visibility { + | HistoryVisibility::WorldReadable => true, + | HistoryVisibility::Shared => currently_member, | HistoryVisibility::Invited => { // Allow if any member on requesting server was AT LEAST invited, else deny self.user_was_invited(shortstatehash, user_id).await @@ -116,9 +127,18 @@ pub async fn user_can_see_event( // Allow if any member on requested server was joined, else deny self.user_was_joined(shortstatehash, user_id).await }, - | HistoryVisibility::WorldReadable => true, - | HistoryVisibility::Shared | _ => currently_member, - } + | _ => { + error!("Unknown history visibility {history_visibility}"); + false + }, + }; + + self.user_visibility_cache + .lock() + .expect("locked") + .insert((user_id.to_owned(), shortstatehash), visibility); + + visibility } /// Whether a user is allowed to see an event, based on diff --git a/src/service/rooms/state_cache/mod.rs b/src/service/rooms/state_cache/mod.rs index d3dbc143..23ba0520 100644 --- a/src/service/rooms/state_cache/mod.rs +++ b/src/service/rooms/state_cache/mod.rs @@ -40,7 +40,6 @@ struct Services { account_data: Dep, config: Dep, globals: Dep, - metadata: Dep, state_accessor: Dep, users: Dep, } @@ -74,7 +73,6 @@ impl crate::Service for Service { account_data: args.depend::("account_data"), config: args.depend::("config"), globals: args.depend::("globals"), - metadata: args.depend::("rooms::metadata"), state_accessor: args .depend::("rooms::state_accessor"), users: args.depend::("users"), @@ -273,9 +271,7 @@ impl Service { self.mark_as_left(user_id, room_id); if self.services.globals.user_is_local(user_id) - && (self.services.config.forget_forced_upon_leave - || self.services.metadata.is_banned(room_id).await - || self.services.metadata.is_disabled(room_id).await) + && self.services.config.forget_forced_upon_leave { self.forget(room_id, user_id); } diff --git a/src/service/rooms/state_compressor/mod.rs b/src/service/rooms/state_compressor/mod.rs index 56a91d0e..305d3187 100644 --- a/src/service/rooms/state_compressor/mod.rs +++ b/src/service/rooms/state_compressor/mod.rs @@ -5,7 +5,6 @@ use std::{ sync::{Arc, Mutex}, }; -use async_trait::async_trait; use conduwuit::{ Result, arrayvec::ArrayVec, @@ -66,7 +65,6 @@ type ParentStatesVec = Vec; pub type CompressedState = BTreeSet; pub type CompressedStateEvent = [u8; 2 * size_of::()]; -#[async_trait] impl crate::Service for Service { fn build(args: crate::Args<'_>) -> Result> { let config = &args.server.config; @@ -84,7 +82,7 @@ impl crate::Service for Service { })) } - async fn memory_usage(&self, out: &mut (dyn Write + Send)) -> Result { + fn memory_usage(&self, out: &mut dyn Write) -> Result { let (cache_len, ents) = { let cache = self.stateinfo_cache.lock().expect("locked"); let ents = cache.iter().map(at!(1)).flat_map(|vec| vec.iter()).fold( @@ -110,7 +108,7 @@ impl crate::Service for Service { Ok(()) } - async fn clear_cache(&self) { self.stateinfo_cache.lock().expect("locked").clear(); } + fn clear_cache(&self) { self.stateinfo_cache.lock().expect("locked").clear(); } fn name(&self) -> &str { crate::service::make_name(std::module_path!()) } } diff --git a/src/service/rooms/threads/mod.rs b/src/service/rooms/threads/mod.rs index a680df55..7f9a7515 100644 --- a/src/service/rooms/threads/mod.rs +++ b/src/service/rooms/threads/mod.rs @@ -1,14 +1,13 @@ use std::{collections::BTreeMap, sync::Arc}; use conduwuit::{ - Result, err, - matrix::pdu::{PduCount, PduEvent, PduId, RawPduId}, + PduCount, PduEvent, PduId, RawPduId, Result, err, utils::{ ReadyExt, stream::{TryIgnore, WidebandExt}, }, }; -use conduwuit_database::{Deserialized, Map}; +use database::{Deserialized, Map}; use futures::{Stream, StreamExt}; use ruma::{ CanonicalJsonValue, EventId, OwnedUserId, RoomId, UserId, diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 947e1c38..826a1dae 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -9,20 +9,16 @@ use std::{ sync::Arc, }; -use async_trait::async_trait; -pub use conduwuit::matrix::pdu::{PduId, RawPduId}; use conduwuit::{ Err, Error, Result, Server, at, debug, debug_warn, err, error, implement, info, - matrix::{ - Event, - pdu::{EventHash, PduBuilder, PduCount, PduEvent, gen_event_id}, - state_res::{self, RoomVersion}, - }, + pdu::{EventHash, PduBuilder, PduCount, PduEvent, gen_event_id}, + state_res::{self, Event, RoomVersion}, utils::{ self, IterStream, MutexMap, MutexMapGuard, ReadyExt, future::TryExtExt, stream::TryIgnore, }, validated, warn, }; +pub use conduwuit::{PduId, RawPduId}; use futures::{ Future, FutureExt, Stream, StreamExt, TryStreamExt, future, future::ready, pin_mut, }; @@ -113,7 +109,6 @@ struct Services { type RoomMutexMap = MutexMap; pub type RoomMutexGuard = MutexMapGuard; -#[async_trait] impl crate::Service for Service { fn build(args: crate::Args<'_>) -> Result> { Ok(Arc::new(Self { @@ -147,7 +142,7 @@ impl crate::Service for Service { })) } - async fn memory_usage(&self, out: &mut (dyn Write + Send)) -> Result { + fn memory_usage(&self, out: &mut dyn Write) -> Result<()> { let mutex_insert = self.mutex_insert.len(); writeln!(out, "insert_mutex: {mutex_insert}")?; diff --git a/src/service/sending/appservice.rs b/src/service/sending/appservice.rs index c7fae11f..7fa0be9a 100644 --- a/src/service/sending/appservice.rs +++ b/src/service/sending/appservice.rs @@ -25,10 +25,6 @@ where return Ok(None); }; - if dest == *"null" || dest.is_empty() { - return Ok(None); - } - trace!("Appservice URL \"{dest}\", Appservice ID: {}", registration.id); let hs_token = registration.hs_token.as_str(); @@ -38,11 +34,7 @@ where SendAccessToken::IfRequired(hs_token), &VERSIONS, ) - .map_err(|e| { - err!(BadServerResponse( - warn!(appservice = %registration.id, "Failed to find destination {dest}: {e:?}") - )) - })? + .map_err(|e| err!(BadServerResponse(warn!("Failed to find destination {dest}: {e}"))))? .map(BytesMut::freeze); let mut parts = http_request.uri().clone().into_parts(); @@ -59,7 +51,7 @@ where let reqwest_request = reqwest::Request::try_from(http_request)?; let mut response = client.execute(reqwest_request).await.map_err(|e| { - warn!("Could not send request to appservice \"{}\" at {dest}: {e:?}", registration.id); + warn!("Could not send request to appservice \"{}\" at {dest}: {e}", registration.id); e })?; @@ -79,7 +71,7 @@ where if !status.is_success() { debug_error!("Appservice response bytes: {:?}", utils::string_from_bytes(&body)); - return Err!(BadServerResponse(warn!( + return Err!(BadServerResponse(error!( "Appservice \"{}\" returned unsuccessful HTTP response {status} at {dest}", registration.id ))); @@ -92,8 +84,8 @@ where ); response.map(Some).map_err(|e| { - err!(BadServerResponse(warn!( - "Appservice \"{}\" returned invalid/malformed response bytes {dest}: {e}", + err!(BadServerResponse(error!( + "Appservice \"{}\" returned invalid response bytes {dest}: {e}", registration.id ))) }) diff --git a/src/service/sending/sender.rs b/src/service/sending/sender.rs index fab02f6b..616f0846 100644 --- a/src/service/sending/sender.rs +++ b/src/service/sending/sender.rs @@ -697,7 +697,7 @@ impl Service { match event { | SendingEvent::Pdu(pdu_id) => { if let Ok(pdu) = self.services.timeline.get_pdu_from_id(pdu_id).await { - pdu_jsons.push(pdu.into_room_event()); + pdu_jsons.push(pdu.to_room_event()); } }, | SendingEvent::Edu(edu) => diff --git a/src/service/service.rs b/src/service/service.rs index 574efd8f..2907a562 100644 --- a/src/service/service.rs +++ b/src/service/service.rs @@ -31,10 +31,10 @@ pub(crate) trait Service: Any + Send + Sync { fn interrupt(&self) {} /// Clear any caches or similar runtime state. - async fn clear_cache(&self) {} + fn clear_cache(&self) {} /// Memory usage report in a markdown string. - async fn memory_usage(&self, _out: &mut (dyn Write + Send)) -> Result { Ok(()) } + fn memory_usage(&self, _out: &mut dyn Write) -> Result<()> { Ok(()) } /// Return the name of the service. /// i.e. `crate::service::make_name(std::module_path!())` diff --git a/src/service/services.rs b/src/service/services.rs index dc390054..269a1f87 100644 --- a/src/service/services.rs +++ b/src/service/services.rs @@ -1,12 +1,12 @@ use std::{ any::Any, collections::BTreeMap, + fmt::Write, sync::{Arc, RwLock}, }; -use conduwuit::{Result, Server, debug, debug_info, info, trace, utils::stream::IterStream}; +use conduwuit::{Result, Server, debug, debug_info, info, trace}; use database::Database; -use futures::{Stream, StreamExt, TryStreamExt}; use tokio::sync::Mutex; use crate::{ @@ -171,21 +171,40 @@ impl Services { } pub async fn clear_cache(&self) { - self.services() - .for_each(|service| async move { - service.clear_cache().await; - }) - .await; + for (service, ..) in self.service.read().expect("locked for reading").values() { + if let Some(service) = service.upgrade() { + service.clear_cache(); + } + } + + //TODO + self.rooms + .spaces + .roomid_spacehierarchy_cache + .lock() + .await + .clear(); } pub async fn memory_usage(&self) -> Result { - self.services() - .map(Ok) - .try_fold(String::new(), |mut out, service| async move { - service.memory_usage(&mut out).await?; - Ok(out) - }) + let mut out = String::new(); + for (service, ..) in self.service.read().expect("locked for reading").values() { + if let Some(service) = service.upgrade() { + service.memory_usage(&mut out)?; + } + } + + //TODO + let roomid_spacehierarchy_cache = self + .rooms + .spaces + .roomid_spacehierarchy_cache + .lock() .await + .len(); + writeln!(out, "roomid_spacehierarchy_cache: {roomid_spacehierarchy_cache}")?; + + Ok(out) } fn interrupt(&self) { @@ -198,18 +217,6 @@ impl Services { } } - /// Iterate from snapshot of the services map - fn services(&self) -> impl Stream> + Send { - self.service - .read() - .expect("locked for reading") - .values() - .filter_map(|val| val.0.upgrade()) - .collect::>() - .into_iter() - .stream() - } - #[inline] pub fn try_get(&self, name: &str) -> Result> where diff --git a/src/service/users/mod.rs b/src/service/users/mod.rs index 1eb289fc..5265e64b 100644 --- a/src/service/users/mod.rs +++ b/src/service/users/mod.rs @@ -350,6 +350,7 @@ impl Service { token: &str, ) -> Result<()> { let key = (user_id, device_id); + // should not be None, but we shouldn't assert either lol... if self.db.userdeviceid_metadata.qry(&key).await.is_err() { return Err!(Database(error!( ?user_id, @@ -593,7 +594,7 @@ impl Service { key_id: &str, signature: (String, String), sender_id: &UserId, - ) -> Result { + ) -> Result<()> { let key = (target_id, key_id); let mut cross_signing_key: serde_json::Value = self @@ -601,27 +602,21 @@ impl Service { .keyid_key .qry(&key) .await - .map_err(|_| err!(Request(InvalidParam("Tried to sign nonexistent key"))))? + .map_err(|_| err!(Request(InvalidParam("Tried to sign nonexistent key."))))? .deserialized() - .map_err(|e| err!(Database(debug_warn!("key in keyid_key is invalid: {e:?}"))))?; + .map_err(|e| err!(Database("key in keyid_key is invalid. {e:?}")))?; let signatures = cross_signing_key .get_mut("signatures") - .ok_or_else(|| { - err!(Database(debug_warn!("key in keyid_key has no signatures field"))) - })? + .ok_or_else(|| err!(Database("key in keyid_key has no signatures field.")))? .as_object_mut() - .ok_or_else(|| { - err!(Database(debug_warn!("key in keyid_key has invalid signatures field."))) - })? + .ok_or_else(|| err!(Database("key in keyid_key has invalid signatures field.")))? .entry(sender_id.to_string()) .or_insert_with(|| serde_json::Map::new().into()); signatures .as_object_mut() - .ok_or_else(|| { - err!(Database(debug_warn!("signatures in keyid_key for a user is invalid."))) - })? + .ok_or_else(|| err!(Database("signatures in keyid_key for a user is invalid.")))? .insert(signature.0, signature.1.into()); let key = (target_id, key_id); diff --git a/tests/test_results/complement/test_results.jsonl b/tests/test_results/complement/test_results.jsonl index 97c2e1b1..97170a5c 100644 --- a/tests/test_results/complement/test_results.jsonl +++ b/tests/test_results/complement/test_results.jsonl @@ -69,11 +69,11 @@ {"Action":"pass","Test":"TestChangePassword/After_changing_password,_can_log_in_with_new_password"} {"Action":"pass","Test":"TestChangePassword/After_changing_password,_different_sessions_can_optionally_be_kept"} {"Action":"pass","Test":"TestChangePassword/After_changing_password,_existing_session_still_works"} -{"Action":"pass","Test":"TestChangePasswordPushers"} -{"Action":"pass","Test":"TestChangePasswordPushers/Pushers_created_with_a_different_access_token_are_deleted_on_password_change"} +{"Action":"fail","Test":"TestChangePasswordPushers"} +{"Action":"fail","Test":"TestChangePasswordPushers/Pushers_created_with_a_different_access_token_are_deleted_on_password_change"} {"Action":"pass","Test":"TestChangePasswordPushers/Pushers_created_with_the_same_access_token_are_not_deleted_on_password_change"} {"Action":"fail","Test":"TestClientSpacesSummary"} -{"Action":"pass","Test":"TestClientSpacesSummary/max_depth"} +{"Action":"fail","Test":"TestClientSpacesSummary/max_depth"} {"Action":"fail","Test":"TestClientSpacesSummary/pagination"} {"Action":"fail","Test":"TestClientSpacesSummary/query_whole_graph"} {"Action":"fail","Test":"TestClientSpacesSummary/redact_link"} @@ -491,7 +491,7 @@ {"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself"} {"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself/parallel"} {"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Joining_room_twice_is_idempotent"} -{"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself/parallel/Room_creation_reports_m.room.create_to_myself"} +{"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Room_creation_reports_m.room.create_to_myself"} {"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Room_creation_reports_m.room.member_to_myself"} {"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Setting_room_topic_reports_m.room.topic_to_myself"} {"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself/parallel/Setting_state_twice_is_idempotent"} @@ -527,17 +527,17 @@ {"Action":"pass","Test":"TestRoomMessagesLazyLoadingLocalUser"} {"Action":"pass","Test":"TestRoomReadMarkers"} {"Action":"pass","Test":"TestRoomReceipts"} -{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin"} -{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_mxid"} -{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_profile_display_name"} -{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Eve_can_find_Alice_by_mxid"} -{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Eve_can_find_Alice_by_profile_display_name"} +{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin"} +{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_mxid"} +{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_profile_display_name"} +{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin/Eve_can_find_Alice_by_mxid"} +{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin/Eve_can_find_Alice_by_profile_display_name"} {"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Eve_cannot_find_Alice_by_room-specific_name_that_Eve_is_not_privy_to"} -{"Action":"pass","Test":"TestRoomSpecificUsernameChange"} -{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Bob_can_find_Alice_by_mxid"} -{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Bob_can_find_Alice_by_profile_display_name"} -{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Eve_can_find_Alice_by_mxid"} -{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Eve_can_find_Alice_by_profile_display_name"} +{"Action":"fail","Test":"TestRoomSpecificUsernameChange"} +{"Action":"fail","Test":"TestRoomSpecificUsernameChange/Bob_can_find_Alice_by_mxid"} +{"Action":"fail","Test":"TestRoomSpecificUsernameChange/Bob_can_find_Alice_by_profile_display_name"} +{"Action":"fail","Test":"TestRoomSpecificUsernameChange/Eve_can_find_Alice_by_mxid"} +{"Action":"fail","Test":"TestRoomSpecificUsernameChange/Eve_can_find_Alice_by_profile_display_name"} {"Action":"pass","Test":"TestRoomSpecificUsernameChange/Eve_cannot_find_Alice_by_room-specific_name_that_Eve_is_not_privy_to"} {"Action":"fail","Test":"TestRoomState"} {"Action":"fail","Test":"TestRoomState/Parallel"} @@ -589,7 +589,7 @@ {"Action":"fail","Test":"TestSync/parallel/Newly_joined_room_has_correct_timeline_in_incremental_sync"} {"Action":"fail","Test":"TestSync/parallel/Newly_joined_room_includes_presence_in_incremental_sync"} {"Action":"pass","Test":"TestSync/parallel/Newly_joined_room_is_included_in_an_incremental_sync"} -{"Action":"pass","Test":"TestSync/parallel/sync_should_succeed_even_if_the_sync_token_points_to_a_redaction_of_an_unknown_event"} +{"Action":"fail","Test":"TestSync/parallel/sync_should_succeed_even_if_the_sync_token_points_to_a_redaction_of_an_unknown_event"} {"Action":"pass","Test":"TestSyncFilter"} {"Action":"pass","Test":"TestSyncFilter/Can_create_filter"} {"Action":"pass","Test":"TestSyncFilter/Can_download_filter"}