Compare commits

...

42 Commits

Author SHA1 Message Date
strawberry 00221db8fe dedupe auto_room_join to one function
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 15:00:17 -04:00
strawberry 65b3bc7c48 chore: bump ruma and deps
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 14:54:46 -04:00
strawberry 99d98efeb1 ci: fix docker publishing typo
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 13:05:00 -04:00
strawberry 7b25ef2e6c make next_batch token a variable in search, revert threads_until change
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 1f8a7a707c nix: cache complement outputs using nix-build-and-cache
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 86ec20e787 docs: remove last dev branch mention
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
Charles Hall 8c21388f01 fix nix-build-and-cache
Now it actually caches everything.

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry d657fa32e9 ci: format string
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 321e197d8c correct arithmetic adjustments
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 16a98b0683 ci: push docker images for PRs in the merge-PR_NUMBER-HEAD_REF format, fix main pushes
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 9e1bbc1650 ci: run on new tag pushes
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 91ff6a36a4 ci: abort workflow if latest repo tag does not match with running tag ref
protects against a maintainer creating a downgrading version tag, and
uploading artifacts with that version

this check is only ran via workflow dispatch on the tag

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 56f1d8be1f ci(docker): publish latest only if ref starts with our tag format
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry ed60f189cc docs: remove dev docker images
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry cabf4362be docs: direct all PRs to main
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 2472c7c47a ci: don't run on dev anymore, run on main and non-draft PRs
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
Xiretza 136cb038cf auth_chain: add useful debug logging 2024-05-06 03:45:10 -04:00
Xiretza 8f89be0fbd utils: add helper for adding unbounded slices to tracing spans 2024-05-06 03:45:10 -04:00
Xiretza bbdced9c90 Fix appservice namespace check for room aliases
Only normal users should be prevented from creating an alias within an
exclusive namespace, not the appservice itself. This mirrors the
behaviour in api/client_server/room.rs on room creation.
2024-05-06 03:45:10 -04:00
strawberry a6f4dc2b74 engage(lychee): check all markdown files too, enable verbose mode
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry df203fa244 add a contributing guide
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry c6e6eb0af3 ignore empty CONDUWUIT_VERSION_EXTRA for server version
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 29babebc4d adminroom: add count to list-joined-rooms user command
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
Matt Moriarity 2f3194840c fix extra version when using flake-compat 2024-05-06 03:45:10 -04:00
strawberry 0ebb323490 resolve almost all as_conversions lints
may need further opinion from others on these

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry f8e1255994 presence: set empty string status msg to None
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry b5c0c30a5e resolve half of the integer_arithmetic lints, couple misc changes
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry ac4590952b set io_uring for rocksdb a default feature
this was already enabled by default by rocksdb technically, but
it wasn't building with it properly.

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 67569cb9c8 nix: switch to fork of rocksdb input
https://github.com/girlbossceo/rocksdb/commit/db6df0b185774778457dabfcbd822cb81760cade
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 11ec0dff4f add PATCH to list of allowed HTTP methods in CORS (MSC4138)
https://github.com/matrix-org/matrix-spec-proposals/pull/4138

we already had HEAD

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry a198f0481a nix: add liburing to devshell
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 6266e0ab5e rocksdb: enable async_io if using io_uring feature
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 9ee1485960 enable overflow-checks for dev/debug profile
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 05314ec46c nix: set hardcoded NIX_OUTPATH_USED_AS_RANDOM_SEED for bindgen
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry b66d2d44d0 chore: bump MSRV to 1.77.0 as 1.78.0 came out
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 3b2db9027a envrc: allow loading env vars from .env if it exists
from https://or.computer.surgery/charles/matrix/-/commit/ffd479d66fae5092073ff380d25fac3735d055bd

This is primarily useful for replicating the environment from CI so that
the `nix-build-and-cache` script is easier to invoke.

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 97e81885db use dep: syntax in cargo.toml features
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry 706c1c993b nix: don't run cargo test for crane buildpackage
CI does this already

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-06 03:45:10 -04:00
strawberry cb70d51e2b bump conduwuit version to 0.3.2
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-05 16:52:51 -04:00
strawberry bfb827a418 send Cache-Control and CORS header for remote thumbnail responses
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-05 16:28:21 -04:00
strawberry e2fb588a8c sent attachment content-disposition on thumbnails too
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-05 16:28:21 -04:00
strawberry 43c4dfc5df set content-disposition to attachment instead of inline
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-05-05 16:28:21 -04:00
75 changed files with 819 additions and 478 deletions
+2
View File
@@ -3,3 +3,5 @@
use flake use flake
PATH_add bin PATH_add bin
dotenv_if_exists
+29 -16
View File
@@ -14,10 +14,10 @@ on:
- 'docs/**' - 'docs/**'
- 'debian/**' - 'debian/**'
- 'docker/**' - 'docker/**'
- 'test_results/**'
branches: branches:
- main - main
- dev tags:
- '*'
# Allows you to run this workflow manually from the Actions tab # Allows you to run this workflow manually from the Actions tab
workflow_dispatch: workflow_dispatch:
@@ -48,6 +48,18 @@ jobs:
- name: Sync repository - name: Sync repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Tag comparison check
if: startsWith('refs/tags/v', github.ref)
run: |
# Tag mismatch with latest repo tag check to prevent potential downgrades
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
if [ $LATEST_TAG != ${{ github.ref_name }} ]; then
echo '# WARNING: Attempting to run this workflow for a tag that is not the latest repo tag. Aborting.'
echo '# WARNING: Attempting to run this workflow for a tag that is not the latest repo tag. Aborting.' >> $GITHUB_STEP_SUMMARY
exit 1
fi
- name: Install Nix - name: Install Nix
uses: DeterminateSystems/nix-installer-action@main uses: DeterminateSystems/nix-installer-action@main
@@ -138,7 +150,7 @@ jobs:
name: Build name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: tests needs: tests
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' if: startsWith('refs/tags/v', github.ref) || github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false)
strategy: strategy:
matrix: matrix:
include: include:
@@ -223,20 +235,21 @@ jobs:
name: Docker publish name: Docker publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build
if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && github.event_name != 'pull_request' if: startsWith('refs/tags/v', github.ref) || github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false)
env: env:
DOCKER_ARM64: docker.io/${{ github.repository }}:${{ github.ref_name }}-${{ github.sha }}-arm64v8 DOCKER_ARM64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-arm64v8
DOCKER_AMD64: docker.io/${{ github.repository }}:${{ github.ref_name }}-${{ github.sha }}-amd64 DOCKER_AMD64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-amd64
DOCKER_TAG: docker.io/${{ github.repository }}:${{ github.ref_name }}-${{ github.sha }} DOCKER_TAG: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}
DOCKER_BRANCH: docker.io/${{ github.repository }}:${{ (github.ref == 'refs/heads/main' && 'latest') || github.ref_name }} DOCKER_BRANCH: docker.io/${{ github.repository }}:${{ (startsWith('refs/tags/v', github.ref) && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}
GHCR_ARM64: ghcr.io/${{ github.repository }}:${{ github.ref_name }}-${{ github.sha }}-arm64v8 GHCR_ARM64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-arm64v8
GHCR_AMD64: ghcr.io/${{ github.repository }}:${{ github.ref_name }}-${{ github.sha }}-amd64 GHCR_AMD64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-amd64
GHCR_TAG: ghcr.io/${{ github.repository }}:${{ github.ref_name }}-${{ github.sha }} GHCR_TAG: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}
GHCR_BRANCH: ghcr.io/${{ github.repository }}:${{ (github.ref == 'refs/heads/main' && 'latest') || github.ref_name }} GHCR_BRANCH: ghcr.io/${{ github.repository }}:${{ (startsWith('refs/tags/v', github.ref) && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}
GLCR_ARM64: registry.gitlab.com/${{ github.repository }}:${{ github.ref_name }}-${{ github.sha }}-arm64v8 GLCR_ARM64: registry.gitlab.com/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-arm64v8
GLCR_AMD64: registry.gitlab.com/${{ github.repository }}:${{ github.ref_name }}-${{ github.sha }}-amd64 GLCR_AMD64: registry.gitlab.com/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-amd64
GLCR_TAG: registry.gitlab.com/${{ github.repository }}:${{ github.ref_name }}-${{ github.sha }} GLCR_TAG: registry.gitlab.com/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}
GLCR_BRANCH: registry.gitlab.com/${{ github.repository }}:${{ (github.ref == 'refs/heads/main' && 'latest') || github.ref_name }} GLCR_BRANCH: registry.gitlab.com/${{ github.repository }}:${{ (startsWith('refs/tags/v', github.ref) && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
steps: steps:
+2
View File
@@ -5,6 +5,8 @@ on:
push: push:
branches: branches:
- main - main
tags:
- '*'
# Allows you to run this workflow manually from the Actions tab # Allows you to run this workflow manually from the Actions tab
workflow_dispatch: workflow_dispatch:
+2
View File
@@ -5,6 +5,8 @@ on:
push: push:
branches: branches:
- main - main
tags:
- '*'
schedule: schedule:
- cron: '00 12 * * *' - cron: '00 12 * * *'
+3
View File
@@ -1,3 +1,6 @@
# Local environment overrides
/.env
# CMake # CMake
cmake-build-*/ cmake-build-*/
+90
View File
@@ -0,0 +1,90 @@
# Contributing guide
This page is for about contributing to conduwuit. The [development](docs/development.md) page may be of interest for you as well.
If you would like to work on an [issue][issues] that is not assigned, preferably ask in the Matrix room first at [#conduwuit:puppygock.gay][conduwuit-matrix], and comment on it.
### Linting and Formatting
It is mandatory all your changes satisfy the lints (clippy, rustc, rustdoc, etc) and your code is formatted via the **nightly** `cargo fmt`. A lot of the `rustfmt.toml` features depend on nightly toolchain. It would be ideal if they weren't nightly-exclusive features, but they currently still are. CI's rustfmt uses nightly.
If you need to allow a lint, please make sure it's either obvious as to why (e.g. clippy saying redundant clone but it's actually required) or it has a comment saying why. Do not write inefficient code for the sake of satisfying lints. If a lint is wrong and provides a more inefficient solution or suggestion, allow the lint and mention that in a comment.
### Running CI tests locally
conduwuit's CI for tests, linting, formatting, audit, etc use [`engage`][engage]. engage can be installed from nixpkgs or `cargo install engage`. conduwuit's Nix flake devshell has the nixpkgs engage with `direnv`. Use `engage --help` for more usage details.
To test, format, lint, etc that CI would do, install engage, allow the `.envrc` file using `direnv allow`, and run `engage`.
All of the tasks are defined at the [engage.toml][engage.toml] file. You can view all of them neatly by running `engage list`
If you would like to run only a specific engage task group, use `just`:
- `engage just <group>`
- Example: `engage just lints`
If you would like to run a specific engage task in a specific group, use `just <GROUP> [TASK]`: `engage just lints cargo-fmt`
The following binaries are used in [`engage.toml`][engage.toml]:
- [`engage`][engage]
- `nix`
- [`direnv`][direnv]
- `rustc`
- `cargo`
- `cargo-fmt`
- `rustdoc`
- `cargo-clippy`
- [`cargo-audit`][cargo-audit]
- [`cargo-deb`][cargo-deb]
- [`lychee`][lychee]
### Matrix tests
CI runs [Complement][complement], but currently does not fail if results from the checked-in results differ with the new results. If your changes are done to fix Matrix tests, note that in your pull request. If more Complement tests start failing from your changes, please review the logs (they are uploaded as artifacts) and determine if they're intended or not.
If you'd like to run Complement locally using Nix, see the [testing](docs/development/testing.md) page.
[Sytest][sytest] support will come soon.
### Writing documentation
conduwuit's website uses [`mdbook`][mdbook] and deployed via CI using GitHub Pages in the [`documentation.yml`][documentation.yml] workflow file with Nix's mdbook in the devshell. All documentation is in the `docs/` directory at the top level. The compiled mdbook website is also uploaded as an artifact.
To build the documentation using Nix, run: `bin/nix-build-and-cache just .#book`
### Inclusivity and Diversity
All **MUST** code and write with inclusivity and diversity in mind. See the [following page by Google on writing inclusive code and documentation](https://developers.google.com/style/inclusive-documentation).
This **EXPLICITLY** forbids usage of terms like "blacklist"/"whitelist" and "master"/"slave", [forbids gender-specific words and phrases](https://developers.google.com/style/pronouns#gender-neutral-pronouns), forbids ableist language like "sanity-check", "cripple", or "insane", and forbids culture-specific language (e.g. US-only holidays or cultures).
No exceptions are allowed. Dependencies that may use these terms are allowed but [do not replicate the name in your functions or variables](https://developers.google.com/style/inclusive-documentation#write-around).
In addition to language, write and code with the user experience in mind. This is software that intends to be used by everyone, so make it easy and comfortable for everyone to use. 🏳️‍⚧️
### Variable, comment, function, etc standards
Rust's default style and standards with regards to [function names, variable names, comments](https://rust-lang.github.io/api-guidelines/naming.html), etc applies here.
### Creating pull requests
Please try to keep contributions to the GitHub. While the mirrors of conduwuit allow for pull/merge requests, there is no guarantee I will see them in a timely manner.
If you open a pull request on one of the mirrors, it is your responsibility to inform me about its existence. In the future I may try to solve this with more repo bots in the conduwuit Matrix room. There is no mailing list or email-patch support on the sr.ht mirror, but if you'd like to email me a git patch you can do so at `strawberry@puppygock.gay`.
Direct all PRs/MRs to the `main` branch.
By sending a pull request or patch, you are agreeing that your changes are allowed to be licenced under the Apache-2.0 licence and all of your conduct is in line with the Contributor's Covenant.
[issues]: https://github.com/girlbossceo/conduwuit/issues
[conduwuit-matrix]: https://matrix.to/#/#conduwuit:puppygock.gay
[complement]: https://github.com/matrix-org/complement/
[engage.toml]: https://github.com/girlbossceo/conduwuit/blob/main/engage.toml
[engage]: https://charles.page.computer.surgery/engage/
[sytest]: https://github.com/matrix-org/sytest/
[cargo-deb]: https://github.com/kornelski/cargo-deb
[lychee]: https://github.com/lycheeverse/lychee
[cargo-audit]: https://github.com/RustSec/rustsec/tree/main/cargo-audit
[direnv]: https://direnv.net/
[mdbook]: https://rust-lang.github.io/mdBook/
[documentation.yml]: https://github.com/girlbossceo/conduwuit/blob/main/.github/workflows/documentation.yml
Generated
+84 -66
View File
@@ -61,15 +61,15 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.6" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.82" version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
@@ -161,9 +161,9 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.2.0" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]] [[package]]
name = "axum" name = "axum"
@@ -472,9 +472,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.96" version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@@ -568,7 +568,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]] [[package]]
name = "conduit" name = "conduit"
version = "0.3.1" version = "0.3.2"
dependencies = [ dependencies = [
"argon2", "argon2",
"async-trait", "async-trait",
@@ -1090,9 +1090,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.14" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@@ -1357,16 +1357,16 @@ dependencies = [
[[package]] [[package]]
name = "html5ever" name = "html5ever"
version = "0.26.0" version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4"
dependencies = [ dependencies = [
"log", "log",
"mac", "mac",
"markup5ever", "markup5ever",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 2.0.60",
] ]
[[package]] [[package]]
@@ -1885,9 +1885,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]] [[package]]
name = "markup5ever" name = "markup5ever"
version = "0.11.0" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
dependencies = [ dependencies = [
"log", "log",
"phf", "phf",
@@ -1899,9 +1899,9 @@ dependencies = [
[[package]] [[package]]
name = "markup5ever_rcdom" name = "markup5ever_rcdom"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9521dd6750f8e80ee6c53d65e2e4656d7de37064f3a7a5d2d11d05df93839c2" checksum = "edaa21ab3701bfee5099ade5f7e1f84553fd19228cf332f13cd6e964bf59be18"
dependencies = [ dependencies = [
"html5ever", "html5ever",
"markup5ever", "markup5ever",
@@ -2092,9 +2092,9 @@ dependencies = [
[[package]] [[package]]
name = "num-iter" name = "num-iter"
version = "0.1.44" version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"num-integer", "num-integer",
@@ -2115,9 +2115,9 @@ dependencies = [
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.18" version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
@@ -2332,21 +2332,21 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "phf" name = "phf"
version = "0.10.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [ dependencies = [
"phf_shared", "phf_shared 0.11.2",
] ]
[[package]] [[package]]
name = "phf_codegen" name = "phf_codegen"
version = "0.10.0" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
dependencies = [ dependencies = [
"phf_generator", "phf_generator 0.11.2",
"phf_shared", "phf_shared 0.11.2",
] ]
[[package]] [[package]]
@@ -2355,7 +2355,17 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [ dependencies = [
"phf_shared", "phf_shared 0.10.0",
"rand",
]
[[package]]
name = "phf_generator"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
dependencies = [
"phf_shared 0.11.2",
"rand", "rand",
] ]
@@ -2368,6 +2378,15 @@ dependencies = [
"siphasher", "siphasher",
] ]
[[package]]
name = "phf_shared"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [
"siphasher",
]
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.1.5" version = "1.1.5"
@@ -2698,7 +2717,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma" name = "ruma"
version = "0.9.4" version = "0.9.4"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"assign", "assign",
"js_int", "js_int",
@@ -2718,7 +2737,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-appservice-api" name = "ruma-appservice-api"
version = "0.9.0" version = "0.9.0"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@@ -2730,7 +2749,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-client-api" name = "ruma-client-api"
version = "0.17.4" version = "0.17.4"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"as_variant", "as_variant",
"assign", "assign",
@@ -2752,7 +2771,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-common" name = "ruma-common"
version = "0.12.1" version = "0.12.1"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"as_variant", "as_variant",
"base64 0.22.1", "base64 0.22.1",
@@ -2782,7 +2801,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-events" name = "ruma-events"
version = "0.27.11" version = "0.27.11"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"as_variant", "as_variant",
"indexmap 2.2.6", "indexmap 2.2.6",
@@ -2804,7 +2823,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-federation-api" name = "ruma-federation-api"
version = "0.8.0" version = "0.8.0"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@@ -2816,7 +2835,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers-validation" name = "ruma-identifiers-validation"
version = "0.9.3" version = "0.9.3"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"js_int", "js_int",
"thiserror", "thiserror",
@@ -2825,7 +2844,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identity-service-api" name = "ruma-identity-service-api"
version = "0.8.0" version = "0.8.0"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@@ -2835,7 +2854,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-macros" name = "ruma-macros"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"proc-macro-crate", "proc-macro-crate",
@@ -2850,7 +2869,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-push-gateway-api" name = "ruma-push-gateway-api"
version = "0.8.0" version = "0.8.0"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@@ -2862,7 +2881,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-signatures" name = "ruma-signatures"
version = "0.14.0" version = "0.14.0"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"ed25519-dalek", "ed25519-dalek",
@@ -2878,7 +2897,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-state-res" name = "ruma-state-res"
version = "0.10.0" version = "0.10.0"
source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#1c291e18efd0559c2dd76b27d555c86471cbb0fd" source = "git+https://github.com/girlbossceo/ruma?branch=conduwuit-changes#e6e8462c050296c1ee4911f1c0e66112fb7c4986"
dependencies = [ dependencies = [
"itertools", "itertools",
"js_int", "js_int",
@@ -2906,7 +2925,7 @@ dependencies = [
[[package]] [[package]]
name = "rust-librocksdb-sys" name = "rust-librocksdb-sys"
version = "0.21.0+9.1.1" version = "0.21.0+9.1.1"
source = "git+https://github.com/zaidoon1/rust-rocksdb?branch=master#c5cd6bd25152ef1f8a488761351da0c3d29ed93a" source = "git+https://github.com/zaidoon1/rust-rocksdb?branch=master#567825463480b75f733b73f01c1bd05990aea5b9"
dependencies = [ dependencies = [
"bindgen", "bindgen",
"bzip2-sys", "bzip2-sys",
@@ -2923,7 +2942,7 @@ dependencies = [
[[package]] [[package]]
name = "rust-rocksdb" name = "rust-rocksdb"
version = "0.25.0" version = "0.25.0"
source = "git+https://github.com/zaidoon1/rust-rocksdb?branch=master#c5cd6bd25152ef1f8a488761351da0c3d29ed93a" source = "git+https://github.com/zaidoon1/rust-rocksdb?branch=master#567825463480b75f733b73f01c1bd05990aea5b9"
dependencies = [ dependencies = [
"libc", "libc",
"rust-librocksdb-sys", "rust-librocksdb-sys",
@@ -3080,11 +3099,11 @@ checksum = "621e3680f3e07db4c9c2c3fb07c6223ab2fab2e54bd3c04c3ae037990f428c32"
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.10.0" version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.5.0",
"core-foundation", "core-foundation",
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@@ -3093,9 +3112,9 @@ dependencies = [
[[package]] [[package]]
name = "security-framework-sys" name = "security-framework-sys"
version = "2.10.0" version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@@ -3480,7 +3499,7 @@ dependencies = [
"new_debug_unreachable", "new_debug_unreachable",
"once_cell", "once_cell",
"parking_lot", "parking_lot",
"phf_shared", "phf_shared 0.10.0",
"precomputed-hash", "precomputed-hash",
"serde", "serde",
] ]
@@ -3491,8 +3510,8 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
dependencies = [ dependencies = [
"phf_generator", "phf_generator 0.10.0",
"phf_shared", "phf_shared 0.10.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
] ]
@@ -3772,16 +3791,15 @@ dependencies = [
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.10" version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"pin-project-lite", "pin-project-lite",
"tokio", "tokio",
"tracing",
] ]
[[package]] [[package]]
@@ -3826,7 +3844,7 @@ dependencies = [
"serde", "serde",
"serde_spanned", "serde_spanned",
"toml_datetime", "toml_datetime",
"winnow 0.6.7", "winnow 0.6.8",
] ]
[[package]] [[package]]
@@ -4277,9 +4295,9 @@ dependencies = [
[[package]] [[package]]
name = "webpage" name = "webpage"
version = "2.0.0" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb86b12e58d490a99867f561ce8466ffa7b73e24d015a8e7f5bc111d4424ba2" checksum = "70862efc041d46e6bbaa82bb9c34ae0596d090e86cbd14bd9e93b36ee6802eac"
dependencies = [ dependencies = [
"html5ever", "html5ever",
"markup5ever_rcdom", "markup5ever_rcdom",
@@ -4520,9 +4538,9 @@ dependencies = [
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.6.7" version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@@ -4549,9 +4567,9 @@ dependencies = [
[[package]] [[package]]
name = "xml5ever" name = "xml5ever"
version = "0.17.0" version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4034e1d05af98b51ad7214527730626f019682d797ba38b51689212118d8e650" checksum = "7c376f76ed09df711203e20c3ef5ce556f0166fa03d39590016c0fd625437fad"
dependencies = [ dependencies = [
"log", "log",
"mac", "mac",
@@ -4566,18 +4584,18 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.7.32" version = "0.7.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" checksum = "087eca3c1eaf8c47b94d02790dd086cd594b912d2043d4de4bfdd466b3befb7c"
dependencies = [ dependencies = [
"zerocopy-derive", "zerocopy-derive",
] ]
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.7.32" version = "0.7.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" checksum = "6f4b6c273f496d8fd4eaf18853e6b448760225dc030ff2c485a786859aea6393"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
+23 -19
View File
@@ -10,11 +10,11 @@ authors = [
homepage = "https://conduwuit.puppyirl.gay/" homepage = "https://conduwuit.puppyirl.gay/"
repository = "https://github.com/girlbossceo/conduwuit" repository = "https://github.com/girlbossceo/conduwuit"
readme = "README.md" readme = "README.md"
version = "0.3.1" version = "0.3.2"
edition = "2021" edition = "2021"
# See also `rust-toolchain.toml` # See also `rust-toolchain.toml`
rust-version = "1.76.0" rust-version = "1.77.0"
[dependencies] [dependencies]
console-subscriber = { version = "0.2", optional = true } console-subscriber = { version = "0.2", optional = true }
@@ -362,44 +362,45 @@ default = [
"brotli_compression", "brotli_compression",
"zstd_compression", "zstd_compression",
"release_max_log_level", "release_max_log_level",
"io_uring",
] ]
backend_sqlite = ["sqlite"] backend_sqlite = ["sqlite"]
backend_rocksdb = ["rocksdb"] backend_rocksdb = ["rocksdb"]
rocksdb = ["rust-rocksdb"] rocksdb = ["dep:rust-rocksdb"]
jemalloc = [ jemalloc = [
"tikv-jemalloc-sys", "dep:tikv-jemalloc-sys",
"tikv-jemalloc-ctl", "dep:tikv-jemalloc-ctl",
"tikv-jemallocator", "dep:tikv-jemallocator",
"rust-rocksdb/jemalloc", "rust-rocksdb/jemalloc",
] ]
jemalloc_prof = ["tikv-jemalloc-sys/profiling"] jemalloc_prof = ["tikv-jemalloc-sys/profiling"]
sqlite = ["rusqlite", "parking_lot", "thread_local"] sqlite = ["dep:rusqlite", "dep:parking_lot", "dep:thread_local"]
systemd = ["sd-notify"] systemd = ["dep:sd-notify"]
sentry_telemetry = ["sentry", "sentry-tracing", "sentry-tower"] sentry_telemetry = ["dep:sentry", "dep:sentry-tracing", "dep:sentry-tower"]
gzip_compression = ["tower-http/compression-gzip", "reqwest/gzip"] gzip_compression = ["tower-http/compression-gzip", "reqwest/gzip"]
zstd_compression = ["tower-http/compression-zstd"] zstd_compression = ["tower-http/compression-zstd"]
brotli_compression = ["tower-http/compression-br", "reqwest/brotli"] brotli_compression = ["tower-http/compression-br", "reqwest/brotli"]
sha256_media = ["sha2"] sha256_media = ["dep:sha2"]
io_uring = ["rust-rocksdb/io-uring"] io_uring = ["rust-rocksdb/io-uring"]
axum_dual_protocol = ["axum-server-dual-protocol"] axum_dual_protocol = ["dep:axum-server-dual-protocol"]
perf_measurements = [ perf_measurements = [
"opentelemetry", "dep:opentelemetry",
"tracing-flame", "dep:tracing-flame",
"tracing-opentelemetry", "dep:tracing-opentelemetry",
"opentelemetry_sdk", "dep:opentelemetry_sdk",
"opentelemetry-jaeger", "dep:opentelemetry-jaeger",
] ]
# enable the tokio_console server # enable the tokio_console server
# incompatible with release_max_log_level # incompatible with release_max_log_level
tokio_console = ["console-subscriber", "tokio/tracing"] tokio_console = ["dep:console-subscriber", "tokio/tracing"]
hot_reload = ["dep:hot-lib-reloader"] hot_reload = ["dep:hot-lib-reloader"]
hardened_malloc = ["hardened_malloc-rs"] hardened_malloc = ["dep:hardened_malloc-rs"]
# increases performance, reduces build times, and reduces binary size by not compiling or # increases performance, reduces build times, and reduces binary size by not compiling or
# genreating code for log level filters that users will generally not use (debug and trace) only in release builds # genreating code for log level filters that users will generally not use (debug and trace) only in release builds
@@ -459,9 +460,11 @@ systemd-units = { unit-name = "conduwuit" }
[profile.dev] [profile.dev]
#debug = 0
lto = 'off' lto = 'off'
codegen-units = 512 codegen-units = 512
incremental = true incremental = true
overflow-checks = true
#panic = "abort" #panic = "abort"
# seems to speed up continuous debug compilations # seems to speed up continuous debug compilations
@@ -622,6 +625,8 @@ manual_let_else = "warn"
trivially_copy_pass_by_ref = "warn" trivially_copy_pass_by_ref = "warn"
wildcard_imports = "warn" wildcard_imports = "warn"
checked_conversions = "warn" checked_conversions = "warn"
#integer_arithmetic = "warn"
#as_conversions = "warn"
# some sadness # some sadness
missing_errors_doc = "allow" missing_errors_doc = "allow"
@@ -642,7 +647,6 @@ map_err_ignore = "allow"
missing_docs_in_private_items = "allow" missing_docs_in_private_items = "allow"
multiple_inherent_impl = "allow" multiple_inherent_impl = "allow"
error_impl_error = "allow" error_impl_error = "allow"
as_conversions = "allow"
string_add = "allow" string_add = "allow"
string_slice = "allow" string_slice = "allow"
ref_patterns = "allow" ref_patterns = "allow"
-10
View File
@@ -2,8 +2,6 @@
`main` / stable: [![CI and Artifacts](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml) `main` / stable: [![CI and Artifacts](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml)
`dev`: [![CI and Artifacts](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml/badge.svg?branch=dev)](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml)
<!-- ANCHOR: catchphrase --> <!-- ANCHOR: catchphrase -->
### a very cool, featureful fork of [Conduit](https://conduit.rs/) ### a very cool, featureful fork of [Conduit](https://conduit.rs/)
<!-- ANCHOR_END: catchphrase --> <!-- ANCHOR_END: catchphrase -->
@@ -37,14 +35,6 @@ from time to time.
<!-- ANCHOR_END: body --> <!-- ANCHOR_END: body -->
<!-- ANCHOR: footer --> <!-- ANCHOR: footer -->
#### How can I contribute?
1. Look for an issue you would like to work on and make sure it's not assigned
to other users
2. Ask someone to assign the issue to you (comment on the issue or chat in
[#conduwuit:puppygock.gay](https://matrix.to/#/#conduwuit:puppygock.gay))
3. Fork the repo and work on the issue.
4. Submit a PR (please keep contributions to the GitHub repo, main development is done here, not the GitLab repo which exists just as a mirror. If you are avoiding GitHub, feel free to join our Matrix chat to get your patch in.)
#### Contact #### Contact
+3 -6
View File
@@ -20,12 +20,9 @@ OCI_IMAGE="complement-conduit:dev"
toplevel="$(git rev-parse --show-toplevel)" toplevel="$(git rev-parse --show-toplevel)"
pushd "$toplevel" > /dev/null pushd "$toplevel" > /dev/null
# uses nix-output-monitor (nom) if available
if command -v nom &> /dev/null; then bin/nix-build-and-cache just .#complement
nom build .#complement
else
nix build -L .#complement
fi
docker load < result docker load < result
popd > /dev/null popd > /dev/null
+34 -20
View File
@@ -13,7 +13,11 @@ just() {
nix build -L "$@" nix build -L "$@"
fi fi
if [ ! -z "$ATTIC_TOKEN" ]; then if [ -z "$ATTIC_TOKEN" ]; then
echo "\$ATTIC_TOKEN is unset, skipping uploading to the binary cache"
return
fi
# historical "conduit" store for compatibility purposes, same as conduwuit # historical "conduit" store for compatibility purposes, same as conduwuit
nix run --inputs-from "$toplevel" attic -- \ nix run --inputs-from "$toplevel" attic -- \
login \ login \
@@ -21,15 +25,25 @@ just() {
"${ATTIC_ENDPOINT:-https://attic.kennel.juneis.dog/conduit}" \ "${ATTIC_ENDPOINT:-https://attic.kennel.juneis.dog/conduit}" \
"$ATTIC_TOKEN" "$ATTIC_TOKEN"
readarray -t outputs < <(nix path-info "$@") # Find all output paths of the installables and their build dependencies
readarray -t derivations < <(nix path-info "$@" --derivation) readarray -t derivations < <(nix path-info --derivation "$@")
cache=()
for derivation in "${derivations[@]}"; do
cache+=(
"$(nix-store --query --requisites --include-outputs "$derivation")"
)
done
# Push the target installable and its build dependencies # Upload them to Attic (conduit store)
nix run --inputs-from "$toplevel" attic -- \ #
push \ # Use `xargs` and a here-string because something would probably explode if
conduit \ # several thousand arguments got passed to a command at once. Hopefully no
"${outputs[@]}" \ # store paths include a newline in them.
"${derivations[@]}" (
IFS=$'\n'
nix shell --inputs-from "$toplevel" attic -c xargs \
attic push conduit <<< "${cache[*]}"
)
# main "conduwuit" store # main "conduwuit" store
nix run --inputs-from "$toplevel" attic -- \ nix run --inputs-from "$toplevel" attic -- \
@@ -38,16 +52,16 @@ just() {
"${ATTIC_ENDPOINT:-https://attic.kennel.juneis.dog/conduwuit}" \ "${ATTIC_ENDPOINT:-https://attic.kennel.juneis.dog/conduwuit}" \
"$ATTIC_TOKEN" "$ATTIC_TOKEN"
# Push the target installable and its build dependencies # Upload them to Attic (conduwuit store)
nix run --inputs-from "$toplevel" attic -- \ #
push \ # Use `xargs` and a here-string because something would probably explode if
conduwuit \ # several thousand arguments got passed to a command at once. Hopefully no
"${outputs[@]}" \ # store paths include a newline in them.
"${derivations[@]}" (
else IFS=$'\n'
echo "\$ATTIC_TOKEN is unset, skipping uploading to the binary cache" nix shell --inputs-from "$toplevel" attic -c xargs \
fi attic push conduwuit <<< "${cache[*]}"
)
} }
# Build and cache things needed for CI # Build and cache things needed for CI
@@ -56,7 +70,7 @@ ci() {
--inputs-from "$toplevel" --inputs-from "$toplevel"
# Keep sorted # Keep sorted
"$toplevel#devShells.x86_64-linux.default.inputDerivation" "$toplevel#devShells.x86_64-linux.default"
attic#default attic#default
nixpkgs#direnv nixpkgs#direnv
nixpkgs#jq nixpkgs#jq
+1
View File
@@ -13,3 +13,4 @@
- [Appservices](appservices.md) - [Appservices](appservices.md)
- [Development](development.md) - [Development](development.md)
- [Testing](development/testing.md) - [Testing](development/testing.md)
- [Contributing](contributing.md)
+1
View File
@@ -0,0 +1 @@
{{#include ../CONTRIBUTING.md}}
-5
View File
@@ -17,17 +17,12 @@ OCI images for conduwuit are available in the registries listed below.
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:main][gh] | ![Image Size][shield-main] | Stable main branch. | | GitHub Registry | [ghcr.io/girlbossceo/conduwuit:main][gh] | ![Image Size][shield-main] | Stable main branch. |
| GitLab Registry | [registry.gitlab.com/girlbossceo/conduwuit:main][gl] | ![Image Size][shield-main] | Stable main branch. | | GitLab Registry | [registry.gitlab.com/girlbossceo/conduwuit:main][gl] | ![Image Size][shield-main] | Stable main branch. |
| Docker Hub | [docker.io/girlbossceo/conduwuit:main][dh] | ![Image Size][shield-main] | Stable main branch. | | Docker Hub | [docker.io/girlbossceo/conduwuit:main][dh] | ![Image Size][shield-main] | Stable main branch. |
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:dev][gh] | ![Image Size][shield-dev] | Development version/branch. |
| GitLab Registry | [registry.gitlab.com/girlbossceo/conduwuit:dev][gl] | ![Image Size][shield-dev] | Development version/branch. |
| Docker Hub | [docker.io/girlbossceo/conduwuit:dev][dh] | ![Image Size][shield-dev] | Development version/branch. |
[dh]: https://hub.docker.com/repository/docker/girlbossceo/conduwuit [dh]: https://hub.docker.com/repository/docker/girlbossceo/conduwuit
[gh]: https://github.com/girlbossceo/conduwuit/pkgs/container/conduwuit [gh]: https://github.com/girlbossceo/conduwuit/pkgs/container/conduwuit
[gl]: https://gitlab.com/girlbossceo/conduwuit/container_registry/6351657 [gl]: https://gitlab.com/girlbossceo/conduwuit/container_registry/6351657
[shield-latest]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/latest [shield-latest]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/latest
[shield-main]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main [shield-main]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main
[shield-dev]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/dev
Use Use
+2 -1
View File
@@ -1,7 +1,8 @@
# Development # Development
Information about developing the project. If you are only interested in using Information about developing the project. If you are only interested in using
it, you can safely ignore this section. it, you can safely ignore this section. If you plan on contributing, see the
[contributor's guide](contributing.md).
## Debugging with `tokio-console` ## Debugging with `tokio-console`
+5 -1
View File
@@ -6,7 +6,7 @@
#### What's different about your fork than upstream Conduit? #### What's different about your fork than upstream Conduit?
See [differences.md](differences.md) See the [differences](differences.md) page
#### How can I deploy my own? #### How can I deploy my own?
@@ -14,4 +14,8 @@ See [differences.md](differences.md)
If you want to connect an Appservice to Conduwuit, take a look at the [appservices documentation](appservices.md). If you want to connect an Appservice to Conduwuit, take a look at the [appservices documentation](appservices.md).
#### How can I contribute?
See the [contributor's guide](contributing.md)
{{#include ../README.md:footer}} {{#include ../README.md:footer}}
+1 -1
View File
@@ -131,7 +131,7 @@ cargo clippy \
[[task]] [[task]]
name = "lychee" name = "lychee"
group = "lints" group = "lints"
script = "lychee --offline docs" script = "lychee --verbose --offline docs *.md"
[[task]] [[task]]
name = "cargo" name = "cargo"
Generated
+5 -5
View File
@@ -238,15 +238,15 @@
"rocksdb": { "rocksdb": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1713810944, "lastModified": 1714770052,
"narHash": "sha256-/Xf0bzNJPclH9IP80QNaABfhj4IAR5LycYET18VFCXc=", "narHash": "sha256-NCPYF2wYBsB9OHEkZSOYoPlxjC9BBMhJp8EM5M1o3Mc=",
"owner": "facebook", "owner": "girlbossceo",
"repo": "rocksdb", "repo": "rocksdb",
"rev": "6f7cabeac80a3a6150be2c8a8369fcecb107bf43", "rev": "db6df0b185774778457dabfcbd822cb81760cade",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "facebook", "owner": "girlbossceo",
"ref": "v9.1.1", "ref": "v9.1.1",
"repo": "rocksdb", "repo": "rocksdb",
"type": "github" "type": "github"
+7 -2
View File
@@ -8,7 +8,8 @@
flake-utils.url = "github:numtide/flake-utils?ref=main"; flake-utils.url = "github:numtide/flake-utils?ref=main";
nix-filter.url = "github:numtide/nix-filter?ref=main"; nix-filter.url = "github:numtide/nix-filter?ref=main";
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
rocksdb = { url = "github:facebook/rocksdb?ref=v9.1.1"; flake = false; }; # https://github.com/girlbossceo/rocksdb/commit/db6df0b185774778457dabfcbd822cb81760cade
rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.1.1"; flake = false; };
}; };
outputs = inputs: outputs = inputs:
@@ -21,7 +22,7 @@
file = ./rust-toolchain.toml; file = ./rust-toolchain.toml;
# See also `rust-toolchain.toml` # See also `rust-toolchain.toml`
sha256 = "sha256-e4mlaJehWBymYxJGgnbuCObVlqMlQSilZ8FljG9zPHY="; sha256 = "sha256-+syqAd2kX8KVa8/U2gz3blIQTTsYYt3U63xBWaGOSc8";
}; };
scope = pkgs: pkgs.lib.makeScope pkgs.newScope (self: { scope = pkgs: pkgs.lib.makeScope pkgs.newScope (self: {
@@ -179,6 +180,10 @@
# Useful for editing the book locally # Useful for editing the book locally
mdbook mdbook
]) ])
++ (if !pkgsHost.stdenv.isDarwin then [
# Needed for building with io_uring
pkgsHost.liburing
] else [])
++ ++
scopeHost.main.nativeBuildInputs; scopeHost.main.nativeBuildInputs;
}; };
+7 -1
View File
@@ -37,7 +37,7 @@ buildDepsOnlyEnv =
}); });
buildPackageEnv = { buildPackageEnv = {
CONDUWUIT_VERSION_EXTRA = inputs.self.shortRev or inputs.self.dirtyShortRev; CONDUWUIT_VERSION_EXTRA = inputs.self.shortRev or inputs.self.dirtyShortRev or "";
} // buildDepsOnlyEnv; } // buildDepsOnlyEnv;
commonAttrs = { commonAttrs = {
@@ -83,9 +83,15 @@ craneLib.buildPackage ( commonAttrs // {
(features != []) (features != [])
"--features " + (builtins.concatStringsSep "," features); "--features " + (builtins.concatStringsSep "," features);
# This is redundant with CI
cargoTestCommand = "";
# This is redundant with CI # This is redundant with CI
doCheck = false; doCheck = false;
# https://crane.dev/faq/rebuilds-bindgen.html
NIX_OUTPATH_USED_AS_RANDOM_SEED = "aaaaaaaaaa";
env = buildPackageEnv; env = buildPackageEnv;
passthru = { passthru = {
+1 -1
View File
@@ -11,7 +11,7 @@
# If you're having trouble making the relevant changes, bug a maintainer. # If you're having trouble making the relevant changes, bug a maintainer.
[toolchain] [toolchain]
channel = "1.76.0" channel = "1.77.0"
components = [ components = [
# For rust-analyzer # For rust-analyzer
"rust-src", "rust-src",
+41 -28
View File
@@ -1,3 +1,5 @@
use std::fmt::Write as _;
use register::RegistrationKind; use register::RegistrationKind;
use ruma::{ use ruma::{
api::client::{ api::client::{
@@ -238,7 +240,7 @@ pub(crate) async fn register_route(body: Ruma<register::v3::Request>) -> Result<
// If `new_user_displayname_suffix` is set, registration will push whatever // If `new_user_displayname_suffix` is set, registration will push whatever
// content is set to the user's display name with a space before it // content is set to the user's display name with a space before it
if !services().globals.new_user_displayname_suffix().is_empty() { if !services().globals.new_user_displayname_suffix().is_empty() {
displayname.push_str(&(" ".to_owned() + services().globals.new_user_displayname_suffix())); _ = write!(displayname, " {}", services().globals.config.new_user_displayname_suffix);
} }
services() services()
@@ -355,33 +357,7 @@ pub(crate) async fn register_route(body: Ruma<register::v3::Request>) -> Result<
&& !services().globals.config.auto_join_rooms.is_empty() && !services().globals.config.auto_join_rooms.is_empty()
&& (services().globals.allow_guests_auto_join_rooms() || !is_guest) && (services().globals.allow_guests_auto_join_rooms() || !is_guest)
{ {
for room in &services().globals.config.auto_join_rooms { auto_join_rooms(&user_id).await?;
if !services()
.rooms
.state_cache
.server_in_room(services().globals.server_name(), room)?
{
warn!("Skipping room {room} to automatically join as we have never joined before.");
continue;
}
if let Some(room_id_server_name) = room.server_name() {
if let Err(e) = join_room_by_id_helper(
Some(&user_id),
room,
Some("Automatically joining this room upon registration".to_owned()),
&[room_id_server_name.to_owned(), services().globals.server_name().to_owned()],
None,
)
.await
{
// don't return this error so we don't fail registrations
error!("Failed to automatically join room {room} for user {user_id}: {e}");
} else {
info!("Automatically joined room {room} for user {user_id}");
};
}
}
} }
Ok(register::v3::Response { Ok(register::v3::Response {
@@ -591,3 +567,40 @@ pub(crate) async fn request_3pid_management_token_via_msisdn_route(
"Third party identifier is not allowed", "Third party identifier is not allowed",
)) ))
} }
/// Auto joins all the specified users to the rooms listed in the
/// `auto_join_rooms` config option
///
/// TODO: can this be moved somewhere else instead of this file where routes are
/// typically defined?
pub(crate) async fn auto_join_rooms(user_id: &UserId) -> Result<()> {
for room in &services().globals.config.auto_join_rooms {
if !services()
.rooms
.state_cache
.server_in_room(&services().globals.config.server_name, room)?
{
warn!("Skipping room {room} to automatically join as we have never joined before.");
continue;
}
if let Some(room_id_server_name) = room.server_name() {
if let Err(e) = join_room_by_id_helper(
Some(user_id),
room,
Some("Automatically joining this room upon registration".to_owned()),
&[room_id_server_name.to_owned(), services().globals.config.server_name.clone()],
None,
)
.await
{
// don't return this error so we don't fail registrations
error!("Failed to automatically join room {room} for user {user_id}: {e}");
} else {
info!("Automatically joined room {room} for user {user_id}");
};
}
}
Ok(())
}
+1 -3
View File
@@ -269,9 +269,7 @@ async fn alias_checks(room_alias: &OwnedRoomAliasId, appservice_info: &Option<Re
if !info.aliases.is_match(room_alias.as_str()) { if !info.aliases.is_match(room_alias.as_str()) {
return Err(Error::BadRequest(ErrorKind::Exclusive, "Room alias is not in namespace.")); return Err(Error::BadRequest(ErrorKind::Exclusive, "Room alias is not in namespace."));
} }
} } else if services().appservice.is_exclusive_alias(room_alias).await {
if services().appservice.is_exclusive_alias(room_alias).await {
return Err(Error::BadRequest(ErrorKind::Exclusive, "Room alias reserved by appservice.")); return Err(Error::BadRequest(ErrorKind::Exclusive, "Room alias reserved by appservice."));
} }
+41 -23
View File
@@ -1,4 +1,5 @@
use ruma::api::client::{ use ruma::{
api::client::{
backup::{ backup::{
add_backup_keys, add_backup_keys_for_room, add_backup_keys_for_session, create_backup_version, add_backup_keys, add_backup_keys_for_room, add_backup_keys_for_session, create_backup_version,
delete_backup_keys, delete_backup_keys_for_room, delete_backup_keys_for_session, delete_backup_version, delete_backup_keys, delete_backup_keys_for_room, delete_backup_keys_for_session, delete_backup_version,
@@ -6,6 +7,8 @@ use ruma::api::client::{
get_latest_backup_info, update_backup_version, get_latest_backup_info, update_backup_version,
}, },
error::ErrorKind, error::ErrorKind,
},
UInt,
}; };
use crate::{services, Error, Result, Ruma}; use crate::{services, Error, Result, Ruma};
@@ -56,7 +59,8 @@ pub(crate) async fn get_latest_backup_info_route(
Ok(get_latest_backup_info::v3::Response { Ok(get_latest_backup_info::v3::Response {
algorithm, algorithm,
count: (services().key_backups.count_keys(sender_user, &version)? as u32).into(), count: (UInt::try_from(services().key_backups.count_keys(sender_user, &version)?)
.expect("user backup keys count should not be that high")),
etag: services().key_backups.get_etag(sender_user, &version)?, etag: services().key_backups.get_etag(sender_user, &version)?,
version, version,
}) })
@@ -76,10 +80,12 @@ pub(crate) async fn get_backup_info_route(
Ok(get_backup_info::v3::Response { Ok(get_backup_info::v3::Response {
algorithm, algorithm,
count: (services() count: (UInt::try_from(
services()
.key_backups .key_backups
.count_keys(sender_user, &body.version)? as u32) .count_keys(sender_user, &body.version)?,
.into(), )
.expect("user backup keys count should not be that high")),
etag: services() etag: services()
.key_backups .key_backups
.get_etag(sender_user, &body.version)?, .get_etag(sender_user, &body.version)?,
@@ -139,10 +145,12 @@ pub(crate) async fn add_backup_keys_route(
} }
Ok(add_backup_keys::v3::Response { Ok(add_backup_keys::v3::Response {
count: (services() count: (UInt::try_from(
services()
.key_backups .key_backups
.count_keys(sender_user, &body.version)? as u32) .count_keys(sender_user, &body.version)?,
.into(), )
.expect("user backup keys count should not be that high")),
etag: services() etag: services()
.key_backups .key_backups
.get_etag(sender_user, &body.version)?, .get_etag(sender_user, &body.version)?,
@@ -181,10 +189,12 @@ pub(crate) async fn add_backup_keys_for_room_route(
} }
Ok(add_backup_keys_for_room::v3::Response { Ok(add_backup_keys_for_room::v3::Response {
count: (services() count: (UInt::try_from(
services()
.key_backups .key_backups
.count_keys(sender_user, &body.version)? as u32) .count_keys(sender_user, &body.version)?,
.into(), )
.expect("user backup keys count should not be that high")),
etag: services() etag: services()
.key_backups .key_backups
.get_etag(sender_user, &body.version)?, .get_etag(sender_user, &body.version)?,
@@ -221,10 +231,12 @@ pub(crate) async fn add_backup_keys_for_session_route(
.add_key(sender_user, &body.version, &body.room_id, &body.session_id, &body.session_data)?; .add_key(sender_user, &body.version, &body.room_id, &body.session_id, &body.session_data)?;
Ok(add_backup_keys_for_session::v3::Response { Ok(add_backup_keys_for_session::v3::Response {
count: (services() count: (UInt::try_from(
services()
.key_backups .key_backups
.count_keys(sender_user, &body.version)? as u32) .count_keys(sender_user, &body.version)?,
.into(), )
.expect("user backup keys count should not be that high")),
etag: services() etag: services()
.key_backups .key_backups
.get_etag(sender_user, &body.version)?, .get_etag(sender_user, &body.version)?,
@@ -294,10 +306,12 @@ pub(crate) async fn delete_backup_keys_route(
.delete_all_keys(sender_user, &body.version)?; .delete_all_keys(sender_user, &body.version)?;
Ok(delete_backup_keys::v3::Response { Ok(delete_backup_keys::v3::Response {
count: (services() count: (UInt::try_from(
services()
.key_backups .key_backups
.count_keys(sender_user, &body.version)? as u32) .count_keys(sender_user, &body.version)?,
.into(), )
.expect("user backup keys count should not be that high")),
etag: services() etag: services()
.key_backups .key_backups
.get_etag(sender_user, &body.version)?, .get_etag(sender_user, &body.version)?,
@@ -317,10 +331,12 @@ pub(crate) async fn delete_backup_keys_for_room_route(
.delete_room_keys(sender_user, &body.version, &body.room_id)?; .delete_room_keys(sender_user, &body.version, &body.room_id)?;
Ok(delete_backup_keys_for_room::v3::Response { Ok(delete_backup_keys_for_room::v3::Response {
count: (services() count: (UInt::try_from(
services()
.key_backups .key_backups
.count_keys(sender_user, &body.version)? as u32) .count_keys(sender_user, &body.version)?,
.into(), )
.expect("user backup keys count should not be that high")),
etag: services() etag: services()
.key_backups .key_backups
.get_etag(sender_user, &body.version)?, .get_etag(sender_user, &body.version)?,
@@ -340,10 +356,12 @@ pub(crate) async fn delete_backup_keys_for_session_route(
.delete_room_key(sender_user, &body.version, &body.room_id, &body.session_id)?; .delete_room_key(sender_user, &body.version, &body.room_id, &body.session_id)?;
Ok(delete_backup_keys_for_session::v3::Response { Ok(delete_backup_keys_for_session::v3::Response {
count: (services() count: (UInt::try_from(
services()
.key_backups .key_backups
.count_keys(sender_user, &body.version)? as u32) .count_keys(sender_user, &body.version)?,
.into(), )
.expect("user backup keys count should not be that high")),
etag: services() etag: services()
.key_backups .key_backups
.get_etag(sender_user, &body.version)?, .get_etag(sender_user, &body.version)?,
+2 -2
View File
@@ -63,8 +63,8 @@ pub(crate) async fn get_context_route(body: Ruma<get_context::v3::Request>) -> R
lazy_loaded.insert(base_event.sender.as_str().to_owned()); lazy_loaded.insert(base_event.sender.as_str().to_owned());
} }
// Use limit with maximum 100 // Use limit or else 10, with maximum 100
let limit = u64::from(body.limit).min(100) as usize; let limit = usize::try_from(body.limit).unwrap_or(10).min(100);
let base_event = base_event.to_room_event(); let base_event = base_event.to_room_event();
+17 -7
View File
@@ -20,7 +20,7 @@ use ruma::{
}, },
StateEventType, StateEventType,
}, },
ServerName, UInt, uint, ServerName, UInt,
}; };
use tracing::{error, info, warn}; use tracing::{error, info, warn};
@@ -198,8 +198,9 @@ pub(crate) async fn get_public_rooms_filtered_helper(
}); });
} }
// Use limit or else 10, with maximum 100
let limit = limit.map_or(10, u64::from); let limit = limit.map_or(10, u64::from);
let mut num_since = 0_u64; let mut num_since: u64 = 0;
if let Some(s) = &since { if let Some(s) = &since {
let mut characters = s.chars(); let mut characters = s.chars();
@@ -363,12 +364,16 @@ pub(crate) async fn get_public_rooms_filtered_helper(
all_rooms.sort_by(|l, r| r.num_joined_members.cmp(&l.num_joined_members)); all_rooms.sort_by(|l, r| r.num_joined_members.cmp(&l.num_joined_members));
let total_room_count_estimate = (all_rooms.len() as u32).into(); let total_room_count_estimate = UInt::try_from(all_rooms.len()).unwrap_or_else(|_| uint!(0));
let chunk: Vec<_> = all_rooms let chunk: Vec<_> = all_rooms
.into_iter() .into_iter()
.skip(num_since as usize) .skip(
.take(limit as usize) num_since
.try_into()
.expect("num_since should not be this high"),
)
.take(limit.try_into().expect("limit should not be this high"))
.collect(); .collect();
let prev_batch = if num_since == 0 { let prev_batch = if num_since == 0 {
@@ -377,10 +382,15 @@ pub(crate) async fn get_public_rooms_filtered_helper(
Some(format!("p{num_since}")) Some(format!("p{num_since}"))
}; };
let next_batch = if chunk.len() < limit as usize { let next_batch = if chunk.len() < limit.try_into().unwrap() {
None None
} else { } else {
Some(format!("n{}", num_since + limit)) 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 { Ok(get_public_rooms_filtered::v3::Response {
+6 -5
View File
@@ -1,4 +1,5 @@
use std::{ use std::{
cmp,
collections::{hash_map, BTreeMap, HashMap, HashSet}, collections::{hash_map, BTreeMap, HashMap, HashSet},
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@@ -338,7 +339,9 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
hash_map::Entry::Vacant(e) => { hash_map::Entry::Vacant(e) => {
e.insert((Instant::now(), 1)); e.insert((Instant::now(), 1));
}, },
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1), hash_map::Entry::Occupied(mut e) => {
*e.get_mut() = (Instant::now(), e.get().1.saturating_add(1));
},
} }
}; };
@@ -353,10 +356,8 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
.get(server) .get(server)
{ {
// Exponential backoff // Exponential backoff
let mut min_elapsed_duration = Duration::from_secs(5 * 60) * (*tries) * (*tries); const MAX_DURATION: Duration = Duration::from_secs(60 * 60 * 24);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) { let min_elapsed_duration = cmp::min(MAX_DURATION, Duration::from_secs(5 * 60) * (*tries) * (*tries));
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
}
if time.elapsed() < min_elapsed_duration { if time.elapsed() < min_elapsed_duration {
debug!("Backing off query from {:?}", server); debug!("Backing off query from {:?}", server);
+22 -8
View File
@@ -130,7 +130,7 @@ pub(crate) async fn create_content_route(
mxc.clone(), mxc.clone(),
body.filename body.filename
.as_ref() .as_ref()
.map(|filename| "inline; filename=".to_owned() + filename) .map(|filename| format!("attachment; filename={filename}"))
.as_deref(), .as_deref(),
body.content_type.as_deref(), body.content_type.as_deref(),
&body.file, &body.file,
@@ -173,15 +173,16 @@ pub(crate) async fn get_content_route(body: Ruma<get_content::v3::Request>) -> R
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id); let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
if let Some(FileMeta { if let Some(FileMeta {
content_disposition,
content_type, content_type,
file, file,
..
}) = services().media.get(mxc.clone()).await? }) = services().media.get(mxc.clone()).await?
{ {
// TODO: safely sanitise filename to be included in the content-disposition
Ok(get_content::v3::Response { Ok(get_content::v3::Response {
file, file,
content_type, content_type,
content_disposition, content_disposition: Some("attachment".to_owned()),
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()), cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()), cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
}) })
@@ -243,7 +244,7 @@ pub(crate) async fn get_content_as_filename_route(
Ok(get_content_as_filename::v3::Response { Ok(get_content_as_filename::v3::Response {
file, file,
content_type, content_type,
content_disposition: Some(format!("inline; filename={}", body.filename)), content_disposition: Some("attachment".to_owned()),
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()), cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()), cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
}) })
@@ -258,7 +259,7 @@ pub(crate) async fn get_content_as_filename_route(
.await .await
{ {
Ok(remote_content_response) => Ok(get_content_as_filename::v3::Response { Ok(remote_content_response) => Ok(get_content_as_filename::v3::Response {
content_disposition: Some(format!("inline: filename={}", body.filename)), content_disposition: Some("attachment".to_owned()),
content_type: remote_content_response.content_type, content_type: remote_content_response.content_type,
file: remote_content_response.file, file: remote_content_response.file,
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()), cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
@@ -327,6 +328,7 @@ pub(crate) async fn get_content_thumbnail_route(
content_type, content_type,
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()), cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()), cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
content_disposition: Some("attachment".to_owned()),
}) })
} else if !server_is_ours(&body.server_name) && body.allow_remote { } else if !server_is_ours(&body.server_name) && body.allow_remote {
if services() if services()
@@ -371,7 +373,13 @@ pub(crate) async fn get_content_thumbnail_route(
) )
.await?; .await?;
Ok(get_thumbnail_response) Ok(get_content_thumbnail::v3::Response {
file: get_thumbnail_response.file,
content_type: get_thumbnail_response.content_type,
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
content_disposition: Some("attachment".to_owned()),
})
}, },
Err(e) => { Err(e) => {
debug_warn!("Fetching media `{}` failed: {:?}", mxc, e); debug_warn!("Fetching media `{}` failed: {:?}", mxc, e);
@@ -434,13 +442,19 @@ async fn get_remote_content(
.create( .create(
None, None,
mxc.to_owned(), mxc.to_owned(),
content_response.content_disposition.as_deref(), Some("attachment"),
content_response.content_type.as_deref(), content_response.content_type.as_deref(),
&content_response.file, &content_response.file,
) )
.await?; .await?;
Ok(content_response) Ok(get_content::v3::Response {
file: content_response.file,
content_type: content_response.content_type,
content_disposition: Some("attachment".to_owned()),
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
})
} }
async fn download_image(client: &reqwest::Client, url: &str) -> Result<UrlPreviewData> { async fn download_image(client: &reqwest::Client, url: &str) -> Result<UrlPreviewData> {
+10 -9
View File
@@ -1,4 +1,5 @@
use std::{ use std::{
cmp,
collections::{hash_map::Entry, BTreeMap, HashMap, HashSet}, collections::{hash_map::Entry, BTreeMap, HashMap, HashSet},
sync::Arc, sync::Arc,
time::{Duration, Instant}, time::{Duration, Instant},
@@ -1301,8 +1302,8 @@ async fn make_join_request(
) -> Result<(federation::membership::prepare_join_event::v1::Response, OwnedServerName)> { ) -> Result<(federation::membership::prepare_join_event::v1::Response, OwnedServerName)> {
let mut make_join_response_and_server = Err(Error::BadServerResponse("No server available to assist in joining.")); let mut make_join_response_and_server = Err(Error::BadServerResponse("No server available to assist in joining."));
let mut make_join_counter = 0; let mut make_join_counter: u16 = 0;
let mut incompatible_room_version_count = 0; let mut incompatible_room_version_count: u8 = 0;
for remote_server in servers { for remote_server in servers {
if server_is_ours(remote_server) { if server_is_ours(remote_server) {
@@ -1322,7 +1323,7 @@ async fn make_join_request(
.await; .await;
trace!("make_join response: {:?}", make_join_response); trace!("make_join response: {:?}", make_join_response);
make_join_counter += 1; make_join_counter = make_join_counter.saturating_add(1);
if let Err(ref e) = make_join_response { if let Err(ref e) = make_join_response {
trace!("make_join ErrorKind string: {:?}", e.error_code().to_string()); trace!("make_join ErrorKind string: {:?}", e.error_code().to_string());
@@ -1336,7 +1337,7 @@ async fn make_join_request(
.to_string() .to_string()
.contains("M_UNSUPPORTED_ROOM_VERSION") .contains("M_UNSUPPORTED_ROOM_VERSION")
{ {
incompatible_room_version_count += 1; incompatible_room_version_count = incompatible_room_version_count.saturating_add(1);
} }
if incompatible_room_version_count > 15 { if incompatible_room_version_count > 15 {
@@ -1393,7 +1394,9 @@ async fn validate_and_add_event_id(
Entry::Vacant(e) => { Entry::Vacant(e) => {
e.insert((Instant::now(), 1)); e.insert((Instant::now(), 1));
}, },
Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1), Entry::Occupied(mut e) => {
*e.get_mut() = (Instant::now(), e.get().1.saturating_add(1));
},
} }
}; };
@@ -1405,10 +1408,8 @@ async fn validate_and_add_event_id(
.get(&event_id) .get(&event_id)
{ {
// Exponential backoff // Exponential backoff
let mut min_elapsed_duration = Duration::from_secs(5 * 60) * (*tries) * (*tries); const MAX_DURATION: Duration = Duration::from_secs(60 * 60 * 24);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) { let min_elapsed_duration = cmp::min(MAX_DURATION, Duration::from_secs(5 * 60) * (*tries) * (*tries));
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
}
if time.elapsed() < min_elapsed_duration { if time.elapsed() < min_elapsed_duration {
debug!("Backing off from {}", event_id); debug!("Backing off from {}", event_id);
+5 -5
View File
@@ -144,7 +144,7 @@ pub(crate) async fn get_message_events_route(
.lazy_load_confirm_delivery(sender_user, sender_device, &body.room_id, from) .lazy_load_confirm_delivery(sender_user, sender_device, &body.room_id, from)
.await?; .await?;
let limit = u64::from(body.limit).min(100) as usize; let limit = usize::try_from(body.limit).unwrap_or(10).min(100);
let next_token; let next_token;
@@ -159,8 +159,9 @@ pub(crate) async fn get_message_events_route(
.timeline .timeline
.pdus_after(sender_user, &body.room_id, from)? .pdus_after(sender_user, &body.room_id, from)?
.filter_map(Result::ok) // Filter out buggy events .filter_map(Result::ok) // Filter out buggy events
.filter(|(_, pdu)| contains_url_filter(pdu, &body.filter)) .filter(|(_, pdu)| { contains_url_filter(pdu, &body.filter) && visibility_filter(pdu, sender_user, &body.room_id)
.filter(|(_, pdu)| visibility_filter(pdu, sender_user, &body.room_id))
})
.take_while(|&(k, _)| Some(k) != to) // Stop at `to` .take_while(|&(k, _)| Some(k) != to) // Stop at `to`
.take(limit) .take(limit)
.collect(); .collect();
@@ -205,8 +206,7 @@ pub(crate) async fn get_message_events_route(
.timeline .timeline
.pdus_until(sender_user, &body.room_id, from)? .pdus_until(sender_user, &body.room_id, from)?
.filter_map(Result::ok) // Filter out buggy events .filter_map(Result::ok) // Filter out buggy events
.filter(|(_, pdu)| contains_url_filter(pdu, &body.filter)) .filter(|(_, pdu)| {contains_url_filter(pdu, &body.filter) && visibility_filter(pdu, sender_user, &body.room_id)})
.filter(|(_, pdu)| visibility_filter(pdu, sender_user, &body.room_id))
.take_while(|&(k, _)| Some(k) != to) // Stop at `to` .take_while(|&(k, _)| Some(k) != to) // Stop at `to`
.take(limit) .take(limit)
.collect(); .collect();
+12 -1
View File
@@ -49,9 +49,20 @@ pub(crate) async fn get_presence_route(body: Ruma<get_presence::v3::Request>) ->
} }
if let Some(presence) = presence_event { if let Some(presence) = presence_event {
let status_msg = if presence
.content
.status_msg
.as_ref()
.is_some_and(String::is_empty)
{
None
} else {
presence.content.status_msg
};
Ok(get_presence::v3::Response { Ok(get_presence::v3::Response {
// TODO: Should ruma just use the presenceeventcontent type here? // TODO: Should ruma just use the presenceeventcontent type here?
status_msg: presence.content.status_msg, status_msg,
currently_active: presence.content.currently_active, currently_active: presence.content.currently_active,
last_active_ago: presence last_active_ago: presence
.content .content
+9 -1
View File
@@ -801,7 +801,15 @@ pub(crate) async fn upgrade_room_route(body: Ruma<upgrade_room::v3::Request>) ->
.map_err(|_| Error::bad_database("Invalid room event in database."))?; .map_err(|_| Error::bad_database("Invalid room event in database."))?;
// Setting events_default and invite to the greater of 50 and users_default + 1 // Setting events_default and invite to the greater of 50 and users_default + 1
let new_level = max(int!(50), power_levels_event_content.users_default + int!(1)); let new_level = max(
int!(50),
power_levels_event_content
.users_default
.checked_add(int!(1))
.ok_or_else(|| {
Error::BadRequest(ErrorKind::BadJson, "users_default power levels event content is not valid")
})?,
);
power_levels_event_content.events_default = new_level; power_levels_event_content.events_default = new_level;
power_levels_event_content.invite = new_level; power_levels_event_content.invite = new_level;
+13 -6
View File
@@ -10,7 +10,7 @@ use ruma::{
}, },
events::AnyStateEvent, events::AnyStateEvent,
serde::Raw, serde::Raw,
OwnedRoomId, uint, OwnedRoomId,
}; };
use tracing::debug; use tracing::debug;
@@ -39,7 +39,12 @@ pub(crate) async fn search_events_route(body: Ruma<search_events::v3::Request>)
}); });
// Use limit or else 10, with maximum 100 // Use limit or else 10, with maximum 100
let limit = filter.limit.map_or(10, u64::from).min(100) as usize; let limit: usize = filter
.limit
.unwrap_or_else(|| uint!(10))
.try_into()
.unwrap_or(10)
.min(100);
let mut room_states: BTreeMap<OwnedRoomId, Vec<Raw<AnyStateEvent>>> = BTreeMap::new(); let mut room_states: BTreeMap<OwnedRoomId, Vec<Raw<AnyStateEvent>>> = BTreeMap::new();
@@ -106,14 +111,16 @@ pub(crate) async fn search_events_route(body: Ruma<search_events::v3::Request>)
} }
} }
let skip = match body.next_batch.as_ref().map(|s| s.parse()) { let skip: usize = match body.next_batch.as_ref().map(|s| s.parse()) {
Some(Ok(s)) => s, Some(Ok(s)) => s,
Some(Err(_)) => return Err(Error::BadRequest(ErrorKind::InvalidParam, "Invalid next_batch token.")), Some(Err(_)) => return Err(Error::BadRequest(ErrorKind::InvalidParam, "Invalid next_batch token.")),
None => 0, // Default to the start None => 0, // Default to the start
}; };
let mut results = Vec::new(); let mut results = Vec::new();
for _ in 0..skip + limit { let next_batch: usize = skip.saturating_add(limit);
for _ in 0..next_batch {
if let Some(s) = searches if let Some(s) = searches
.iter_mut() .iter_mut()
.map(|s| (s.peek().cloned(), s)) .map(|s| (s.peek().cloned(), s))
@@ -162,12 +169,12 @@ pub(crate) async fn search_events_route(body: Ruma<search_events::v3::Request>)
let next_batch = if results.len() < limit { let next_batch = if results.len() < limit {
None None
} else { } else {
Some((skip + limit).to_string()) Some(next_batch.to_string())
}; };
Ok(search_events::v3::Response::new(ResultCategories { Ok(search_events::v3::Response::new(ResultCategories {
room_events: ResultRoomEvents { room_events: ResultRoomEvents {
count: Some((results.len() as u32).into()), count: Some(results.len().try_into().unwrap_or_else(|_| uint!(0))),
groups: BTreeMap::new(), // TODO groups: BTreeMap::new(), // TODO
next_batch, next_batch,
results, results,
+9 -7
View File
@@ -2,7 +2,7 @@ use std::str::FromStr;
use ruma::{ use ruma::{
api::client::{error::ErrorKind, space::get_hierarchy}, api::client::{error::ErrorKind, space::get_hierarchy},
UInt, uint, UInt,
}; };
use crate::{service::rooms::spaces::PagnationToken, services, Error, Result, Ruma}; use crate::{service::rooms::spaces::PagnationToken, services, Error, Result, Ruma};
@@ -14,10 +14,12 @@ use crate::{service::rooms::spaces::PagnationToken, services, Error, Result, Rum
pub(crate) async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>) -> Result<get_hierarchy::v1::Response> { pub(crate) async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>) -> Result<get_hierarchy::v1::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated"); let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let limit = body let limit: usize = body
.limit .limit
.unwrap_or_else(|| UInt::from(10_u32)) .unwrap_or_else(|| uint!(10))
.min(UInt::from(100_u32)); .try_into()
.unwrap_or(10)
.min(100);
let max_depth = body let max_depth = body
.max_depth .max_depth
@@ -45,9 +47,9 @@ pub(crate) async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>)
.get_client_hierarchy( .get_client_hierarchy(
sender_user, sender_user,
&body.room_id, &body.room_id,
u64::from(limit) as usize, limit,
key.map_or(0, |token| u64::from(token.skip) as usize), key.map_or(0, |token| token.skip.try_into().unwrap_or(0)),
u64::from(max_depth) as usize, max_depth.try_into().unwrap_or(3),
body.suggested_only, body.suggested_only,
) )
.await .await
+18 -15
View File
@@ -539,7 +539,7 @@ async fn handle_left_room(
left_state_ids.insert(leave_shortstatekey, left_event_id); left_state_ids.insert(leave_shortstatekey, left_event_id);
let mut i = 0; let mut i: u8 = 0;
for (key, id) in left_state_ids { for (key, id) in left_state_ids {
if full_state || since_state_ids.get(&key) != Some(&id) { if full_state || since_state_ids.get(&key) != Some(&id) {
let (event_type, state_key) = services().rooms.short.get_statekey_from_short(key)?; let (event_type, state_key) = services().rooms.short.get_statekey_from_short(key)?;
@@ -557,7 +557,7 @@ async fn handle_left_room(
left_state_events.push(pdu.to_sync_state_event()); left_state_events.push(pdu.to_sync_state_event());
i += 1; i = i.wrapping_add(1);
if i % 100 == 0 { if i % 100 == 0 {
tokio::task::yield_now().await; tokio::task::yield_now().await;
} }
@@ -705,7 +705,7 @@ async fn load_joined_room(
// Recalculate heroes (first 5 members) // Recalculate heroes (first 5 members)
let mut heroes = Vec::new(); let mut heroes = Vec::new();
if joined_member_count + invited_member_count <= 5 { if joined_member_count.saturating_add(invited_member_count) <= 5 {
// Go through all PDUs and for each member event, check if the user is still // Go through all PDUs and for each member event, check if the user is still
// joined or invited until we have 5 or we reach the end // joined or invited until we have 5 or we reach the end
@@ -784,7 +784,7 @@ async fn load_joined_room(
let mut state_events = Vec::new(); let mut state_events = Vec::new();
let mut lazy_loaded = HashSet::new(); let mut lazy_loaded = HashSet::new();
let mut i = 0; let mut i: u8 = 0;
for (shortstatekey, id) in current_state_ids { for (shortstatekey, id) in current_state_ids {
let (event_type, state_key) = services() let (event_type, state_key) = services()
.rooms .rooms
@@ -798,7 +798,7 @@ async fn load_joined_room(
}; };
state_events.push(pdu); state_events.push(pdu);
i += 1; i = i.wrapping_add(1);
if i % 100 == 0 { if i % 100 == 0 {
tokio::task::yield_now().await; tokio::task::yield_now().await;
} }
@@ -819,7 +819,7 @@ async fn load_joined_room(
} }
state_events.push(pdu); state_events.push(pdu);
i += 1; i = i.wrapping_add(1);
if i % 100 == 0 { if i % 100 == 0 {
tokio::task::yield_now().await; tokio::task::yield_now().await;
} }
@@ -1416,10 +1416,14 @@ pub(crate) async fn sync_events_v4_route(
.ranges .ranges
.into_iter() .into_iter()
.map(|mut r| { .map(|mut r| {
r.0 = r.0 = r.0.clamp(
r.0.clamp(uint!(0), UInt::from(all_joined_rooms.len() as u32 - 1)); uint!(0),
r.1 = UInt::try_from(all_joined_rooms.len().saturating_sub(1)).unwrap_or(UInt::MAX),
r.1.clamp(r.0, UInt::from(all_joined_rooms.len() as u32 - 1)); );
r.1 = r.1.clamp(
r.0,
UInt::try_from(all_joined_rooms.len().saturating_sub(1)).unwrap_or(UInt::MAX),
);
let room_ids = all_joined_rooms[(u64::from(r.0) as usize)..=(u64::from(r.1) as usize)].to_vec(); let room_ids = all_joined_rooms[(u64::from(r.0) as usize)..=(u64::from(r.1) as usize)].to_vec();
new_known_rooms.extend(room_ids.iter().cloned()); new_known_rooms.extend(room_ids.iter().cloned());
for room_id in &room_ids { for room_id in &room_ids {
@@ -1592,14 +1596,13 @@ pub(crate) async fn sync_events_v4_route(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let name = match heroes.len().cmp(&(1_usize)) { let name = match heroes.len().cmp(&(1_usize)) {
Ordering::Greater => { Ordering::Greater => {
let last = heroes[0].0.clone(); let firsts = heroes[1..]
Some(
heroes[1..]
.iter() .iter()
.map(|h| h.0.clone()) .map(|h| h.0.clone())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") + " and " + &last, .join(", ");
) let last = heroes[0].0.clone();
Some(format!("{firsts} and {last}"))
}, },
Ordering::Equal => Some(heroes[0].0.clone()), Ordering::Equal => Some(heroes[0].0.clone()),
Ordering::Less => None, Ordering::Less => None,
+6 -2
View File
@@ -1,4 +1,7 @@
use ruma::api::client::{error::ErrorKind, threads::get_threads}; use ruma::{
api::client::{error::ErrorKind, threads::get_threads},
uint,
};
use crate::{services, Error, Result, Ruma}; use crate::{services, Error, Result, Ruma};
@@ -9,7 +12,8 @@ pub(crate) async fn get_threads_route(body: Ruma<get_threads::v1::Request>) -> R
// Use limit or else 10, with maximum 100 // Use limit or else 10, with maximum 100
let limit = body let limit = body
.limit .limit
.and_then(|l| l.try_into().ok()) .unwrap_or_else(|| uint!(10))
.try_into()
.unwrap_or(10) .unwrap_or(10)
.min(100); .min(100);
+20 -4
View File
@@ -22,14 +22,30 @@ pub(crate) async fn create_typing_event_route(
if let Typing::Yes(duration) = body.state { if let Typing::Yes(duration) = body.state {
let duration = utils::clamp( let duration = utils::clamp(
duration.as_millis() as u64, duration.as_millis().try_into().unwrap_or(u64::MAX),
services().globals.config.typing_client_timeout_min_s * 1000, services()
services().globals.config.typing_client_timeout_max_s * 1000, .globals
.config
.typing_client_timeout_min_s
.checked_mul(1000)
.unwrap(),
services()
.globals
.config
.typing_client_timeout_max_s
.checked_mul(1000)
.unwrap(),
); );
services() services()
.rooms .rooms
.typing .typing
.typing_add(sender_user, &body.room_id, utils::millis_since_unix_epoch() + duration) .typing_add(
sender_user,
&body.room_id,
utils::millis_since_unix_epoch()
.checked_add(duration)
.expect("user typing timeout should not get this high"),
)
.await?; .await?;
} else { } else {
services() services()
+1 -1
View File
@@ -17,7 +17,7 @@ use crate::{services, Result, Ruma};
/// and don't share a room with the sender /// and don't share a room with the sender
pub(crate) async fn search_users_route(body: Ruma<search_users::v3::Request>) -> Result<search_users::v3::Response> { pub(crate) async fn search_users_route(body: Ruma<search_users::v3::Request>) -> Result<search_users::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated"); let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let limit = u64::from(body.limit) as usize; let limit = usize::try_from(body.limit).unwrap_or(10); // default limit is 10
let mut users = services().users.iter().filter_map(|user_id| { let mut users = services().users.iter().filter_map(|user_id| {
// Filter out buggy users (they should not exist, but you never know...) // Filter out buggy users (they should not exist, but you never know...)
+3 -1
View File
@@ -21,7 +21,9 @@ pub(crate) async fn turn_server_route(
let (username, password) = if !turn_secret.is_empty() { let (username, password) = if !turn_secret.is_empty() {
let expiry = SecondsSinceUnixEpoch::from_system_time( let expiry = SecondsSinceUnixEpoch::from_system_time(
SystemTime::now() + Duration::from_secs(services().globals.turn_ttl()), SystemTime::now()
.checked_add(Duration::from_secs(services().globals.turn_ttl()))
.expect("TURN TTL should not get this high"),
) )
.expect("time is valid"); .expect("time is valid");
+13 -6
View File
@@ -101,7 +101,9 @@ pub(crate) async fn get_server_keys_route() -> Result<impl IntoResponse> {
old_verify_keys: BTreeMap::new(), old_verify_keys: BTreeMap::new(),
signatures: BTreeMap::new(), signatures: BTreeMap::new(),
valid_until_ts: MilliSecondsSinceUnixEpoch::from_system_time( valid_until_ts: MilliSecondsSinceUnixEpoch::from_system_time(
SystemTime::now() + Duration::from_secs(86400 * 7), SystemTime::now()
.checked_add(Duration::from_secs(86400 * 7))
.expect("valid_until_ts should not get this high"),
) )
.expect("time is valid"), .expect("time is valid"),
}) })
@@ -398,8 +400,13 @@ pub(crate) async fn send_transaction_message_route(
.is_joined(&typing.user_id, &typing.room_id)? .is_joined(&typing.user_id, &typing.room_id)?
{ {
if typing.typing { if typing.typing {
let timeout = utils::millis_since_unix_epoch() let timeout = utils::millis_since_unix_epoch().saturating_add(
+ services().globals.config.typing_federation_timeout_s * 1000; services()
.globals
.config
.typing_federation_timeout_s
.saturating_mul(1000),
);
services() services()
.rooms .rooms
.typing .typing
@@ -662,7 +669,7 @@ pub(crate) async fn get_missing_events_route(
} }
if body.earliest_events.contains(&queued_events[i]) { if body.earliest_events.contains(&queued_events[i]) {
i += 1; i = i.saturating_add(1);
continue; continue;
} }
@@ -671,7 +678,7 @@ pub(crate) async fn get_missing_events_route(
&body.room_id, &body.room_id,
&queued_events[i], &queued_events[i],
)? { )? {
i += 1; i = i.saturating_add(1);
continue; continue;
} }
@@ -688,7 +695,7 @@ pub(crate) async fn get_missing_events_route(
); );
events.push(PduEvent::convert_to_outgoing_federation_event(pdu)); events.push(PduEvent::convert_to_outgoing_federation_event(pdu));
} }
i += 1; i = i.saturating_add(1);
} }
Ok(get_missing_events::v1::Response { Ok(get_missing_events::v1::Response {
+1 -1
View File
@@ -105,7 +105,7 @@ impl service::account_data::Data for KeyValueDatabase {
// Skip the data that's exactly at since, because we sent that last time // Skip the data that's exactly at since, because we sent that last time
let mut first_possible = prefix.clone(); let mut first_possible = prefix.clone();
first_possible.extend_from_slice(&(since + 1).to_be_bytes()); first_possible.extend_from_slice(&(since.saturating_add(1)).to_be_bytes());
for r in self for r in self
.roomuserdataid_accountdata .roomuserdataid_accountdata
+5 -8
View File
@@ -158,18 +158,15 @@ impl service::globals::Data for KeyValueDatabase {
let max_appservice_in_room_cache = self.appservice_in_room_cache.read().unwrap().capacity(); let max_appservice_in_room_cache = self.appservice_in_room_cache.read().unwrap().capacity();
let max_lasttimelinecount_cache = self.lasttimelinecount_cache.lock().unwrap().capacity(); let max_lasttimelinecount_cache = self.lasttimelinecount_cache.lock().unwrap().capacity();
let mut response = format!( format!(
"\ "\
auth_chain_cache: {auth_chain_cache} / {max_auth_chain_cache} auth_chain_cache: {auth_chain_cache} / {max_auth_chain_cache}
our_real_users_cache: {our_real_users_cache} / {max_our_real_users_cache} our_real_users_cache: {our_real_users_cache} / {max_our_real_users_cache}
appservice_in_room_cache: {appservice_in_room_cache} / {max_appservice_in_room_cache} appservice_in_room_cache: {appservice_in_room_cache} / {max_appservice_in_room_cache}
lasttimelinecount_cache: {lasttimelinecount_cache} / {max_lasttimelinecount_cache}\n\n" lasttimelinecount_cache: {lasttimelinecount_cache} / {max_lasttimelinecount_cache}\n\n
); {}",
if let Ok(db_stats) = self.db.memory_usage() { self.db.memory_usage().unwrap_or_default()
response += &db_stats; )
}
response
} }
fn clear_caches(&self, amount: u32) { fn clear_caches(&self, amount: u32) {
+11 -3
View File
@@ -1,8 +1,8 @@
use ruma::{events::presence::PresenceEvent, presence::PresenceState, OwnedUserId, UInt, UserId}; use ruma::{events::presence::PresenceEvent, presence::PresenceState, OwnedUserId, UInt, UserId};
use tracing::debug;
use crate::{ use crate::{
database::KeyValueDatabase, database::KeyValueDatabase,
debug_info,
service::{self, presence::Presence}, service::{self, presence::Presence},
services, services,
utils::{self, user_id_from_bytes}, utils::{self, user_id_from_bytes},
@@ -50,13 +50,21 @@ impl service::presence::Data for KeyValueDatabase {
// tighten for state flicker? // tighten for state flicker?
if !state_changed && last_active_ts <= last_last_active_ts { if !state_changed && last_active_ts <= last_last_active_ts {
debug!( debug_info!(
"presence spam {:?} last_active_ts:{:?} <= {:?}", "presence spam {:?} last_active_ts:{:?} <= {:?}",
user_id, last_active_ts, last_last_active_ts user_id,
last_active_ts,
last_last_active_ts
); );
return Ok(()); return Ok(());
} }
let status_msg = if status_msg.as_ref().is_some_and(String::is_empty) {
None
} else {
status_msg
};
let presence = Presence::new( let presence = Presence::new(
presence_state.to_owned(), presence_state.to_owned(),
currently_active.unwrap_or(false), currently_active.unwrap_or(false),
+2 -2
View File
@@ -23,10 +23,10 @@ impl service::rooms::pdu_metadata::Data for KeyValueDatabase {
let mut current = prefix.clone(); let mut current = prefix.clone();
let count_raw = match until { let count_raw = match until {
PduCount::Normal(x) => x - 1, PduCount::Normal(x) => x.saturating_sub(1),
PduCount::Backfilled(x) => { PduCount::Backfilled(x) => {
current.extend_from_slice(&0_u64.to_be_bytes()); current.extend_from_slice(&0_u64.to_be_bytes());
u64::MAX - x - 1 u64::MAX.saturating_sub(x).saturating_sub(1)
}, },
}; };
current.extend_from_slice(&count_raw.to_be_bytes()); current.extend_from_slice(&count_raw.to_be_bytes());
+1 -1
View File
@@ -48,7 +48,7 @@ impl service::rooms::read_receipt::Data for KeyValueDatabase {
let prefix2 = prefix.clone(); let prefix2 = prefix.clone();
let mut first_possible_edu = prefix.clone(); let mut first_possible_edu = prefix.clone();
first_possible_edu.extend_from_slice(&(since + 1).to_be_bytes()); // +1 so we don't send the event at since first_possible_edu.extend_from_slice(&(since.saturating_add(1)).to_be_bytes()); // +1 so we don't send the event at since
Box::new( Box::new(
self.readreceiptid_readreceipt self.readreceiptid_readreceipt
@@ -17,7 +17,7 @@ impl service::rooms::state_accessor::Data for KeyValueDatabase {
.expect("there is always one layer") .expect("there is always one layer")
.1; .1;
let mut result = HashMap::new(); let mut result = HashMap::new();
let mut i = 0; let mut i: u8 = 0;
for compressed in full_state.iter() { for compressed in full_state.iter() {
let parsed = services() let parsed = services()
.rooms .rooms
@@ -25,7 +25,7 @@ impl service::rooms::state_accessor::Data for KeyValueDatabase {
.parse_compressed_state_event(compressed)?; .parse_compressed_state_event(compressed)?;
result.insert(parsed.0, parsed.1); result.insert(parsed.0, parsed.1);
i += 1; i = i.wrapping_add(1);
if i % 100 == 0 { if i % 100 == 0 {
tokio::task::yield_now().await; tokio::task::yield_now().await;
} }
@@ -44,7 +44,7 @@ impl service::rooms::state_accessor::Data for KeyValueDatabase {
.1; .1;
let mut result = HashMap::new(); let mut result = HashMap::new();
let mut i = 0; let mut i: u8 = 0;
for compressed in full_state.iter() { for compressed in full_state.iter() {
let (_, eventid) = services() let (_, eventid) = services()
.rooms .rooms
@@ -63,7 +63,7 @@ impl service::rooms::state_accessor::Data for KeyValueDatabase {
); );
} }
i += 1; i = i.wrapping_add(1);
if i % 100 == 0 { if i % 100 == 0 {
tokio::task::yield_now().await; tokio::task::yield_now().await;
} }
+2 -2
View File
@@ -154,11 +154,11 @@ impl service::rooms::state_cache::Data for KeyValueDatabase {
if user_is_local(&joined) && !services().users.is_deactivated(&joined).unwrap_or(true) { if user_is_local(&joined) && !services().users.is_deactivated(&joined).unwrap_or(true) {
real_users.insert(joined); real_users.insert(joined);
} }
joinedcount += 1; joinedcount = joinedcount.saturating_add(1);
} }
for _invited in self.room_members_invited(room_id).filter_map(Result::ok) { for _invited in self.room_members_invited(room_id).filter_map(Result::ok) {
invitedcount += 1; invitedcount = invitedcount.saturating_add(1);
} }
self.roomid_joinedcount self.roomid_joinedcount
+6 -10
View File
@@ -256,7 +256,7 @@ fn pdu_count(pdu_id: &[u8]) -> Result<PduCount> {
utils::u64_from_bytes(&pdu_id[pdu_id.len() - 2 * size_of::<u64>()..pdu_id.len() - size_of::<u64>()]); utils::u64_from_bytes(&pdu_id[pdu_id.len() - 2 * size_of::<u64>()..pdu_id.len() - size_of::<u64>()]);
if matches!(second_last_u64, Ok(0)) { if matches!(second_last_u64, Ok(0)) {
Ok(PduCount::Backfilled(u64::MAX - last_u64)) Ok(PduCount::Backfilled(u64::MAX.saturating_sub(last_u64)))
} else { } else {
Ok(PduCount::Normal(last_u64)) Ok(PduCount::Normal(last_u64))
} }
@@ -275,22 +275,18 @@ fn count_to_id(room_id: &RoomId, count: PduCount, offset: u64, subtract: bool) -
let count_raw = match count { let count_raw = match count {
PduCount::Normal(x) => { PduCount::Normal(x) => {
if subtract { if subtract {
x - offset x.saturating_sub(offset)
} else { } else {
x + offset x.saturating_add(offset)
} }
}, },
PduCount::Backfilled(x) => { PduCount::Backfilled(x) => {
pdu_id.extend_from_slice(&0_u64.to_be_bytes()); pdu_id.extend_from_slice(&0_u64.to_be_bytes());
let num = u64::MAX - x; let num = u64::MAX.saturating_sub(x);
if subtract { if subtract {
if num > 0 { num.saturating_sub(offset)
num - offset
} else { } else {
num num.saturating_add(offset)
}
} else {
num + offset
} }
}, },
}; };
+2 -1
View File
@@ -110,7 +110,8 @@ impl service::rooms::user::Data for KeyValueDatabase {
.enumerate() .enumerate()
.find(|(_, &b)| b == 0xFF) .find(|(_, &b)| b == 0xFF)
.ok_or_else(|| Error::bad_database("Invalid userroomid_joined in db."))? .ok_or_else(|| Error::bad_database("Invalid userroomid_joined in db."))?
.0 + 1; // +1 because the room id starts AFTER the separator .0
.saturating_add(1); // +1 because the room id starts AFTER the separator
let room_id = key[roomid_index..].to_vec(); let room_id = key[roomid_index..].to_vec();
+3 -3
View File
@@ -5,7 +5,7 @@ use ruma::{
encryption::{CrossSigningKey, DeviceKeys, OneTimeKey}, encryption::{CrossSigningKey, DeviceKeys, OneTimeKey},
events::{AnyToDeviceEvent, StateEventType}, events::{AnyToDeviceEvent, StateEventType},
serde::Raw, serde::Raw,
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedDeviceKeyId, uint, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedDeviceKeyId,
OwnedMxcUri, OwnedUserId, UInt, UserId, OwnedMxcUri, OwnedUserId, UInt, UserId,
}; };
use tracing::warn; use tracing::warn;
@@ -414,7 +414,7 @@ impl service::users::Data for KeyValueDatabase {
.algorithm(), .algorithm(),
) )
}) { }) {
*counts.entry(algorithm?).or_default() += UInt::from(1_u32); *counts.entry(algorithm?).or_default() += uint!(1);
} }
Ok(counts) Ok(counts)
@@ -561,7 +561,7 @@ impl service::users::Data for KeyValueDatabase {
prefix.push(0xFF); prefix.push(0xFF);
let mut start = prefix.clone(); let mut start = prefix.clone();
start.extend_from_slice(&(from + 1).to_be_bytes()); start.extend_from_slice(&(from.saturating_add(1)).to_be_bytes());
let to = to.unwrap_or(u64::MAX); let to = to.unwrap_or(u64::MAX);
+1 -3
View File
@@ -173,13 +173,11 @@ pub(crate) async fn migrations(db: &KeyValueDatabase, config: &Config) -> Result
let mut current_sstatehash: Option<u64> = None; let mut current_sstatehash: Option<u64> = None;
let mut current_room = None; let mut current_room = None;
let mut current_state = HashSet::new(); let mut current_state = HashSet::new();
let mut counter = 0;
let mut handle_state = |current_sstatehash: u64, let handle_state = |current_sstatehash: u64,
current_room: &RoomId, current_room: &RoomId,
current_state: HashSet<_>, current_state: HashSet<_>,
last_roomstates: &mut HashMap<_, _>| { last_roomstates: &mut HashMap<_, _>| {
counter += 1;
let last_roomsstatehash = last_roomstates.get(current_room); let last_roomsstatehash = last_roomstates.get(current_room);
let states_parents = last_roomsstatehash.map_or_else( let states_parents = last_roomsstatehash.map_or_else(
+3 -13
View File
@@ -340,6 +340,7 @@ impl KeyValueDatabase {
roomid_inviteviaservers: builder.open_tree("roomid_inviteviaservers")?, roomid_inviteviaservers: builder.open_tree("roomid_inviteviaservers")?,
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
auth_chain_cache: Mutex::new(LruCache::new( auth_chain_cache: Mutex::new(LruCache::new(
(f64::from(config.auth_chain_cache_capacity) * config.conduit_cache_capacity_modifier) as usize, (f64::from(config.auth_chain_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)), )),
@@ -401,19 +402,8 @@ impl KeyValueDatabase {
let sqlite_exists = path.join("conduit.db").exists(); let sqlite_exists = path.join("conduit.db").exists();
let rocksdb_exists = path.join("IDENTITY").exists(); let rocksdb_exists = path.join("IDENTITY").exists();
let mut count = 0; if sqlite_exists && rocksdb_exists {
return Err(Error::bad_config("Multiple databases at database_path detected."));
if sqlite_exists {
count += 1;
}
if rocksdb_exists {
count += 1;
}
if count > 1 {
warn!("Multiple databases at database_path detected");
return Ok(());
} }
if sqlite_exists && config.database_backend != "sqlite" { if sqlite_exists && config.database_backend != "sqlite" {
+9
View File
@@ -19,6 +19,7 @@ impl KvTree for RocksDbEngineTree<'_> {
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> { fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
let mut readoptions = rust_rocksdb::ReadOptions::default(); let mut readoptions = rust_rocksdb::ReadOptions::default();
readoptions.set_total_order_seek(true); readoptions.set_total_order_seek(true);
readoptions.set_async_io(cfg!(feature = "io_uring"));
Ok(self.db.rocks.get_cf_opt(&self.cf(), key, &readoptions)?) Ok(self.db.rocks.get_cf_opt(&self.cf(), key, &readoptions)?)
} }
@@ -26,6 +27,7 @@ impl KvTree for RocksDbEngineTree<'_> {
fn multi_get(&self, keys: &[&[u8]]) -> Result<Vec<Option<Vec<u8>>>> { fn multi_get(&self, keys: &[&[u8]]) -> Result<Vec<Option<Vec<u8>>>> {
let mut readoptions = rust_rocksdb::ReadOptions::default(); let mut readoptions = rust_rocksdb::ReadOptions::default();
readoptions.set_total_order_seek(true); readoptions.set_total_order_seek(true);
readoptions.set_async_io(cfg!(feature = "io_uring"));
// Optimization can be `true` if key vector is pre-sorted **by the column // Optimization can be `true` if key vector is pre-sorted **by the column
// comparator**. // comparator**.
@@ -113,6 +115,7 @@ impl KvTree for RocksDbEngineTree<'_> {
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> { fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> {
let mut readoptions = rust_rocksdb::ReadOptions::default(); let mut readoptions = rust_rocksdb::ReadOptions::default();
readoptions.set_total_order_seek(true); readoptions.set_total_order_seek(true);
readoptions.set_async_io(cfg!(feature = "io_uring"));
Box::new( Box::new(
self.db self.db
@@ -126,6 +129,7 @@ impl KvTree for RocksDbEngineTree<'_> {
fn iter_from<'a>(&'a self, from: &[u8], backwards: bool) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> { fn iter_from<'a>(&'a self, from: &[u8], backwards: bool) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> {
let mut readoptions = rust_rocksdb::ReadOptions::default(); let mut readoptions = rust_rocksdb::ReadOptions::default();
readoptions.set_total_order_seek(true); readoptions.set_total_order_seek(true);
readoptions.set_async_io(cfg!(feature = "io_uring"));
Box::new( Box::new(
self.db self.db
@@ -150,6 +154,8 @@ impl KvTree for RocksDbEngineTree<'_> {
fn increment(&self, key: &[u8]) -> Result<Vec<u8>> { fn increment(&self, key: &[u8]) -> Result<Vec<u8>> {
let mut readoptions = rust_rocksdb::ReadOptions::default(); let mut readoptions = rust_rocksdb::ReadOptions::default();
readoptions.set_total_order_seek(true); readoptions.set_total_order_seek(true);
readoptions.set_async_io(cfg!(feature = "io_uring"));
let writeoptions = rust_rocksdb::WriteOptions::default(); let writeoptions = rust_rocksdb::WriteOptions::default();
let old = self.db.rocks.get_cf_opt(&self.cf(), key, &readoptions)?; let old = self.db.rocks.get_cf_opt(&self.cf(), key, &readoptions)?;
@@ -168,6 +174,8 @@ impl KvTree for RocksDbEngineTree<'_> {
fn increment_batch(&self, iter: &mut dyn Iterator<Item = Vec<u8>>) -> Result<()> { fn increment_batch(&self, iter: &mut dyn Iterator<Item = Vec<u8>>) -> Result<()> {
let mut readoptions = rust_rocksdb::ReadOptions::default(); let mut readoptions = rust_rocksdb::ReadOptions::default();
readoptions.set_total_order_seek(true); readoptions.set_total_order_seek(true);
readoptions.set_async_io(cfg!(feature = "io_uring"));
let writeoptions = rust_rocksdb::WriteOptions::default(); let writeoptions = rust_rocksdb::WriteOptions::default();
let mut batch = WriteBatchWithTransaction::<false>::default(); let mut batch = WriteBatchWithTransaction::<false>::default();
@@ -190,6 +198,7 @@ impl KvTree for RocksDbEngineTree<'_> {
fn scan_prefix<'a>(&'a self, prefix: Vec<u8>) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> { fn scan_prefix<'a>(&'a self, prefix: Vec<u8>) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> {
let mut readoptions = rust_rocksdb::ReadOptions::default(); let mut readoptions = rust_rocksdb::ReadOptions::default();
readoptions.set_total_order_seek(true); readoptions.set_total_order_seek(true);
readoptions.set_async_io(cfg!(feature = "io_uring"));
Box::new( Box::new(
self.db self.db
+5
View File
@@ -35,7 +35,11 @@ pub(crate) struct Engine {
impl KeyValueDatabaseEngine for Arc<Engine> { impl KeyValueDatabaseEngine for Arc<Engine> {
fn open(config: &Config) -> Result<Self> { fn open(config: &Config) -> Result<Self> {
let cache_capacity_bytes = config.db_cache_capacity_mb * 1024.0 * 1024.0; let cache_capacity_bytes = config.db_cache_capacity_mb * 1024.0 * 1024.0;
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
let row_cache_capacity_bytes = (cache_capacity_bytes * 0.50) as usize; let row_cache_capacity_bytes = (cache_capacity_bytes * 0.50) as usize;
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
let col_cache_capacity_bytes = (cache_capacity_bytes * 0.50) as usize; let col_cache_capacity_bytes = (cache_capacity_bytes * 0.50) as usize;
let mut col_cache = HashMap::new(); let mut col_cache = HashMap::new();
@@ -128,6 +132,7 @@ impl KeyValueDatabaseEngine for Arc<Engine> {
Ok(()) Ok(())
} }
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
fn memory_usage(&self) -> Result<String> { fn memory_usage(&self) -> Result<String> {
let mut res = String::new(); let mut res = String::new();
let stats = rust_rocksdb::perf::get_memory_usage_stats(Some(&[&self.rocks]), Some(&[&self.row_cache]))?; let stats = rust_rocksdb::perf::get_memory_usage_stats(Some(&[&self.rocks]), Some(&[&self.row_cache]))?;
+12 -2
View File
@@ -145,7 +145,14 @@ pub(crate) fn cf_options(cfg: &Config, name: &str, mut opts: Options, cache: &mu
cache_size(cfg, cfg.statekeyshort_cache_capacity, 1024), cache_size(cfg, cfg.statekeyshort_cache_capacity, 1024),
), ),
"pduid_pdu" => set_table_with_new_cache(&mut opts, cfg, cache, name, cfg.pdu_cache_capacity as usize * 1536), #[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
"pduid_pdu" => set_table_with_new_cache(
&mut opts,
cfg,
cache,
name,
(cfg.pdu_cache_capacity as usize).saturating_mul(1536),
),
"eventid_outlierpdu" => set_table_with_shared_cache(&mut opts, cfg, cache, name, "pduid_pdu"), "eventid_outlierpdu" => set_table_with_shared_cache(&mut opts, cfg, cache, name, "pduid_pdu"),
@@ -309,7 +316,10 @@ fn set_table_with_shared_cache(
fn cache_size(config: &Config, base_size: u32, entity_size: usize) -> usize { fn cache_size(config: &Config, base_size: u32, entity_size: usize) -> usize {
let ents = f64::from(base_size) * config.conduit_cache_capacity_modifier; let ents = f64::from(base_size) * config.conduit_cache_capacity_modifier;
ents as usize * entity_size #[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
(ents as usize)
.checked_mul(entity_size)
.expect("cache capacity size is too large")
} }
fn table_options(_config: &Config) -> BlockBasedOptions { fn table_options(_config: &Config) -> BlockBasedOptions {
+29 -15
View File
@@ -21,7 +21,7 @@ thread_local! {
struct PreparedStatementIterator<'a> { struct PreparedStatementIterator<'a> {
iterator: Box<dyn Iterator<Item = TupleOfBytes> + 'a>, iterator: Box<dyn Iterator<Item = TupleOfBytes> + 'a>,
_statement_ref: NonAliasingBox<rusqlite::Statement<'a>>, _statement_ref: AliasableBox<rusqlite::Statement<'a>>,
} }
impl Iterator for PreparedStatementIterator<'_> { impl Iterator for PreparedStatementIterator<'_> {
@@ -30,16 +30,25 @@ impl Iterator for PreparedStatementIterator<'_> {
fn next(&mut self) -> Option<Self::Item> { self.iterator.next() } fn next(&mut self) -> Option<Self::Item> { self.iterator.next() }
} }
struct NonAliasingBox<T>(*mut T); struct AliasableBox<T>(*mut T);
impl<T> Drop for NonAliasingBox<T> { impl<T> Drop for AliasableBox<T> {
fn drop(&mut self) { fn drop(&mut self) {
// TODO: figure out why this is necessary, but also this is sqlite so dont think // SAFETY: This is cursed and relies on non-local reasoning.
// i care that much. i tried checking commit history but couldn't find out why //
// this was done. // In order for this to be safe:
#[allow(clippy::undocumented_unsafe_blocks)] //
unsafe { // * All aliased references to this value must have been dropped first, for
_ = Box::from_raw(self.0); // example by coming after its referrers in struct fields, because struct
}; // fields are automatically dropped in order from top to bottom in the absence
// of an explicit Drop impl. Otherwise, the referrers may read into
// deallocated memory.
// * This type must not be copyable or cloneable. Otherwise, double-free can
// occur.
//
// These conditions are met, but again, note that changing safe code in
// this module can result in unsoundness if any of these constraints are
// violated.
unsafe { drop(Box::from_raw(self.0)) }
} }
} }
@@ -93,8 +102,13 @@ impl KeyValueDatabaseEngine for Arc<Engine> {
// 2. divide by permanent connections + permanent iter connections + write // 2. divide by permanent connections + permanent iter connections + write
// connection // connection
// 3. round down to nearest integer // 3. round down to nearest integer
let cache_size_per_thread: u32 = #[allow(
((config.db_cache_capacity_mb * 1024.0) / ((num_cpus::get().max(1) * 2) + 1) as f64) as u32; clippy::as_conversions,
clippy::cast_possible_truncation,
clippy::cast_precision_loss,
clippy::cast_sign_loss
)]
let cache_size_per_thread = ((config.db_cache_capacity_mb * 1024.0) / ((num_cpus::get() as f64 * 2.0) + 1.0)) as u32;
let writer = Mutex::new(Engine::prepare_conn(&path, cache_size_per_thread)?); let writer = Mutex::new(Engine::prepare_conn(&path, cache_size_per_thread)?);
@@ -161,7 +175,7 @@ impl SqliteTable {
.unwrap(), .unwrap(),
)); ));
let statement_ref = NonAliasingBox(statement); let statement_ref = AliasableBox(statement);
//let name = self.name.clone(); //let name = self.name.clone();
@@ -250,7 +264,7 @@ impl KvTree for SqliteTable {
.unwrap(), .unwrap(),
)); ));
let statement_ref = NonAliasingBox(statement); let statement_ref = AliasableBox(statement);
let iterator = Box::new( let iterator = Box::new(
statement statement
@@ -272,7 +286,7 @@ impl KvTree for SqliteTable {
.unwrap(), .unwrap(),
)); ));
let statement_ref = NonAliasingBox(statement); let statement_ref = AliasableBox(statement);
let iterator = Box::new( let iterator = Box::new(
statement statement
+1 -1
View File
@@ -47,7 +47,7 @@ impl Watchers {
let mut watchers = self.watchers.write().unwrap(); let mut watchers = self.watchers.write().unwrap();
for prefix in triggered { for prefix in triggered {
if let Some(tx) = watchers.remove(prefix) { if let Some(tx) = watchers.remove(prefix) {
_ = tx.0.send(()); tx.0.send(()).expect("channel should still be open");
} }
} }
}; };
+2 -1
View File
@@ -131,9 +131,10 @@ fn request_result_log(method: &Method, uri: &Uri, result: &axum::response::Respo
} }
fn cors_layer(_server: &Server) -> CorsLayer { fn cors_layer(_server: &Server) -> CorsLayer {
const METHODS: [Method; 6] = [ const METHODS: [Method; 7] = [
Method::GET, Method::GET,
Method::HEAD, Method::HEAD,
Method::PATCH,
Method::POST, Method::POST,
Method::PUT, Method::PUT,
Method::DELETE, Method::DELETE,
@@ -4,7 +4,7 @@ use crate::{service::admin::escape_html, services, Result};
pub(crate) async fn register(body: Vec<&str>) -> Result<RoomMessageEventContent> { pub(crate) async fn register(body: Vec<&str>) -> Result<RoomMessageEventContent> {
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" { if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" {
let appservice_config = body[1..body.len() - 1].join("\n"); let appservice_config = body[1..body.len().checked_sub(1).unwrap()].join("\n");
let parsed_config = serde_yaml::from_str::<Registration>(&appservice_config); let parsed_config = serde_yaml::from_str::<Registration>(&appservice_config);
match parsed_config { match parsed_config {
Ok(yaml) => match services().appservice.register_appservice(yaml).await { Ok(yaml) => match services().appservice.register_appservice(yaml).await {
+3 -3
View File
@@ -121,7 +121,7 @@ pub(crate) async fn get_remote_pdu_list(
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" { if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" {
let list = body let list = body
.clone() .clone()
.drain(1..body.len() - 1) .drain(1..body.len().checked_sub(1).unwrap())
.filter_map(|pdu| EventId::parse(pdu).ok()) .filter_map(|pdu| EventId::parse(pdu).ok())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@@ -381,7 +381,7 @@ pub(crate) async fn change_log_level(
pub(crate) async fn sign_json(body: Vec<&str>) -> Result<RoomMessageEventContent> { pub(crate) async fn sign_json(body: Vec<&str>) -> Result<RoomMessageEventContent> {
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" { if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" {
let string = body[1..body.len() - 1].join("\n"); let string = body[1..body.len().checked_sub(1).unwrap()].join("\n");
match serde_json::from_str(&string) { match serde_json::from_str(&string) {
Ok(mut value) => { Ok(mut value) => {
ruma::signatures::sign_json( ruma::signatures::sign_json(
@@ -404,7 +404,7 @@ pub(crate) async fn sign_json(body: Vec<&str>) -> Result<RoomMessageEventContent
pub(crate) async fn verify_json(body: Vec<&str>) -> Result<RoomMessageEventContent> { pub(crate) async fn verify_json(body: Vec<&str>) -> Result<RoomMessageEventContent> {
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" { if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" {
let string = body[1..body.len() - 1].join("\n"); let string = body[1..body.len().checked_sub(1).unwrap()].join("\n");
match serde_json::from_str(&string) { match serde_json::from_str(&string) {
Ok(value) => { Ok(value) => {
let pub_key_map = RwLock::new(BTreeMap::new()); let pub_key_map = RwLock::new(BTreeMap::new());
+8 -3
View File
@@ -139,14 +139,19 @@ pub(crate) async fn delete(
pub(crate) async fn delete_list(body: Vec<&str>) -> Result<RoomMessageEventContent> { pub(crate) async fn delete_list(body: Vec<&str>) -> Result<RoomMessageEventContent> {
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" { if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" {
let mxc_list = body.clone().drain(1..body.len() - 1).collect::<Vec<_>>(); let mxc_list = body
.clone()
.drain(1..body.len().checked_sub(1).unwrap())
.collect::<Vec<_>>();
let mut mxc_deletion_count = 0; let mut mxc_deletion_count: usize = 0;
for mxc in mxc_list { for mxc in mxc_list {
debug!("Deleting MXC {mxc} in bulk"); debug!("Deleting MXC {mxc} in bulk");
services().media.delete(mxc.to_owned()).await?; services().media.delete(mxc.to_owned()).await?;
mxc_deletion_count += 1; mxc_deletion_count = mxc_deletion_count
.checked_add(1)
.expect("mxc_deletion_count should not get this high");
} }
return Ok(RoomMessageEventContent::text_plain(format!( return Ok(RoomMessageEventContent::text_plain(format!(
+1 -1
View File
@@ -22,7 +22,7 @@ pub(crate) async fn list(_body: Vec<&str>, page: Option<usize>) -> Result<RoomMe
let rooms = rooms let rooms = rooms
.into_iter() .into_iter()
.skip(page.saturating_sub(1) * PAGE_SIZE) .skip(page.saturating_sub(1).saturating_mul(PAGE_SIZE))
.take(PAGE_SIZE) .take(PAGE_SIZE)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@@ -39,7 +39,7 @@ pub(crate) async fn process(command: RoomDirectoryCommand, _body: Vec<&str>) ->
let rooms = rooms let rooms = rooms
.into_iter() .into_iter()
.skip(page.saturating_sub(1) * PAGE_SIZE) .skip(page.saturating_sub(1).saturating_mul(PAGE_SIZE))
.take(PAGE_SIZE) .take(PAGE_SIZE)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
+2 -2
View File
@@ -33,9 +33,9 @@ pub(crate) async fn memory_usage(_body: Vec<&str>) -> Result<RoomMessageEventCon
Ok(RoomMessageEventContent::text_plain(format!( Ok(RoomMessageEventContent::text_plain(format!(
"Services:\n{response0}\n\nDatabase:\n{response1}\n{}", "Services:\n{response0}\n\nDatabase:\n{response1}\n{}",
if !response2.is_empty() { if !response2.is_empty() {
"Allocator:\n{response2}" format!("Allocator:\n {response2}")
} else { } else {
"" String::new()
} }
))) )))
} }
+25 -46
View File
@@ -1,10 +1,9 @@
use std::{fmt::Write as _, sync::Arc}; use std::{fmt::Write as _, sync::Arc};
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, UserId}; use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, UserId};
use tracing::{error, info, warn};
use crate::{ use crate::{
api::client_server::{join_room_by_id_helper, leave_all_rooms, AUTO_GEN_PASSWORD_LENGTH}, api::client_server::{auto_join_rooms, leave_all_rooms, AUTO_GEN_PASSWORD_LENGTH},
service::admin::{escape_html, get_room_info}, service::admin::{escape_html, get_room_info},
services, services,
utils::{self, user_id::user_is_local}, utils::{self, user_id::user_is_local},
@@ -15,7 +14,7 @@ pub(crate) async fn list(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
match services().users.list_local_users() { match services().users.list_local_users() {
Ok(users) => { Ok(users) => {
let mut msg = format!("Found {} local user account(s):\n", users.len()); let mut msg = format!("Found {} local user account(s):\n", users.len());
msg += &users.join("\n"); _ = write!(msg, "{}\n", users.join("\n"));
Ok(RoomMessageEventContent::text_plain(&msg)) Ok(RoomMessageEventContent::text_plain(&msg))
}, },
Err(e) => Ok(RoomMessageEventContent::text_plain(e.to_string())), Err(e) => Ok(RoomMessageEventContent::text_plain(e.to_string())),
@@ -28,8 +27,10 @@ pub(crate) async fn create(
let password = password.unwrap_or_else(|| utils::random_string(AUTO_GEN_PASSWORD_LENGTH)); let password = password.unwrap_or_else(|| utils::random_string(AUTO_GEN_PASSWORD_LENGTH));
// Validate user id // Validate user id
let user_id = let user_id = match UserId::parse_with_server_name(
match UserId::parse_with_server_name(username.as_str().to_lowercase(), services().globals.server_name()) { username.as_str().to_lowercase(),
&services().globals.config.server_name,
) {
Ok(id) => id, Ok(id) => id,
Err(e) => { Err(e) => {
return Ok(RoomMessageEventContent::text_plain(format!( return Ok(RoomMessageEventContent::text_plain(format!(
@@ -61,8 +62,13 @@ pub(crate) async fn create(
// If `new_user_displayname_suffix` is set, registration will push whatever // If `new_user_displayname_suffix` is set, registration will push whatever
// content is set to the user's display name with a space before it // content is set to the user's display name with a space before it
if !services().globals.new_user_displayname_suffix().is_empty() { if !services()
displayname.push_str(&(" ".to_owned() + services().globals.new_user_displayname_suffix())); .globals
.config
.new_user_displayname_suffix
.is_empty()
{
_ = write!(displayname, " {}", services().globals.config.new_user_displayname_suffix);
} }
services() services()
@@ -86,36 +92,7 @@ pub(crate) async fn create(
)?; )?;
if !services().globals.config.auto_join_rooms.is_empty() { if !services().globals.config.auto_join_rooms.is_empty() {
for room in &services().globals.config.auto_join_rooms { auto_join_rooms(&user_id).await?;
if !services()
.rooms
.state_cache
.server_in_room(services().globals.server_name(), room)?
{
warn!("Skipping room {room} to automatically join as we have never joined before.");
continue;
}
if let Some(room_id_server_name) = room.server_name() {
match join_room_by_id_helper(
Some(&user_id),
room,
Some("Automatically joining this room upon registration".to_owned()),
&[room_id_server_name.to_owned(), services().globals.server_name().to_owned()],
None,
)
.await
{
Ok(_) => {
info!("Automatically joined room {room} for user {user_id}");
},
Err(e) => {
// don't return this error so we don't fail registrations
error!("Failed to automatically join room {room} for user {user_id}: {e}");
},
};
}
}
} }
// we dont add a device since we're not the user, just the creator // we dont add a device since we're not the user, just the creator
@@ -152,7 +129,7 @@ pub(crate) async fn deactivate(
== UserId::parse_with_server_name("conduit", services().globals.server_name()).expect("conduit user exists") == UserId::parse_with_server_name("conduit", services().globals.server_name()).expect("conduit user exists")
{ {
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain(
"Not allowed to deactivate the Conduit service account.", "Not allowed to deactivate the conduwuit service account.",
)); ));
} }
@@ -188,7 +165,7 @@ pub(crate) async fn reset_password(_body: Vec<&str>, username: String) -> Result
}; };
// check if user belongs to our server // check if user belongs to our server
if user_id.server_name() != services().globals.server_name() { if !user_is_local(&user_id) {
return Ok(RoomMessageEventContent::text_plain(format!( return Ok(RoomMessageEventContent::text_plain(format!(
"User {user_id} does not belong to our server." "User {user_id} does not belong to our server."
))); )));
@@ -234,7 +211,7 @@ pub(crate) async fn deactivate_all(body: Vec<&str>, leave_rooms: bool, force: bo
} }
} }
let mut deactivation_count = 0; let mut deactivation_count: usize = 0;
let mut admins = Vec::new(); let mut admins = Vec::new();
if !force { if !force {
@@ -253,7 +230,7 @@ pub(crate) async fn deactivate_all(body: Vec<&str>, leave_rooms: bool, force: bo
for &user_id in &user_ids { for &user_id in &user_ids {
// check if user belongs to our server and skips over non-local users // check if user belongs to our server and skips over non-local users
if user_id.server_name() != services().globals.server_name() { if !user_is_local(user_id) {
continue; continue;
} }
@@ -271,7 +248,7 @@ pub(crate) async fn deactivate_all(body: Vec<&str>, leave_rooms: bool, force: bo
} }
if services().users.deactivate_account(user_id).is_ok() { if services().users.deactivate_account(user_id).is_ok() {
deactivation_count += 1; deactivation_count = deactivation_count.saturating_add(1);
} }
} }
@@ -311,7 +288,7 @@ pub(crate) async fn list_joined_rooms(_body: Vec<&str>, user_id: String) -> Resu
}, },
}; };
if user_id.server_name() != services().globals.server_name() { if !user_is_local(&user_id) {
return Ok(RoomMessageEventContent::text_plain("User does not belong to our server.")); return Ok(RoomMessageEventContent::text_plain("User does not belong to our server."));
} }
@@ -335,7 +312,8 @@ pub(crate) async fn list_joined_rooms(_body: Vec<&str>, user_id: String) -> Resu
rooms.reverse(); rooms.reverse();
let output_plain = format!( let output_plain = format!(
"Rooms {user_id} Joined:\n{}", "Rooms {user_id} Joined ({}):\n{}",
rooms.len(),
rooms rooms
.iter() .iter()
.map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}")) .map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}"))
@@ -343,8 +321,9 @@ pub(crate) async fn list_joined_rooms(_body: Vec<&str>, user_id: String) -> Resu
.join("\n") .join("\n")
); );
let output_html = format!( let output_html = format!(
"<table><caption>Rooms {user_id} \ "<table><caption>Rooms {user_id} Joined \
Joined</caption>\n<tr><th>id</th>\t<th>members</th>\t<th>name</th></tr>\n{}</table>", ({})</caption>\n<tr><th>id</th>\t<th>members</th>\t<th>name</th></tr>\n{}</table>",
rooms.len(),
rooms rooms
.iter() .iter()
.fold(String::new(), |mut output, (id, members, name)| { .fold(String::new(), |mut output, (id, members, name)| {
+3 -1
View File
@@ -89,6 +89,8 @@ impl Client {
fn base(config: &Config) -> Result<reqwest::ClientBuilder> { fn base(config: &Config) -> Result<reqwest::ClientBuilder> {
let version = conduwuit_version(); let version = conduwuit_version();
let user_agent = format!("Conduwuit/{version}");
let mut builder = reqwest::Client::builder() let mut builder = reqwest::Client::builder()
.hickory_dns(true) .hickory_dns(true)
.connect_timeout(Duration::from_secs(config.request_conn_timeout)) .connect_timeout(Duration::from_secs(config.request_conn_timeout))
@@ -96,7 +98,7 @@ impl Client {
.timeout(Duration::from_secs(config.request_total_timeout)) .timeout(Duration::from_secs(config.request_total_timeout))
.pool_idle_timeout(Duration::from_secs(config.request_idle_timeout)) .pool_idle_timeout(Duration::from_secs(config.request_idle_timeout))
.pool_max_idle_per_host(config.request_idle_per_host.into()) .pool_max_idle_per_host(config.request_idle_per_host.into())
.user_agent("Conduwuit".to_owned() + "/" + &version) .user_agent(user_agent)
.redirect(redirect::Policy::limited(6)) .redirect(redirect::Policy::limited(6))
.connection_verbose(true); .connection_verbose(true);
+1
View File
@@ -30,6 +30,7 @@ pub(crate) struct Hooked {
} }
impl Resolver { impl Resolver {
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
pub(crate) fn new(config: &Config) -> Self { pub(crate) fn new(config: &Config) -> Self {
let (sys_conf, mut opts) = hickory_resolver::system_conf::read_system_conf() let (sys_conf, mut opts) = hickory_resolver::system_conf::read_system_conf()
.map_err(|e| { .map_err(|e| {
+4 -1
View File
@@ -16,6 +16,7 @@ use crate::{services, utils, Error, Result};
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct FileMeta { pub(crate) struct FileMeta {
#[allow(dead_code)]
pub(crate) content_disposition: Option<String>, pub(crate) content_disposition: Option<String>,
pub(crate) content_type: Option<String>, pub(crate) content_type: Option<String>,
pub(crate) file: Vec<u8>, pub(crate) file: Vec<u8>,
@@ -187,7 +188,9 @@ impl Service {
Ok(duration) => { Ok(duration) => {
debug!("Parsed duration: {:?}", duration); debug!("Parsed duration: {:?}", duration);
debug!("System time now: {:?}", SystemTime::now()); debug!("System time now: {:?}", SystemTime::now());
SystemTime::now() - duration SystemTime::now().checked_sub(duration).ok_or_else(|| {
Error::bad_database("Duration specified is not valid against the current system time")
})?
}, },
Err(e) => { Err(e) => {
error!("Failed to parse user-specified time duration: {}", e); error!("Failed to parse user-specified time duration: {}", e);
+1
View File
@@ -40,6 +40,7 @@ pub(crate) struct Services<'a> {
} }
impl Services<'_> { impl Services<'_> {
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
pub(crate) fn build< pub(crate) fn build<
D: appservice::Data D: appservice::Data
+ pusher::Data + pusher::Data
+4 -3
View File
@@ -188,13 +188,14 @@ impl Service {
let ctx = PushConditionRoomCtx { let ctx = PushConditionRoomCtx {
room_id: room_id.to_owned(), room_id: room_id.to_owned(),
member_count: UInt::from( member_count: UInt::try_from(
services() services()
.rooms .rooms
.state_cache .state_cache
.room_joined_count(room_id)? .room_joined_count(room_id)?
.unwrap_or(1) as u32, .unwrap_or(1),
), )
.unwrap_or_else(|_| uint!(0)),
user_id: user.to_owned(), user_id: user.to_owned(),
user_display_name: services() user_display_name: services()
.users .users
+10 -4
View File
@@ -6,9 +6,9 @@ use std::{
pub(crate) use data::Data; pub(crate) use data::Data;
use ruma::{api::client::error::ErrorKind, EventId, RoomId}; use ruma::{api::client::error::ErrorKind, EventId, RoomId};
use tracing::{debug, error, warn}; use tracing::{debug, error, trace, warn};
use crate::{services, Error, Result}; use crate::{services, utils::debug_slice_truncated, Error, Result};
pub(crate) struct Service { pub(crate) struct Service {
pub(crate) db: &'static dyn Data, pub(crate) db: &'static dyn Data,
@@ -30,7 +30,7 @@ impl Service {
.filter_map(move |sid| services().rooms.short.get_eventid_from_short(sid).ok())) .filter_map(move |sid| services().rooms.short.get_eventid_from_short(sid).ok()))
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip(self), fields(starting_events = debug_slice_truncated(starting_events, 5)))]
pub(crate) async fn get_auth_chain(&self, room_id: &RoomId, starting_events: &[&EventId]) -> Result<Vec<u64>> { pub(crate) async fn get_auth_chain(&self, room_id: &RoomId, starting_events: &[&EventId]) -> Result<Vec<u64>> {
const NUM_BUCKETS: usize = 50; //TODO: change possible w/o disrupting db? const NUM_BUCKETS: usize = 50; //TODO: change possible w/o disrupting db?
const BUCKET: BTreeSet<(u64, &EventId)> = BTreeSet::new(); const BUCKET: BTreeSet<(u64, &EventId)> = BTreeSet::new();
@@ -68,6 +68,7 @@ impl Service {
.auth_chain .auth_chain
.get_cached_eventid_authchain(&chunk_key)? .get_cached_eventid_authchain(&chunk_key)?
{ {
trace!("Found cache entry for whole chunk");
full_auth_chain.extend(cached.iter().copied()); full_auth_chain.extend(cached.iter().copied());
hits += 1; hits += 1;
continue; continue;
@@ -82,6 +83,7 @@ impl Service {
.auth_chain .auth_chain
.get_cached_eventid_authchain(&[sevent_id])? .get_cached_eventid_authchain(&[sevent_id])?
{ {
trace!(?event_id, "Found cache entry for event");
chunk_cache.extend(cached.iter().copied()); chunk_cache.extend(cached.iter().copied());
hits2 += 1; hits2 += 1;
} else { } else {
@@ -132,15 +134,18 @@ impl Service {
Ok(full_auth_chain) Ok(full_auth_chain)
} }
#[tracing::instrument(skip(self, event_id))] #[tracing::instrument(skip(self, room_id))]
fn get_auth_chain_inner(&self, room_id: &RoomId, event_id: &EventId) -> Result<HashSet<u64>> { fn get_auth_chain_inner(&self, room_id: &RoomId, event_id: &EventId) -> Result<HashSet<u64>> {
let mut todo = vec![Arc::from(event_id)]; let mut todo = vec![Arc::from(event_id)];
let mut found = HashSet::new(); let mut found = HashSet::new();
while let Some(event_id) = todo.pop() { while let Some(event_id) = todo.pop() {
trace!(?event_id, "processing auth event");
match services().rooms.timeline.get_pdu(&event_id) { match services().rooms.timeline.get_pdu(&event_id) {
Ok(Some(pdu)) => { Ok(Some(pdu)) => {
if pdu.room_id != room_id { if pdu.room_id != room_id {
error!(?event_id, ?pdu, "auth event for incorrect room_id");
return Err(Error::BadRequest(ErrorKind::forbidden(), "Evil event in db")); return Err(Error::BadRequest(ErrorKind::forbidden(), "Evil event in db"));
} }
for auth_event in &pdu.auth_events { for auth_event in &pdu.auth_events {
@@ -150,6 +155,7 @@ impl Service {
.get_or_create_shorteventid(auth_event)?; .get_or_create_shorteventid(auth_event)?;
if found.insert(sauthevent) { if found.insert(sauthevent) {
trace!(?event_id, ?auth_event, "adding auth event to processing queue");
todo.push(auth_event.clone()); todo.push(auth_event.clone());
} }
} }
+8 -9
View File
@@ -236,6 +236,7 @@ impl Service {
const MAX_DURATION: Duration = Duration::from_secs(60 * 60 * 24); const MAX_DURATION: Duration = Duration::from_secs(60 * 60 * 24);
let min_duration = cmp::min(MAX_DURATION, Duration::from_secs(5 * 60) * (*tries) * (*tries)); let min_duration = cmp::min(MAX_DURATION, Duration::from_secs(5 * 60) * (*tries) * (*tries));
let duration = time.elapsed(); let duration = time.elapsed();
if duration < min_duration { if duration < min_duration {
debug!( debug!(
duration = ?duration, duration = ?duration,
@@ -1003,7 +1004,7 @@ impl Service {
hash_map::Entry::Vacant(e) => { hash_map::Entry::Vacant(e) => {
e.insert((Instant::now(), 1)); e.insert((Instant::now(), 1));
}, },
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1), hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1.saturating_add(1)),
} }
}; };
@@ -1034,10 +1035,9 @@ impl Service {
.get(&*next_id) .get(&*next_id)
{ {
// Exponential backoff // Exponential backoff
let mut min_elapsed_duration = Duration::from_secs(5 * 60) * (*tries) * (*tries); const MAX_DURATION: Duration = Duration::from_secs(60 * 60 * 24);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) { let min_elapsed_duration =
min_elapsed_duration = Duration::from_secs(60 * 60 * 24); cmp::min(MAX_DURATION, Duration::from_secs(5 * 60) * (*tries) * (*tries));
}
if time.elapsed() < min_elapsed_duration { if time.elapsed() < min_elapsed_duration {
info!("Backing off from {}", next_id); info!("Backing off from {}", next_id);
@@ -1143,10 +1143,9 @@ impl Service {
.get(&**next_id) .get(&**next_id)
{ {
// Exponential backoff // Exponential backoff
let mut min_elapsed_duration = Duration::from_secs(5 * 60) * (*tries) * (*tries); const MAX_DURATION: Duration = Duration::from_secs(60 * 60 * 24);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) { let min_elapsed_duration =
min_elapsed_duration = Duration::from_secs(60 * 60 * 24); cmp::min(MAX_DURATION, Duration::from_secs(5 * 60) * (*tries) * (*tries));
}
if time.elapsed() < min_elapsed_duration { if time.elapsed() < min_elapsed_duration {
debug!("Backing off from {}", next_id); debug!("Backing off from {}", next_id);
+4 -3
View File
@@ -5,7 +5,7 @@ pub(crate) use data::Data;
use ruma::{ use ruma::{
api::{client::relations::get_relating_events, Direction}, api::{client::relations::get_relating_events, Direction},
events::{relation::RelationType, TimelineEventType}, events::{relation::RelationType, TimelineEventType},
EventId, RoomId, UInt, UserId, uint, EventId, RoomId, UInt, UserId,
}; };
use serde::Deserialize; use serde::Deserialize;
@@ -57,8 +57,9 @@ impl Service {
// Use limit or else 10, with maximum 100 // Use limit or else 10, with maximum 100
let limit = limit let limit = limit
.and_then(|u| u32::try_from(u).ok()) .unwrap_or_else(|| uint!(10))
.map_or(10_usize, |u| u as usize) .try_into()
.unwrap_or(10)
.min(100); .min(100);
let next_token; let next_token;
+1 -1
View File
@@ -818,7 +818,7 @@ impl FedDest {
fn into_uri_string(self) -> String { fn into_uri_string(self) -> String {
match self { match self {
Self::Literal(addr) => addr.to_string(), Self::Literal(addr) => addr.to_string(),
Self::Named(host, port) => host + &port, Self::Named(host, port) => format!("{host}{port}"),
} }
} }
+53 -2
View File
@@ -21,6 +21,7 @@ use crate::{services, Error, Result};
pub(crate) fn clamp<T: Ord>(val: T, min: T, max: T) -> T { cmp::min(cmp::max(val, min), max) } pub(crate) fn clamp<T: Ord>(val: T, min: T, max: T) -> T { cmp::min(cmp::max(val, min), max) }
#[allow(clippy::as_conversions)]
pub(crate) fn millis_since_unix_epoch() -> u64 { pub(crate) fn millis_since_unix_epoch() -> u64 {
SystemTime::now() SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@@ -196,10 +197,60 @@ impl fmt::Display for HtmlEscape<'_> {
/// git commit hashes. /// git commit hashes.
pub(crate) fn conduwuit_version() -> String { pub(crate) fn conduwuit_version() -> String {
match option_env!("CONDUWUIT_VERSION_EXTRA") { match option_env!("CONDUWUIT_VERSION_EXTRA") {
Some(extra) => format!("{} ({})", env!("CARGO_PKG_VERSION"), extra), Some(extra) => {
if extra.is_empty() {
env!("CARGO_PKG_VERSION").to_owned()
} else {
format!("{} ({})", env!("CARGO_PKG_VERSION"), extra)
}
},
None => match option_env!("CONDUIT_VERSION_EXTRA") { None => match option_env!("CONDUIT_VERSION_EXTRA") {
Some(extra) => format!("{} ({})", env!("CARGO_PKG_VERSION"), extra), Some(extra) => {
if extra.is_empty() {
env!("CARGO_PKG_VERSION").to_owned()
} else {
format!("{} ({})", env!("CARGO_PKG_VERSION"), extra)
}
},
None => env!("CARGO_PKG_VERSION").to_owned(), None => env!("CARGO_PKG_VERSION").to_owned(),
}, },
} }
} }
/// Debug-formats the given slice, but only up to the first `max_len` elements.
/// Any further elements are replaced by an ellipsis.
///
/// See also [`debug_slice_truncated()`],
pub(crate) struct TruncatedDebugSlice<'a, T> {
inner: &'a [T],
max_len: usize,
}
impl<T: fmt::Debug> fmt::Debug for TruncatedDebugSlice<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.inner.len() <= self.max_len {
write!(f, "{:?}", self.inner)
} else {
f.debug_list()
.entries(&self.inner[..self.max_len])
.entry(&"...")
.finish()
}
}
}
/// See [`TruncatedDebugSlice`]. Useful for `#[instrument]`:
///
/// ```
/// #[tracing::instrument(fields(
/// foos = debug_slice_truncated(foos, N)
/// ))]
/// ```
pub(crate) fn debug_slice_truncated<T: fmt::Debug>(
slice: &[T], max_len: usize,
) -> tracing::field::DebugValue<TruncatedDebugSlice<'_, T>> {
tracing::field::debug(TruncatedDebugSlice {
inner: slice,
max_len,
})
}