Compare commits

..

30 Commits

Author SHA1 Message Date
strawberry c29197b3f4 ci: dont publish -rc tags as latest docker branches
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-16 00:44:47 -04:00
Jason Volk 739eab46d5 refactor thumbnail math
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:40:18 +00:00
Jason Volk 923a98eb66 partially revert dc18f89c0b for now
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:40:18 +00:00
Jason Volk 4430e4dee0 de-global some services()
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:39:49 +00:00
Jason Volk d67f19a55d cleanup some error callsites
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:39:49 +00:00
Jason Volk b903b46d16 split thumbnailing related into unit
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:39:49 +00:00
Jason Volk 167559bb27 rename FileMeta::file to Option<content>
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:39:49 +00:00
Jason Volk 838e4b9d8d log more details for panic in tower handler
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:39:49 +00:00
Jason Volk 038b71fc9d add state to router
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:39:49 +00:00
Jason Volk 720fbd09c2 move routes into api router top level
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:39:49 +00:00
Jason Volk c42cb90dd3 simplify result handler / 405 error interposition
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:39:49 +00:00
Jason Volk 5950355348 break from wait loop on empty taskset
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-16 02:39:49 +00:00
strawberry f79bd2ac72 bump ruma-identifiers-validation to c51ccb2c68d2e3557eb12b1a49036531711ec0e5
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-15 22:13:05 -04:00
strawberry 80ec0e31b1 bump tracing fork
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-15 22:13:05 -04:00
strawberry bda44b16b1 ci: run nix dynamic build test with DIRENV_DEVSHELL=dynamic
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-15 22:13:05 -04:00
strawberry e2280aa1a5 ci: try removing --impure
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-15 22:13:05 -04:00
strawberry bdf2de076a ci: set NIX_CONFIG with our binary caches for the earlier CI steps
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-15 22:13:05 -04:00
strawberry 1797fec3c9 nix: disable USE_RTTI for rocksdb
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-15 22:13:05 -04:00
strawberry 188fa5a073 patch rustyline-async and use no default features
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:08:18 -04:00
strawberry f0c63c539b nix: dont build more unnecessary tests/tools for rocksdb
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:08:18 -04:00
strawberry 649e9da1f8 nix: try to make armv8.2-a / cortex-a55 optimised builds if target is aarch64
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:08:18 -04:00
strawberry df28359a19 nix: dont build rocksdb core tools (ldb / sst_dump) (-DWITH_CORE_TOOLS=1)
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:08:18 -04:00
strawberry 9370e93a8d nix: try to make x86-64-v2 optimised builds if target is x86_64
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:08:18 -04:00
strawberry bdd5845490 docs: suggest recursive chmod
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:08:18 -04:00
strawberry bacffd6174 rename conduit_cache_capacity_modifier to cache_capacity_modifier
this prefix causes you to require setting the environment variable
to `CONDUWUIT_CONDUIT_CACHE_CAPACITY_MODIFIER`

alias this so we dont break any configs

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:08:15 -04:00
strawberry a1bfd7a018 nix: dont include experimental feature on all-features builds
this is just future infra for it

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:06:52 -04:00
strawberry 7009f56a7a fix user directory publishing access controls
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:06:52 -04:00
strawberry 2c0bfac43e nix: bump flake.lock and rocksdb to v9.4.0
• Updated input 'attic':
    'github:zhaofengli/attic/717cc95983cdc357bc347d70be20ced21f935843' (2024-06-01)
  → 'github:zhaofengli/attic/6139576a3ce6bb992e0f6c3022528ec233e45f00' (2024-07-09)
• Updated input 'complement':
    'github:matrix-org/complement/bc97f1ddc1cd7485faf80c8935ee2641f3e1b57c' (2024-07-02)
  → 'github:matrix-org/complement/0d14432e010482ea9e13a6f7c47c1533c0c9d62f' (2024-07-10)
• Updated input 'crane':
    'github:ipetkov/crane/0aed560c5c0a61c9385bddff471a13036203e11c' (2024-07-06)
  → 'github:ipetkov/crane/2d83156f23c43598cf44e152c33a59d3892f8b29' (2024-07-09)
• Updated input 'fenix':
    'github:nix-community/fenix/abc0549e3560189462a7d394cc9d50af4608d103' (2024-07-08)
  → 'github:nix-community/fenix/5087b12a595ee73131a944d922f24d81dae05725' (2024-07-13)
• Updated input 'fenix/rust-analyzer-src':
    'github:rust-lang/rust-analyzer/a5b21ea0aa644dffd7cf958b43f11f221d53404e' (2024-07-07)
  → 'github:rust-lang/rust-analyzer/ffbc5ad993d5cd2f3b8bcf9a511165470944ab91' (2024-07-11)
• Updated input 'liburing':
    'github:axboe/liburing/7b3245583069bd481190c9da18f22e9fc8c3a805' (2024-06-22)
  → 'github:axboe/liburing/1d674f83b7d0f07553ac44d99a401b05853d9dbe' (2024-07-12)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/655a58a72a6601292512670343087c2d75d859c1' (2024-07-08)
  → 'github:NixOS/nixpkgs/7e7c39ea35c5cdd002cd4588b03a3fb9ece6fad9' (2024-07-12)
• Updated input 'rocksdb':
    'github:girlbossceo/rocksdb/a935c0273e1ba44eacf88ce3685a9b9831486155' (2024-07-02)
  → 'github:girlbossceo/rocksdb/911f4243e69c2e320a7a209bf1f5f3ff5f825495' (2024-07-13)

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:06:52 -04:00
strawberry fcb6c8a113 bump rust-rocksdb
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:06:52 -04:00
Charles Hall 1ab77aeb91 don't strip binary for dev builds
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-14 12:06:52 -04:00
40 changed files with 670 additions and 550 deletions
+11 -8
View File
@@ -38,8 +38,11 @@ env:
# Custom nix binary cache if fork is being used
ATTIC_ENDPOINT: ${{ vars.ATTIC_ENDPOINT }}
ATTIC_PUBLIC_KEY: ${{ vars.ATTIC_PUBLIC_KEY }}
# Get error output from nix that we can actually use
NIX_CONFIG: show-trace = true
# Get error output from nix that we can actually use, and use our binary caches for the earlier CI steps
NIX_CONFIG: |
show-trace = true
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit https://cache.lix.systems https://conduwuit.cachix.org
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
permissions:
packages: write
@@ -57,7 +60,7 @@ jobs:
uses: actions/checkout@v4
- name: Tag comparison check
if: startsWith(github.ref, 'refs/tags/v')
if: ${{ startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') }}
run: |
# Tag mismatch with latest repo tag check to prevent potential downgrades
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
@@ -115,7 +118,7 @@ jobs:
- name: Prepare build environment
run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --impure --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
nix profile install --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow
nix develop .#all-features --command true
@@ -237,7 +240,7 @@ jobs:
- name: Prepare build environment
run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --impure --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
nix profile install --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow
nix develop .#all-features --command true
@@ -293,15 +296,15 @@ jobs:
DOCKER_ARM64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
DOCKER_AMD64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
DOCKER_TAG: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
DOCKER_BRANCH: docker.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
DOCKER_BRANCH: docker.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
GHCR_ARM64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
GHCR_AMD64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
GHCR_TAG: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
GHCR_BRANCH: ghcr.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
GHCR_BRANCH: ghcr.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
GLCR_ARM64: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
GLCR_AMD64: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
GLCR_TAG: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
GLCR_BRANCH: registry.gitlab.com/conduwuit/conduwuit:${{ (startsWith(github.ref, 'refs/tags/v') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
GLCR_BRANCH: registry.gitlab.com/conduwuit/conduwuit:${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
+6 -3
View File
@@ -21,8 +21,11 @@ env:
# Custom nix binary cache if fork is being used
ATTIC_ENDPOINT: ${{ vars.ATTIC_ENDPOINT }}
ATTIC_PUBLIC_KEY: ${{ vars.ATTIC_PUBLIC_KEY }}
# Get error output from nix that we can actually use
NIX_CONFIG: show-trace = true
# Get error output from nix that we can actually use, and use our binary caches for the earlier CI steps
NIX_CONFIG: |
show-trace = true
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit https://cache.lix.systems https://conduwuit.cachix.org
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
@@ -98,7 +101,7 @@ jobs:
- name: Prepare build environment
run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --impure --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
nix profile install --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow
nix develop --command true
Generated
+13 -22
View File
@@ -769,7 +769,7 @@ dependencies = [
"regex",
"reqwest",
"ruma",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0)",
"ruma-identifiers-validation",
"rustyline-async",
"serde",
"serde_json",
@@ -2988,7 +2988,7 @@ dependencies = [
"percent-encoding",
"rand",
"regex",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-identifiers-validation",
"ruma-macros",
"serde",
"serde_html_form",
@@ -3015,7 +3015,7 @@ dependencies = [
"pulldown-cmark",
"regex",
"ruma-common",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-identifiers-validation",
"ruma-macros",
"serde",
"serde_json",
@@ -3046,15 +3046,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "ruma-identifiers-validation"
version = "0.9.5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
dependencies = [
"js_int",
"thiserror",
]
[[package]]
name = "ruma-identity-service-api"
version = "0.9.0"
@@ -3074,7 +3065,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-identifiers-validation",
"serde",
"syn 2.0.71",
"toml",
@@ -3138,8 +3129,8 @@ dependencies = [
[[package]]
name = "rust-librocksdb-sys"
version = "0.23.1+9.3.1"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=db1ba33c2b78ad228e2525e8902d059c24fc81a1#db1ba33c2b78ad228e2525e8902d059c24fc81a1"
version = "0.24.0+9.4.0"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=4056a3b0f823013fec49f6d0b3e5698856e6476a#4056a3b0f823013fec49f6d0b3e5698856e6476a"
dependencies = [
"bindgen",
"bzip2-sys",
@@ -3155,8 +3146,8 @@ dependencies = [
[[package]]
name = "rust-rocksdb"
version = "0.27.1"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=db1ba33c2b78ad228e2525e8902d059c24fc81a1#db1ba33c2b78ad228e2525e8902d059c24fc81a1"
version = "0.28.0"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=4056a3b0f823013fec49f6d0b3e5698856e6476a#4056a3b0f823013fec49f6d0b3e5698856e6476a"
dependencies = [
"libc",
"rust-librocksdb-sys",
@@ -4250,7 +4241,7 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]]
name = "tracing"
version = "0.1.40"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
dependencies = [
"log",
"pin-project-lite",
@@ -4261,7 +4252,7 @@ dependencies = [
[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
dependencies = [
"proc-macro2",
"quote",
@@ -4271,7 +4262,7 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.32"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
dependencies = [
"once_cell",
"valuable",
@@ -4291,7 +4282,7 @@ dependencies = [
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
dependencies = [
"log",
"once_cell",
@@ -4319,7 +4310,7 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.18"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
dependencies = [
"matchers",
"nu-ansi-term",
+16 -10
View File
@@ -309,7 +309,7 @@ features = [
[workspace.dependencies.ruma-identifiers-validation]
git = "https://github.com/girlbossceo/ruwuma"
rev = "fd686e77950680462377c9105dfb4136dd49c7a0"
rev = "c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
[workspace.dependencies.rust-rocksdb]
path = "deps/rust-rocksdb"
@@ -333,7 +333,7 @@ version = "0.10.8"
# optional opentelemetry, performance measurements, flamegraphs, etc for performance measurements and monitoring
[workspace.dependencies.opentelemetry]
version = "0.24.0"
version = "0.21.0"
[workspace.dependencies.tracing-flame]
version = "0.2.0"
@@ -342,11 +342,11 @@ version = "0.2.0"
version = "0.22.0"
[workspace.dependencies.opentelemetry_sdk]
version = "0.24.0"
version = "0.21.2"
features = ["rt-tokio"]
[workspace.dependencies.opentelemetry-jaeger]
version = "0.22.0"
version = "0.20.0"
features = ["rt-tokio"]
# optional sentry metrics for crash/panic reporting
@@ -405,8 +405,8 @@ features = [
]
[workspace.dependencies.rustyline-async]
git = "https://github.com/girlbossceo/rustyline-async"
rev = "de26100b0db03e419a3d8e1dd26895d170d1fe50"
version = "0.4.2"
default-features = false
[workspace.dependencies.termimad]
version = "0.29.4"
@@ -425,16 +425,16 @@ version = "0.1"
# https://github.com/girlbossceo/tracing/commit/b348dca742af641c47bc390261f60711c2af573c
[patch.crates-io.tracing-subscriber]
git = "https://github.com/girlbossceo/tracing"
rev = "b348dca742af641c47bc390261f60711c2af573c"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
[patch.crates-io.tracing]
git = "https://github.com/girlbossceo/tracing"
rev = "b348dca742af641c47bc390261f60711c2af573c"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
[patch.crates-io.tracing-core]
git = "https://github.com/girlbossceo/tracing"
rev = "b348dca742af641c47bc390261f60711c2af573c"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
[patch.crates-io.tracing-log]
git = "https://github.com/girlbossceo/tracing"
rev = "b348dca742af641c47bc390261f60711c2af573c"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
# fixes hyper graceful shutdowns [https://github.com/programatik29/axum-server/issues/114]
# https://github.com/girlbossceo/axum-server/commit/8e3368d899079818934e61cc9c839abcbbcada8a
@@ -442,6 +442,12 @@ rev = "b348dca742af641c47bc390261f60711c2af573c"
git = "https://github.com/girlbossceo/axum-server"
rev = "8e3368d899079818934e61cc9c839abcbbcada8a"
# adds a tab completion callback: https://github.com/girlbossceo/rustyline-async/commit/de26100b0db03e419a3d8e1dd26895d170d1fe50
# adds event for CTRL+\: https://github.com/girlbossceo/rustyline-async/commit/67d8c49aeac03a5ef4e818f663eaa94dd7bf339b
[patch.crates-io.rustyline-async]
git = "https://github.com/girlbossceo/rustyline-async"
rev = "de26100b0db03e419a3d8e1dd26895d170d1fe50"
#
# Our crates
#
+4 -1
View File
@@ -421,8 +421,11 @@ allow_profile_lookup_federation_requests = true
# Set this to any float value to multiply conduwuit's in-memory LRU caches with.
# May be useful if you have significant memory to spare to increase performance.
#
# This was previously called `conduit_cache_capacity_modifier`
#
# Defaults to 1.0.
#conduit_cache_capacity_modifier = 1.0
#cache_capacity_modifier = 1.0
# Set this to any float value in megabytes for conduwuit to tell the database engine that this much memory is available for database-related caches.
# May be useful if you have significant memory to spare to increase performance.
+1 -1
View File
@@ -27,7 +27,7 @@ malloc-usable-size = ["rust-rocksdb/malloc-usable-size"]
[dependencies.rust-rocksdb]
git = "https://github.com/zaidoon1/rust-rocksdb"
rev = "db1ba33c2b78ad228e2525e8902d059c24fc81a1"
rev = "4056a3b0f823013fec49f6d0b3e5698856e6476a"
#branch = "master"
default-features = false
+3 -5
View File
@@ -23,7 +23,7 @@ Otherwise, follow standard Rust project build guides (installing git and cloning
While conduwuit can run as any user it is better to use dedicated users for different services. This also allows
you to make sure that the file permissions are correctly set up.
In Debian or RHEL, you can use this command to create a conduwuit user:
In Debian or Fedora/RHEL, you can use this command to create a conduwuit user:
```bash
sudo adduser --system conduwuit --group --disabled-login --no-create-home
@@ -53,13 +53,11 @@ RocksDB is the only supported database backend.
## Setting the correct file permissions
If you are using a dedicated user for conduwuit, you will need to allow it to read the config. To do that you can run this command on
Debian or RHEL:
If you are using a dedicated user for conduwuit, you will need to allow it to read the config. To do that you can run this:
```bash
sudo chown -R root:root /etc/conduwuit
sudo chmod 755 /etc/conduwuit
sudo chmod -R 755 /etc/conduwuit
```
If you use the default database path you also need to run this:
+6 -2
View File
@@ -184,6 +184,10 @@ cargo test \
name = "nix-default"
group = "tests"
script = """
bin/nix-build-and-cache just .#default
nix run -L .#default -- --help
env DIRENV_DEVSHELL=dynamic \
direnv exec . \
bin/nix-build-and-cache just .#default
env DIRENV_DEVSHELL=dynamic \
direnv exec . \
nix run -L .#default -- --help
"""
Generated
+25 -25
View File
@@ -9,11 +9,11 @@
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1717279440,
"narHash": "sha256-kH04ReTjxOpQumgWnqy40vvQLSnLGxWP6RF3nq5Esrk=",
"lastModified": 1720542474,
"narHash": "sha256-aKjJ/4l2I9+wNGTaOGRsuS3M1+IoTibqgEMPDikXm04=",
"owner": "zhaofengli",
"repo": "attic",
"rev": "717cc95983cdc357bc347d70be20ced21f935843",
"rev": "6139576a3ce6bb992e0f6c3022528ec233e45f00",
"type": "github"
},
"original": {
@@ -81,11 +81,11 @@
"complement": {
"flake": false,
"locked": {
"lastModified": 1719903368,
"narHash": "sha256-PPzgxM4Bir+Zh9FUV/v+RBxEYeJxYVmi/BYo3uqt268=",
"lastModified": 1720637557,
"narHash": "sha256-oZz6nCmFmdJZpC+K1iOG2KkzTI6rlAmndxANPDVU7X0=",
"owner": "matrix-org",
"repo": "complement",
"rev": "bc97f1ddc1cd7485faf80c8935ee2641f3e1b57c",
"rev": "0d14432e010482ea9e13a6f7c47c1533c0c9d62f",
"type": "github"
},
"original": {
@@ -123,11 +123,11 @@
]
},
"locked": {
"lastModified": 1720226507,
"narHash": "sha256-yHVvNsgrpyNTXZBEokL8uyB2J6gB1wEx0KOJzoeZi1A=",
"lastModified": 1720546058,
"narHash": "sha256-iU2yVaPIZm5vMGdlT0+57vdB/aPq/V5oZFBRwYw+HBM=",
"owner": "ipetkov",
"repo": "crane",
"rev": "0aed560c5c0a61c9385bddff471a13036203e11c",
"rev": "2d83156f23c43598cf44e152c33a59d3892f8b29",
"type": "github"
},
"original": {
@@ -209,11 +209,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1720420198,
"narHash": "sha256-OIuDb6pHDyGpo7YMFyuRzMLcHm7mRvlYOz0Ht7ps2sU=",
"lastModified": 1720852044,
"narHash": "sha256-3NBYz8VuXuKU+8ONd9NFafCNjPEGHIZQ2Mdoam1a4mY=",
"owner": "nix-community",
"repo": "fenix",
"rev": "abc0549e3560189462a7d394cc9d50af4608d103",
"rev": "5087b12a595ee73131a944d922f24d81dae05725",
"type": "github"
},
"original": {
@@ -381,11 +381,11 @@
"liburing": {
"flake": false,
"locked": {
"lastModified": 1719025212,
"narHash": "sha256-kD0yhjNStqC6uFqC1AxBwUpc/HlSFtiKrV+gwDyroDc=",
"lastModified": 1720798442,
"narHash": "sha256-gtPppAoksMLW4GuruQ36nf4EAqIA1Bs6V9Xcx8dBxrQ=",
"owner": "axboe",
"repo": "liburing",
"rev": "7b3245583069bd481190c9da18f22e9fc8c3a805",
"rev": "1d674f83b7d0f07553ac44d99a401b05853d9dbe",
"type": "github"
},
"original": {
@@ -606,11 +606,11 @@
},
"nixpkgs_4": {
"locked": {
"lastModified": 1720418205,
"narHash": "sha256-cPJoFPXU44GlhWg4pUk9oUPqurPlCFZ11ZQPk21GTPU=",
"lastModified": 1720768451,
"narHash": "sha256-EYekUHJE2gxeo2pM/zM9Wlqw1Uw2XTJXOSAO79ksc4Y=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "655a58a72a6601292512670343087c2d75d859c1",
"rev": "7e7c39ea35c5cdd002cd4588b03a3fb9ece6fad9",
"type": "github"
},
"original": {
@@ -673,16 +673,16 @@
"rocksdb": {
"flake": false,
"locked": {
"lastModified": 1719949653,
"narHash": "sha256-DYx7XHH2GEh17GukKhXs6laM6l+eugCmRkF0adpi9wk=",
"lastModified": 1720900786,
"narHash": "sha256-Vta9Um/RRuWwZ46BjXftV06iWLm/j/9MX39emXUvSAY=",
"owner": "girlbossceo",
"repo": "rocksdb",
"rev": "a935c0273e1ba44eacf88ce3685a9b9831486155",
"rev": "911f4243e69c2e320a7a209bf1f5f3ff5f825495",
"type": "github"
},
"original": {
"owner": "girlbossceo",
"ref": "v9.3.1",
"ref": "v9.4.0",
"repo": "rocksdb",
"type": "github"
}
@@ -705,11 +705,11 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1720344064,
"narHash": "sha256-STmaV9Zu74QtkGGrbr9uMhskwagfCjJqOAYapXabiuk=",
"lastModified": 1720717809,
"narHash": "sha256-6I+fm+nTLF/iaj7ffiFGlSY7POmubwUaPA/Wq0Bm53M=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "a5b21ea0aa644dffd7cf958b43f11f221d53404e",
"rev": "ffbc5ad993d5cd2f3b8bcf9a511165470944ab91",
"type": "github"
},
"original": {
+58 -15
View File
@@ -9,8 +9,7 @@
flake-utils.url = "github:numtide/flake-utils?ref=main";
nix-filter.url = "github:numtide/nix-filter?ref=main";
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
# https://github.com/girlbossceo/rocksdb/commit/db6df0b185774778457dabfcbd822cb81760cade
rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.3.1"; flake = false; };
rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.4.0"; flake = false; };
liburing = { url = "github:axboe/liburing?ref=master"; flake = false; };
};
@@ -45,10 +44,34 @@
# we have this already at https://github.com/girlbossceo/rocksdb/commit/a935c0273e1ba44eacf88ce3685a9b9831486155
# unsetting this so i don't have to revert it and make this nix exclusive
patches = [];
# no real reason to have snappy, no one uses this
cmakeFlags = pkgs.lib.subtractLists
[ "-DWITH_SNAPPY=1" ]
old.cmakeFlags;
[
# no real reason to have snappy, no one uses this
"-DWITH_SNAPPY=1"
# we dont need to use ldb or sst_dump (core_tools)
"-DWITH_CORE_TOOLS=1"
# we dont need to build rocksdb tests
"-DWITH_TESTS=1"
# we use rust-rocksdb via C interface and dont need C++ RTTI
"-DUSE_RTTI=1"
]
old.cmakeFlags
++ [
# we dont need to use ldb or sst_dump (core_tools)
"-DWITH_CORE_TOOLS=0"
# we dont need trace tools
"-DWITH_TRACE_TOOLS=0"
# we dont need to build rocksdb tests
"-DWITH_TESTS=0"
# we use rust-rocksdb via C interface and dont need C++ RTTI
"-DUSE_RTTI=0"
];
# outputs has "tools" which we dont need or use
outputs = [ "out" ];
# preInstall hooks has stuff for messing with ldb/sst_dump which we dont need or use
preInstall = "";
});
# TODO: remove once https://github.com/NixOS/nixpkgs/pull/314945 is available
liburing = pkgs.liburing.overrideAttrs (old: {
@@ -123,8 +146,12 @@
default = scopeHost.main;
all-features = scopeHost.main.override {
all_features = true;
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
};
hmalloc = scopeHost.main.override { features = ["hardened_malloc"]; };
@@ -132,8 +159,12 @@
oci-image-all-features = scopeHost.oci-image.override {
main = scopeHost.main.override {
all_features = true;
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
};
};
oci-image-hmalloc = scopeHost.oci-image.override {
@@ -175,8 +206,12 @@
name = "${binaryName}-all-features";
value = scopeCrossStatic.main.override {
all_features = true;
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
};
}
@@ -200,8 +235,12 @@
value = scopeCrossStatic.oci-image.override {
main = scopeCrossStatic.main.override {
all_features = true;
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
};
};
}
@@ -229,8 +268,12 @@
(scopeHostStatic.overrideScope (final: prev: {
main = prev.main.override {
all_features = true;
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
};
}));
devShells.no-features = mkDevShell
+6
View File
@@ -13,6 +13,12 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
lib.concatStringsSep
" "
([]
++ lib.optionals
stdenv.targetPlatform.isx86_64
[ "-C" "target-cpu=x86-64-v2" ]
++ lib.optionals
stdenv.targetPlatform.isAarch64
[ "-C" "target-cpu=cortex-a55" ] # cortex-a55 == ARMv8.2-a
# This disables PIE for static builds, which isn't great in terms
# of security. Unfortunately, my hand is forced because nixpkgs'
# `libstdc++.a` is built without `-fPIE`, which precludes us from
+27 -2
View File
@@ -71,10 +71,29 @@ buildDepsOnlyEnv =
# which breaks Darwin entirely
enableLiburing = enableLiburing;
}).overrideAttrs (old: {
# TODO: static rocksdb fails to build on darwin
# TODO: static rocksdb fails to build on darwin, also see <https://github.com/NixOS/nixpkgs/issues/320448>
# build log at <https://girlboss.ceo/~strawberry/pb/JjGH>
meta.broken = stdenv.hostPlatform.isStatic && stdenv.isDarwin;
enableLiburing = enableLiburing;
sse42Support = stdenv.targetPlatform.isx86_64;
cmakeFlags = if stdenv.targetPlatform.isx86_64
then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags
++ lib.optionals stdenv.targetPlatform.isx86_64 [
"-DPORTABLE=x86-64-v2"
"-DUSE_SSE=1"
"-DHAVE_SSE=1"
"-DHAVE_SSE42=1"
]
else if stdenv.targetPlatform.isAarch64
then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags
++ lib.optionals stdenv.targetPlatform.isAarch64 [
# cortex-a55 == ARMv8.2-a
"-DPORTABLE=armv8.2-a"
]
else old.cmakeFlags;
});
in
{
@@ -101,7 +120,11 @@ buildPackageEnv = {
# Only needed in static stdenv because these are transitive dependencies of rocksdb
CARGO_BUILD_RUSTFLAGS = buildDepsOnlyEnv.CARGO_BUILD_RUSTFLAGS
+ lib.optionalString (enableLiburing && stdenv.hostPlatform.isStatic)
" -L${lib.getLib liburing}/lib -luring";
" -L${lib.getLib liburing}/lib -luring"
+ lib.optionalString stdenv.targetPlatform.isx86_64
" -Ctarget-cpu=x86-64-v2"
+ lib.optionalString stdenv.targetPlatform.isAarch64
" -Ctarget-cpu=cortex-a55"; # cortex-a55 == ARMv8.2-a
};
@@ -126,6 +149,8 @@ commonAttrs = {
];
};
dontStrip = profile == "dev";
buildInputs = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys';
nativeBuildInputs = [
+8 -3
View File
@@ -117,7 +117,12 @@ pub(crate) async fn set_room_visibility_route(
return Err(Error::BadRequest(ErrorKind::NotFound, "Room not found"));
}
user_can_publish_room(sender_user, &body.room_id)?;
if !user_can_publish_room(sender_user, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"User is not allowed to publish this room",
));
}
match &body.visibility {
room::Visibility::Public => {
@@ -377,8 +382,8 @@ fn user_can_publish_room(user_id: &UserId, room_id: &RoomId) -> Result<bool> {
Ok(event.sender == user_id)
} else {
return Err(Error::BadRequest(
ErrorKind::Unauthorized,
"You are not allowed to publish this room to the room directory",
ErrorKind::forbidden(),
"User is not allowed to publish this room",
));
}
}
+6 -3
View File
@@ -200,12 +200,13 @@ pub(crate) async fn get_content_route(
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
if let Some(FileMeta {
content,
content_type,
file,
content_disposition,
}) = services().media.get(&mxc).await?
{
let content_disposition = Some(make_content_disposition(&content_type, content_disposition, None));
let file = content.expect("content");
Ok(get_content::v3::Response {
file,
@@ -282,8 +283,8 @@ pub(crate) async fn get_content_as_filename_route(
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
if let Some(FileMeta {
content,
content_type,
file,
content_disposition,
}) = services().media.get(&mxc).await?
{
@@ -293,6 +294,7 @@ pub(crate) async fn get_content_as_filename_route(
Some(body.filename.clone()),
));
let file = content.expect("content");
Ok(get_content_as_filename::v3::Response {
file,
content_type,
@@ -371,8 +373,8 @@ pub(crate) async fn get_content_thumbnail_route(
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
if let Some(FileMeta {
content,
content_type,
file,
content_disposition,
}) = services()
.media
@@ -388,6 +390,7 @@ pub(crate) async fn get_content_thumbnail_route(
.await?
{
let content_disposition = Some(make_content_disposition(&content_type, content_disposition, None));
let file = content.expect("content");
Ok(get_content_thumbnail::v3::Response {
file,
+5 -5
View File
@@ -1,15 +1,15 @@
pub mod client;
mod router;
pub mod routes;
pub mod router;
pub mod server;
extern crate conduit_core as conduit;
extern crate conduit_service as service;
pub(crate) use conduit::{debug_info, debug_warn, utils, Error, Result};
pub(crate) use service::{pdu::PduEvent, services, user_is_local};
pub(crate) use conduit::{debug_info, debug_warn, pdu::PduEvent, utils, Error, Result};
pub(crate) use service::{services, user_is_local};
pub(crate) use self::router::{Ruma, RumaResponse};
pub use crate::router::State;
pub(crate) use crate::router::{Ruma, RumaResponse};
conduit::mod_ctor! {}
conduit::mod_dtor! {}
+24 -15
View File
@@ -1,15 +1,24 @@
mod args;
mod auth;
mod handler;
mod request;
mod response;
use axum::{
response::IntoResponse,
routing::{any, get, post},
Router,
};
use conduit::{err, Error, Server};
use conduit::{err, Server};
use http::Uri;
use ruma::api::client::error::ErrorKind;
use crate::{client, router::RouterExt, server};
use self::handler::RouterExt;
pub(super) use self::{args::Args as Ruma, response::RumaResponse};
use crate::{client, server};
pub fn build(router: Router, server: &Server) -> Router {
pub type State = &'static service::Services;
pub fn build(router: Router<State>, server: &Server) -> Router<State> {
let config = &server.config;
let router = router
.ruma_route(client::get_supported_versions_route)
@@ -95,7 +104,7 @@ pub fn build(router: Router, server: &Server) -> Router {
.ruma_route(client::get_member_events_route)
.ruma_route(client::get_protocols_route)
.route("/_matrix/client/unstable/thirdparty/protocols",
get(client::get_protocols_route_unstable))
get(client::get_protocols_route_unstable))
.ruma_route(client::send_message_event_route)
.ruma_route(client::send_state_event_for_key_route)
.ruma_route(client::get_state_events_route)
@@ -180,15 +189,15 @@ pub fn build(router: Router, server: &Server) -> Router {
.ruma_route(client::get_relating_events_with_rel_type_route)
.ruma_route(client::get_relating_events_route)
.ruma_route(client::get_hierarchy_route)
.ruma_route(client::get_mutual_rooms_route)
.ruma_route(client::get_room_summary)
.route(
"/_matrix/client/unstable/im.nheko.summary/rooms/:room_id_or_alias/summary",
get(client::get_room_summary_legacy)
)
.ruma_route(client::well_known_support)
.ruma_route(client::well_known_client)
.route("/_conduwuit/server_version", get(client::conduwuit_server_version))
.ruma_route(client::get_mutual_rooms_route)
.ruma_route(client::get_room_summary)
.route(
"/_matrix/client/unstable/im.nheko.summary/rooms/:room_id_or_alias/summary",
get(client::get_room_summary_legacy)
)
.ruma_route(client::well_known_support)
.ruma_route(client::well_known_client)
.route("/_conduwuit/server_version", get(client::conduwuit_server_version))
.route("/_matrix/client/r0/rooms/:room_id/initialSync", get(initial_sync))
.route("/_matrix/client/v3/rooms/:room_id/initialSync", get(initial_sync))
.route("/client/server.json", get(client::syncv3_client_server_json));
@@ -233,7 +242,7 @@ pub fn build(router: Router, server: &Server) -> Router {
}
async fn initial_sync(_uri: Uri) -> impl IntoResponse {
Error::BadRequest(ErrorKind::GuestAccessForbidden, "Guest access not implemented")
err!(Request(GuestAccessForbidden("Guest access not implemented")))
}
async fn federation_disabled() -> impl IntoResponse { err!(Config("allow_federation", "Federation is disabled.")) }
@@ -1,24 +1,15 @@
mod auth;
mod handler;
mod request;
mod response;
use std::{mem, ops::Deref};
use axum::{async_trait, body::Body, extract::FromRequest};
use bytes::{BufMut, BytesMut};
use conduit::{debug, debug_warn, trace, warn};
use ruma::{
api::{client::error::ErrorKind, IncomingRequest},
CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
};
use conduit::{debug, err, trace, Error, Result};
use ruma::{api::IncomingRequest, CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId};
use self::{auth::Auth, request::Request};
pub(super) use self::{handler::RouterExt, response::RumaResponse};
use crate::{service::appservice::RegistrationInfo, services, Error, Result};
use super::{auth, auth::Auth, request, request::Request};
use crate::{service::appservice::RegistrationInfo, services};
/// Extractor for Ruma request structs
pub(crate) struct Ruma<T> {
pub(crate) struct Args<T> {
/// Request struct body
pub(crate) body: T,
@@ -44,7 +35,7 @@ pub(crate) struct Ruma<T> {
}
#[async_trait]
impl<T, S> FromRequest<S, Body> for Ruma<T>
impl<T, S> FromRequest<S, Body> for Args<T>
where
T: IncomingRequest,
{
@@ -65,7 +56,7 @@ where
}
}
impl<T> Deref for Ruma<T> {
impl<T> Deref for Args<T> {
type Target = T;
fn deref(&self) -> &Self::Target { &self.body }
@@ -109,21 +100,14 @@ where
let mut http_request = hyper::Request::builder()
.uri(request.parts.uri.clone())
.method(request.parts.method.clone());
*http_request.headers_mut().unwrap() = request.parts.headers.clone();
let http_request = http_request.body(body).unwrap();
debug!(
"{:?} {:?} {:?}",
http_request.method(),
http_request.uri(),
http_request.headers()
);
*http_request.headers_mut().expect("mutable http headers") = request.parts.headers.clone();
let http_request = http_request.body(body).expect("http request body");
trace!("{:?} {:?} {:?}", http_request.method(), http_request.uri(), json_body);
let body = T::try_from_http_request(http_request, &request.path).map_err(|e| {
warn!("try_from_http_request failed: {e:?}",);
debug_warn!("JSON body: {:?}", json_body);
Error::BadRequest(ErrorKind::BadJson, "Failed to deserialize request.")
})?;
let headers = http_request.headers();
let method = http_request.method();
let uri = http_request.uri();
debug!("{method:?} {uri:?} {headers:?}");
trace!("{method:?} {uri:?} {json_body:?}");
Ok(body)
T::try_from_http_request(http_request, &request.path).map_err(|e| err!(Request(BadJson(debug_warn!("{e}")))))
}
+8 -8
View File
@@ -10,7 +10,7 @@ use conduit::Result;
use http::Method;
use ruma::api::IncomingRequest;
use super::{Ruma, RumaResponse};
use super::{Ruma, RumaResponse, State};
pub(in super::super) trait RouterExt {
fn ruma_route<H, T>(self, handler: H) -> Self
@@ -18,7 +18,7 @@ pub(in super::super) trait RouterExt {
H: RumaHandler<T>;
}
impl RouterExt for Router {
impl RouterExt for Router<State> {
fn ruma_route<H, T>(self, handler: H) -> Self
where
H: RumaHandler<T>,
@@ -28,9 +28,9 @@ impl RouterExt for Router {
}
pub(in super::super) trait RumaHandler<T> {
fn add_routes(&self, router: Router) -> Router;
fn add_routes(&self, router: Router<State>) -> Router<State>;
fn add_route(&self, router: Router, path: &str) -> Router;
fn add_route(&self, router: Router<State>, path: &str) -> Router<State>;
}
macro_rules! ruma_handler {
@@ -41,17 +41,17 @@ macro_rules! ruma_handler {
Req: IncomingRequest + Send + 'static,
Ret: IntoResponse,
Fut: Future<Output = Result<Req::OutgoingResponse, Ret>> + Send,
Fun: FnOnce($($tx,)* Ruma<Req>) -> Fut + Clone + Send + Sync + 'static,
$( $tx: FromRequestParts<()> + Send + 'static, )*
Fun: FnOnce($($tx,)* Ruma<Req>,) -> Fut + Clone + Send + Sync + 'static,
$( $tx: FromRequestParts<State> + Send + 'static, )*
{
fn add_routes(&self, router: Router) -> Router {
fn add_routes(&self, router: Router<State>) -> Router<State> {
Req::METADATA
.history
.all_paths()
.fold(router, |router, path| self.add_route(router, path))
}
fn add_route(&self, router: Router, path: &str) -> Router {
fn add_route(&self, router: Router<State>, path: &str) -> Router<State> {
let handle = self.clone();
let method = method_to_filter(&Req::METADATA.method);
let action = |$($tx,)* req| async { handle($($tx,)* req).await.map(RumaResponse) };
+6 -5
View File
@@ -2,11 +2,11 @@ use std::str;
use axum::{extract::Path, RequestExt, RequestPartsExt};
use bytes::Bytes;
use conduit::err;
use http::request::Parts;
use ruma::api::client::error::ErrorKind;
use serde::Deserialize;
use crate::{services, Error, Result};
use crate::{services, Result};
#[derive(Deserialize)]
pub(super) struct QueryParams {
@@ -26,14 +26,15 @@ pub(super) async fn from(request: hyper::Request<axum::body::Body>) -> Result<Re
let (mut parts, body) = limited.into_parts();
let path: Path<Vec<String>> = parts.extract().await?;
let query = serde_html_form::from_str(parts.uri.query().unwrap_or_default())
.map_err(|_| Error::BadRequest(ErrorKind::Unknown, "Failed to read query parameters"))?;
let query = parts.uri.query().unwrap_or_default();
let query =
serde_html_form::from_str(query).map_err(|e| err!(Request(Unknown("Failed to read query parameters: {e}"))))?;
let max_body_size = services().globals.config.max_request_size;
let body = axum::body::to_bytes(body, max_body_size)
.await
.map_err(|_| Error::BadRequest(ErrorKind::TooLarge, "Request body too large"))?;
.map_err(|e| err!(Request(TooLarge("Request body too large: {e}"))))?;
Ok(Request {
path,
+59 -59
View File
@@ -1,7 +1,8 @@
use std::{collections::BTreeMap, net::IpAddr, time::Instant};
use axum::extract::State;
use axum_client_ip::InsecureClientIp;
use conduit::debug_warn;
use conduit::{debug, debug_warn, err, trace, warn, Err};
use ruma::{
api::{
client::error::ErrorKind,
@@ -18,11 +19,10 @@ use ruma::{
OwnedEventId, ServerName,
};
use tokio::sync::RwLock;
use tracing::{debug, error, trace, warn};
use crate::{
service::rooms::event_handler::parse_incoming_pdu,
services,
services::Services,
utils::{self},
Error, Result, Ruma,
};
@@ -34,29 +34,23 @@ type ResolvedMap = BTreeMap<OwnedEventId, Result<(), Error>>;
/// Push EDUs and PDUs to this server.
#[tracing::instrument(skip_all, fields(%client), name = "send")]
pub(crate) async fn send_transaction_message_route(
InsecureClientIp(client): InsecureClientIp, body: Ruma<send_transaction_message::v1::Request>,
State(services): State<&Services>, InsecureClientIp(client): InsecureClientIp,
body: Ruma<send_transaction_message::v1::Request>,
) -> Result<send_transaction_message::v1::Response> {
let origin = body.origin.as_ref().expect("server is authenticated");
if *origin != body.body.origin {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Not allowed to send transactions on behalf of other servers",
));
return Err!(Request(Forbidden(
"Not allowed to send transactions on behalf of other servers"
)));
}
if body.pdus.len() > 50_usize {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Not allowed to send more than 50 PDUs in one transaction",
));
return Err!(Request(Forbidden("Not allowed to send more than 50 PDUs in one transaction")));
}
if body.edus.len() > 100_usize {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Not allowed to send more than 100 EDUs in one transaction",
));
return Err!(Request(Forbidden("Not allowed to send more than 100 EDUs in one transaction")));
}
let txn_start_time = Instant::now();
@@ -69,8 +63,8 @@ pub(crate) async fn send_transaction_message_route(
"Starting txn",
);
let resolved_map = handle_pdus(&client, &body, origin, &txn_start_time).await?;
handle_edus(&client, &body, origin).await?;
let resolved_map = handle_pdus(services, &client, &body, origin, &txn_start_time).await?;
handle_edus(services, &client, &body, origin).await?;
debug!(
pdus = ?body.pdus.len(),
@@ -90,7 +84,8 @@ pub(crate) async fn send_transaction_message_route(
}
async fn handle_pdus(
_client: &IpAddr, body: &Ruma<send_transaction_message::v1::Request>, origin: &ServerName, txn_start_time: &Instant,
services: &Services, _client: &IpAddr, body: &Ruma<send_transaction_message::v1::Request>, origin: &ServerName,
txn_start_time: &Instant,
) -> Result<ResolvedMap> {
let mut parsed_pdus = Vec::with_capacity(body.pdus.len());
for pdu in &body.pdus {
@@ -110,7 +105,7 @@ async fn handle_pdus(
// corresponding signing keys
let pub_key_map = RwLock::new(BTreeMap::new());
if !parsed_pdus.is_empty() {
services()
services
.rooms
.event_handler
.fetch_required_signing_keys(parsed_pdus.iter().map(|(_event_id, event, _room_id)| event), &pub_key_map)
@@ -126,7 +121,7 @@ async fn handle_pdus(
let mut resolved_map = BTreeMap::new();
for (event_id, value, room_id) in parsed_pdus {
let pdu_start_time = Instant::now();
let mutex_lock = services()
let mutex_lock = services
.rooms
.event_handler
.mutex_federation
@@ -134,7 +129,7 @@ async fn handle_pdus(
.await;
resolved_map.insert(
event_id.clone(),
services()
services
.rooms
.event_handler
.handle_incoming_pdu(origin, &room_id, &event_id, value, true, &pub_key_map)
@@ -162,7 +157,7 @@ async fn handle_pdus(
}
async fn handle_edus(
client: &IpAddr, body: &Ruma<send_transaction_message::v1::Request>, origin: &ServerName,
services: &Services, client: &IpAddr, body: &Ruma<send_transaction_message::v1::Request>, origin: &ServerName,
) -> Result<()> {
for edu in body
.edus
@@ -170,12 +165,12 @@ async fn handle_edus(
.filter_map(|edu| serde_json::from_str::<Edu>(edu.json().get()).ok())
{
match edu {
Edu::Presence(presence) => handle_edu_presence(client, origin, presence).await?,
Edu::Receipt(receipt) => handle_edu_receipt(client, origin, receipt).await?,
Edu::Typing(typing) => handle_edu_typing(client, origin, typing).await?,
Edu::DeviceListUpdate(content) => handle_edu_device_list_update(client, origin, content).await?,
Edu::DirectToDevice(content) => handle_edu_direct_to_device(client, origin, content).await?,
Edu::SigningKeyUpdate(content) => handle_edu_signing_key_update(client, origin, content).await?,
Edu::Presence(presence) => handle_edu_presence(services, client, origin, presence).await?,
Edu::Receipt(receipt) => handle_edu_receipt(services, client, origin, receipt).await?,
Edu::Typing(typing) => handle_edu_typing(services, client, origin, typing).await?,
Edu::DeviceListUpdate(content) => handle_edu_device_list_update(services, client, origin, content).await?,
Edu::DirectToDevice(content) => handle_edu_direct_to_device(services, client, origin, content).await?,
Edu::SigningKeyUpdate(content) => handle_edu_signing_key_update(services, client, origin, content).await?,
Edu::_Custom(ref _custom) => {
debug_warn!(?body.edus, "received custom/unknown EDU");
},
@@ -185,8 +180,10 @@ async fn handle_edus(
Ok(())
}
async fn handle_edu_presence(_client: &IpAddr, origin: &ServerName, presence: PresenceContent) -> Result<()> {
if !services().globals.allow_incoming_presence() {
async fn handle_edu_presence(
services: &Services, _client: &IpAddr, origin: &ServerName, presence: PresenceContent,
) -> Result<()> {
if !services.globals.allow_incoming_presence() {
return Ok(());
}
@@ -199,7 +196,7 @@ async fn handle_edu_presence(_client: &IpAddr, origin: &ServerName, presence: Pr
continue;
}
services().presence.set_presence(
services.presence.set_presence(
&update.user_id,
&update.presence,
Some(update.currently_active),
@@ -211,13 +208,15 @@ async fn handle_edu_presence(_client: &IpAddr, origin: &ServerName, presence: Pr
Ok(())
}
async fn handle_edu_receipt(_client: &IpAddr, origin: &ServerName, receipt: ReceiptContent) -> Result<()> {
if !services().globals.allow_incoming_read_receipts() {
async fn handle_edu_receipt(
services: &Services, _client: &IpAddr, origin: &ServerName, receipt: ReceiptContent,
) -> Result<()> {
if !services.globals.allow_incoming_read_receipts() {
return Ok(());
}
for (room_id, room_updates) in receipt.receipts {
if services()
if services
.rooms
.event_handler
.acl_check(origin, &room_id)
@@ -239,7 +238,7 @@ async fn handle_edu_receipt(_client: &IpAddr, origin: &ServerName, receipt: Rece
continue;
}
if services()
if services
.rooms
.state_cache
.room_members(&room_id)
@@ -255,7 +254,7 @@ async fn handle_edu_receipt(_client: &IpAddr, origin: &ServerName, receipt: Rece
room_id: room_id.clone(),
};
services()
services
.rooms
.read_receipt
.readreceipt_update(&user_id, &room_id, &event)?;
@@ -273,8 +272,10 @@ async fn handle_edu_receipt(_client: &IpAddr, origin: &ServerName, receipt: Rece
Ok(())
}
async fn handle_edu_typing(_client: &IpAddr, origin: &ServerName, typing: TypingContent) -> Result<()> {
if !services().globals.config.allow_incoming_typing {
async fn handle_edu_typing(
services: &Services, _client: &IpAddr, origin: &ServerName, typing: TypingContent,
) -> Result<()> {
if !services.globals.config.allow_incoming_typing {
return Ok(());
}
@@ -286,7 +287,7 @@ async fn handle_edu_typing(_client: &IpAddr, origin: &ServerName, typing: Typing
return Ok(());
}
if services()
if services
.rooms
.event_handler
.acl_check(typing.user_id.server_name(), &typing.room_id)
@@ -299,26 +300,26 @@ async fn handle_edu_typing(_client: &IpAddr, origin: &ServerName, typing: Typing
return Ok(());
}
if services()
if services
.rooms
.state_cache
.is_joined(&typing.user_id, &typing.room_id)?
{
if typing.typing {
let timeout = utils::millis_since_unix_epoch().saturating_add(
services()
services
.globals
.config
.typing_federation_timeout_s
.saturating_mul(1000),
);
services()
services
.rooms
.typing
.typing_add(&typing.user_id, &typing.room_id, timeout)
.await?;
} else {
services()
services
.rooms
.typing
.typing_remove(&typing.user_id, &typing.room_id)
@@ -336,7 +337,7 @@ async fn handle_edu_typing(_client: &IpAddr, origin: &ServerName, typing: Typing
}
async fn handle_edu_device_list_update(
_client: &IpAddr, origin: &ServerName, content: DeviceListUpdateContent,
services: &Services, _client: &IpAddr, origin: &ServerName, content: DeviceListUpdateContent,
) -> Result<()> {
let DeviceListUpdateContent {
user_id,
@@ -351,13 +352,13 @@ async fn handle_edu_device_list_update(
return Ok(());
}
services().users.mark_device_key_update(&user_id)?;
services.users.mark_device_key_update(&user_id)?;
Ok(())
}
async fn handle_edu_direct_to_device(
_client: &IpAddr, origin: &ServerName, content: DirectDeviceContent,
services: &Services, _client: &IpAddr, origin: &ServerName, content: DirectDeviceContent,
) -> Result<()> {
let DirectDeviceContent {
sender,
@@ -375,7 +376,7 @@ async fn handle_edu_direct_to_device(
}
// Check if this is a new transaction id
if services()
if services
.transaction_ids
.existing_txnid(&sender, None, &message_id)?
.is_some()
@@ -387,28 +388,27 @@ async fn handle_edu_direct_to_device(
for (target_device_id_maybe, event) in map {
match target_device_id_maybe {
DeviceIdOrAllDevices::DeviceId(target_device_id) => {
services().users.add_to_device_event(
services.users.add_to_device_event(
&sender,
target_user_id,
target_device_id,
&ev_type.to_string(),
event.deserialize_as().map_err(|e| {
error!("To-Device event is invalid: {event:?} {e}");
Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid")
})?,
event
.deserialize_as()
.map_err(|e| err!(Request(InvalidParam(error!("To-Device event is invalid: {e}")))))?,
)?;
},
DeviceIdOrAllDevices::AllDevices => {
for target_device_id in services().users.all_device_ids(target_user_id) {
services().users.add_to_device_event(
for target_device_id in services.users.all_device_ids(target_user_id) {
services.users.add_to_device_event(
&sender,
target_user_id,
&target_device_id?,
&ev_type.to_string(),
event
.deserialize_as()
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid"))?,
.map_err(|e| err!(Request(InvalidParam("Event is invalid: {e}"))))?,
)?;
}
},
@@ -417,7 +417,7 @@ async fn handle_edu_direct_to_device(
}
// Save transaction id with empty data
services()
services
.transaction_ids
.add_txnid(&sender, None, &message_id, &[])?;
@@ -425,7 +425,7 @@ async fn handle_edu_direct_to_device(
}
async fn handle_edu_signing_key_update(
_client: &IpAddr, origin: &ServerName, content: SigningKeyUpdateContent,
services: &Services, _client: &IpAddr, origin: &ServerName, content: SigningKeyUpdateContent,
) -> Result<()> {
let SigningKeyUpdateContent {
user_id,
@@ -442,7 +442,7 @@ async fn handle_edu_signing_key_update(
}
if let Some(master_key) = master_key {
services()
services
.users
.add_cross_signing_keys(&user_id, &master_key, &self_signing_key, &None, true)?;
}
+6 -5
View File
@@ -58,8 +58,8 @@ pub struct Config {
#[serde(default = "default_pdu_cache_capacity")]
pub pdu_cache_capacity: u32,
#[serde(default = "default_conduit_cache_capacity_modifier")]
pub conduit_cache_capacity_modifier: f64,
#[serde(default = "default_cache_capacity_modifier", alias = "conduit_cache_capacity_modifier")]
pub cache_capacity_modifier: f64,
#[serde(default = "default_auth_chain_cache_capacity")]
pub auth_chain_cache_capacity: u32,
#[serde(default = "default_shorteventid_cache_capacity")]
@@ -391,8 +391,9 @@ struct ListeningAddr {
addrs: Either<IpAddr, Vec<IpAddr>>,
}
const DEPRECATED_KEYS: &[&str] = &[
const DEPRECATED_KEYS: &[&str; 9] = &[
"cache_capacity",
"conduit_cache_capacity_modifier",
"max_concurrent_requests",
"well_known_client",
"well_known_server",
@@ -484,7 +485,7 @@ impl fmt::Display for Config {
);
line("Database backups to keep", &self.database_backups_to_keep.to_string());
line("Database cache capacity (MB)", &self.db_cache_capacity_mb.to_string());
line("Cache capacity modifier", &self.conduit_cache_capacity_modifier.to_string());
line("Cache capacity modifier", &self.cache_capacity_modifier.to_string());
line("PDU cache capacity", &self.pdu_cache_capacity.to_string());
line("Auth chain cache capacity", &self.auth_chain_cache_capacity.to_string());
line("Short eventid cache capacity", &self.shorteventid_cache_capacity.to_string());
@@ -847,7 +848,7 @@ fn default_db_cache_capacity_mb() -> f64 { 256.0 }
fn default_pdu_cache_capacity() -> u32 { 150_000 }
fn default_conduit_cache_capacity_modifier() -> f64 { 1.0 }
fn default_cache_capacity_modifier() -> f64 { 1.0 }
fn default_auth_chain_cache_capacity() -> u32 { 100_000 }
+9 -4
View File
@@ -31,6 +31,7 @@
//! Err(Database(error!("problem with db: {msg}")))` logs the error at the
//! callsite and then returns the error with the same string. Caller has the
//! option of replacing `error!` with `debug_error!`.
#[macro_export]
macro_rules! Err {
($($args:tt)*) => {
@@ -49,14 +50,16 @@ macro_rules! err {
$crate::$level!($($args),*);
$crate::error::Error::Request(
::ruma::api::client::error::ErrorKind::forbidden(),
$crate::format_maybe!($($args),*)
$crate::format_maybe!($($args),*),
::http::StatusCode::BAD_REQUEST
)
}};
(Request(Forbidden($($args:expr),*))) => {
$crate::error::Error::Request(
::ruma::api::client::error::ErrorKind::forbidden(),
$crate::format_maybe!($($args),*)
$crate::format_maybe!($($args),*),
::http::StatusCode::BAD_REQUEST
)
};
@@ -64,14 +67,16 @@ macro_rules! err {
$crate::$level!($($args),*);
$crate::error::Error::Request(
::ruma::api::client::error::ErrorKind::$variant,
$crate::format_maybe!($($args),*)
$crate::format_maybe!($($args),*),
::http::StatusCode::BAD_REQUEST
)
}};
(Request($variant:ident($($args:expr),*))) => {
$crate::error::Error::Request(
::ruma::api::client::error::ErrorKind::$variant,
$crate::format_maybe!($($args),*)
$crate::format_maybe!($($args),*),
::http::StatusCode::BAD_REQUEST
)
};
+5 -4
View File
@@ -68,7 +68,7 @@ pub enum Error {
#[error("{0}: {1}")]
BadRequest(ruma::api::client::error::ErrorKind, &'static str), //TODO: remove
#[error("{0}: {1}")]
Request(ruma::api::client::error::ErrorKind, Cow<'static, str>),
Request(ruma::api::client::error::ErrorKind, Cow<'static, str>, http::StatusCode),
#[error("from {0}: {1}")]
Redaction(ruma::OwnedServerName, ruma::canonical_json::RedactionError),
#[error("Remote server {0} responded with: {1}")]
@@ -78,7 +78,7 @@ pub enum Error {
// conduwuit
#[error("Arithmetic operation failed: {0}")]
Arithmetic(&'static str),
Arithmetic(Cow<'static, str>),
#[error("There was a problem with the '{0}' directive in your configuration: {1}")]
Config(&'static str, Cow<'static, str>),
#[error("{0}")]
@@ -120,7 +120,7 @@ impl Error {
match self {
Self::Federation(_, error) => response::ruma_error_kind(error).clone(),
Self::BadRequest(kind, _) | Self::Request(kind, _) => kind.clone(),
Self::BadRequest(kind, ..) | Self::Request(kind, ..) => kind.clone(),
_ => Unknown,
}
}
@@ -128,7 +128,8 @@ impl Error {
pub fn status_code(&self) -> http::StatusCode {
match self {
Self::Federation(_, ref error) | Self::RumaError(ref error) => error.status_code,
Self::BadRequest(ref kind, _) | Self::Request(ref kind, _) => response::bad_request_code(kind),
Self::Request(ref kind, _, code) => response::status_code(kind, *code),
Self::BadRequest(ref kind, ..) => response::bad_request_code(kind),
Self::Conflict(_) => http::StatusCode::CONFLICT,
_ => http::StatusCode::INTERNAL_SERVER_ERROR,
}
+38 -16
View File
@@ -1,7 +1,13 @@
use bytes::BytesMut;
use http::StatusCode;
use http_body_util::Full;
use ruma::api::{client::uiaa::UiaaResponse, OutgoingResponse};
use ruma::api::{
client::{
error::{ErrorBody, ErrorKind},
uiaa::UiaaResponse,
},
OutgoingResponse,
};
use super::Error;
use crate::error;
@@ -25,7 +31,7 @@ impl From<Error> for UiaaResponse {
return Self::AuthResponse(uiaainfo);
}
let body = ruma::api::client::error::ErrorBody::Standard {
let body = ErrorBody::Standard {
kind: error.kind(),
message: error.message(),
};
@@ -37,10 +43,33 @@ impl From<Error> for UiaaResponse {
}
}
pub(super) fn bad_request_code(kind: &ruma::api::client::error::ErrorKind) -> StatusCode {
use ruma::api::client::error::ErrorKind::*;
pub(super) fn status_code(kind: &ErrorKind, hint: StatusCode) -> StatusCode {
if hint == StatusCode::BAD_REQUEST {
bad_request_code(kind)
} else {
hint
}
}
pub(super) fn bad_request_code(kind: &ErrorKind) -> StatusCode {
use ErrorKind::*;
match kind {
// 429
LimitExceeded {
..
} => StatusCode::TOO_MANY_REQUESTS,
// 413
TooLarge => StatusCode::PAYLOAD_TOO_LARGE,
// 405
Unrecognized => StatusCode::METHOD_NOT_ALLOWED,
// 404
NotFound => StatusCode::NOT_FOUND,
// 403
GuestAccessForbidden
| ThreepidAuthFailed
| UserDeactivated
@@ -52,26 +81,20 @@ pub(super) fn bad_request_code(kind: &ruma::api::client::error::ErrorKind) -> St
..
} => StatusCode::FORBIDDEN,
// 401
UnknownToken {
..
}
| MissingToken
| Unauthorized => StatusCode::UNAUTHORIZED,
LimitExceeded {
..
} => StatusCode::TOO_MANY_REQUESTS,
TooLarge => StatusCode::PAYLOAD_TOO_LARGE,
NotFound | Unrecognized => StatusCode::NOT_FOUND,
// 400
_ => StatusCode::BAD_REQUEST,
}
}
pub(super) fn ruma_error_message(error: &ruma::api::client::error::Error) -> String {
if let ruma::api::client::error::ErrorBody::Standard {
if let ErrorBody::Standard {
message,
..
} = &error.body
@@ -82,7 +105,6 @@ pub(super) fn ruma_error_message(error: &ruma::api::client::error::Error) -> Str
format!("{error}")
}
pub(super) fn ruma_error_kind(e: &ruma::api::client::error::Error) -> &ruma::api::client::error::ErrorKind {
e.error_kind()
.unwrap_or(&ruma::api::client::error::ErrorKind::Unknown)
pub(super) fn ruma_error_kind(e: &ruma::api::client::error::Error) -> &ErrorKind {
e.error_kind().unwrap_or(&ErrorKind::Unknown)
}
+4 -4
View File
@@ -2,14 +2,14 @@ use std::{cmp, time::Duration};
pub use checked_ops::checked_ops;
use crate::{Error, Result};
use crate::{Err, Error, Result};
/// Checked arithmetic expression. Returns a Result<R, Error::Arithmetic>
#[macro_export]
macro_rules! checked {
($($input:tt)*) => {
$crate::utils::math::checked_ops!($($input)*)
.ok_or_else(|| $crate::Error::Arithmetic("operation overflowed or result invalid"))
.ok_or_else(|| $crate::err!(Arithmetic("operation overflowed or result invalid")))
}
}
@@ -21,7 +21,7 @@ macro_rules! validated {
($($input:tt)*) => {
//#[allow(clippy::arithmetic_side_effects)] {
//Some($($input)*)
// .ok_or_else(|| $crate::Error::Arithmetic("this error should never been seen"))
// .ok_or_else(|| $crate::err!(Arithmetic("this error should never been seen")))
//}
//NOTE: remove me when stmt_expr_attributes is stable
@@ -57,7 +57,7 @@ pub fn continue_exponential_backoff(min: Duration, max: Duration, elapsed: Durat
#[allow(clippy::as_conversions)]
pub fn usize_from_f64(val: f64) -> Result<usize, Error> {
if val < 0.0 {
return Err(Error::Arithmetic("Converting negative float to unsigned integer"));
return Err!(Arithmetic("Converting negative float to unsigned integer"));
}
//SAFETY: <https://doc.rust-lang.org/std/primitive.f64.html#method.to_int_unchecked>
+1 -1
View File
@@ -310,7 +310,7 @@ fn set_table_with_shared_cache(
}
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.cache_capacity_modifier;
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
(ents as usize)
+5 -5
View File
@@ -5,7 +5,7 @@ use axum::{
Router,
};
use axum_client_ip::SecureClientIpSource;
use conduit::{Result, Server};
use conduit::{error, Result, Server};
use http::{
header::{self, HeaderName},
HeaderValue, Method, StatusCode,
@@ -149,7 +149,7 @@ fn cors_layer(_server: &Server) -> CorsLayer {
fn body_limit_layer(server: &Server) -> DefaultBodyLimit { DefaultBodyLimit::max(server.config.max_request_size) }
#[allow(clippy::needless_pass_by_value)]
#[tracing::instrument(skip_all)]
#[tracing::instrument(skip_all, name = "panic")]
fn catch_panic(err: Box<dyn Any + Send + 'static>) -> http::Response<http_body_util::Full<bytes::Bytes>> {
conduit_service::services()
.server
@@ -165,17 +165,17 @@ fn catch_panic(err: Box<dyn Any + Send + 'static>) -> http::Response<http_body_u
"Unknown internal server error occurred.".to_owned()
};
error!("{details:#}");
let body = serde_json::json!({
"errcode": "M_UNKNOWN",
"error": "M_UNKNOWN: Internal server error occurred",
"details": details,
})
.to_string();
});
http::Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.header(header::CONTENT_TYPE, "application/json")
.body(http_body_util::Full::from(body))
.body(http_body_util::Full::from(body.to_string()))
.expect("Failed to create response for our panic catcher?")
}
+8 -23
View File
@@ -4,9 +4,8 @@ use axum::{
extract::State,
response::{IntoResponse, Response},
};
use conduit::{debug, debug_error, debug_warn, defer, error, trace, Error, Result, Server};
use conduit::{debug, debug_error, debug_warn, defer, err, error, trace, Result, Server};
use http::{Method, StatusCode, Uri};
use ruma::api::client::error::{Error as RumaError, ErrorBody, ErrorKind};
#[tracing::instrument(skip_all, level = "debug")]
pub(crate) async fn spawn(
@@ -58,33 +57,13 @@ pub(crate) async fn handle(
trace!(active, finished, "leave");
}};
let method = req.method().clone();
let uri = req.uri().clone();
let method = req.method().clone();
let result = next.run(req).await;
handle_result(&method, &uri, result)
}
fn handle_result(method: &Method, uri: &Uri, result: Response) -> Result<Response, StatusCode> {
handle_result_log(method, uri, &result);
match result.status() {
StatusCode::METHOD_NOT_ALLOWED => handle_result_405(method, uri, &result),
_ => Ok(result),
}
}
fn handle_result_405(_method: &Method, _uri: &Uri, result: &Response) -> Result<Response, StatusCode> {
let error = Error::RumaError(RumaError {
status_code: result.status(),
body: ErrorBody::Standard {
kind: ErrorKind::Unrecognized,
message: "M_UNRECOGNIZED: Method not allowed for endpoint".to_owned(),
},
});
Ok(error.into_response())
}
fn handle_result_log(method: &Method, uri: &Uri, result: &Response) {
let status = result.status();
let reason = status.canonical_reason().unwrap_or("Unknown Reason");
let code = status.as_u16();
@@ -97,4 +76,10 @@ fn handle_result_log(method: &Method, uri: &Uri, result: &Response) {
} else {
trace!(method = ?method, uri = ?uri, "{code} {reason}");
}
if status == StatusCode::METHOD_NOT_ALLOWED {
return Ok(err!(Request(Unrecognized("Method Not Allowed"))).into_response());
}
Ok(result)
}
+7 -8
View File
@@ -2,24 +2,23 @@ use std::sync::Arc;
use axum::{response::IntoResponse, routing::get, Router};
use conduit::{Error, Server};
use conduit_service as service;
use http::Uri;
use http::{StatusCode, Uri};
use ruma::api::client::error::ErrorKind;
extern crate conduit_api as api;
extern crate conduit_service as service;
pub(crate) fn build(server: &Arc<Server>) -> Router {
let state = service::services();
let router = Router::new()
let router = Router::<api::State>::new();
api::router::build(router, server)
.route("/", get(it_works))
.fallback(not_found)
.with_state(state);
api::routes::build(router, server)
.with_state(service::services())
}
async fn not_found(_uri: Uri) -> impl IntoResponse {
Error::BadRequest(ErrorKind::Unrecognized, "Unrecognized request")
Error::Request(ErrorKind::Unrecognized, "Not Found".into(), StatusCode::NOT_FOUND)
}
async fn it_works() -> &'static str { "hewwo from conduwuit woof!" }
+2 -2
View File
@@ -127,8 +127,8 @@ async fn fini(server: &Arc<Server>, listener: UnixListener, mut tasks: JoinSet<(
debug!("Waiting for requests to finish...");
while server.metrics.requests_spawn_active.load(Ordering::Relaxed) > 0 {
tokio::select! {
_ = tasks.join_next() => {}
() = sleep(FINI_POLL_INTERVAL) => {}
task = tasks.join_next() => if task.is_none() { break; },
() = sleep(FINI_POLL_INTERVAL) => {},
}
}
+4 -4
View File
@@ -9,7 +9,7 @@ use std::{
};
use async_trait::async_trait;
use conduit::{debug, error, Error, Result};
use conduit::{debug, error, error::default_log, Error, Result};
pub use create::create_admin_room;
pub use grant::make_user_admin;
use loole::{Receiver, Sender};
@@ -239,9 +239,9 @@ async fn respond_to_room(content: RoomMessageEventContent, room_id: &RoomId, use
.build_and_append_pdu(response_pdu, user_id, room_id, &state_lock)
.await
{
if let Err(e) = handle_response_error(e, room_id, user_id, &state_lock).await {
error!("{e}");
}
handle_response_error(e, room_id, user_id, &state_lock)
.await
.unwrap_or_else(default_log);
}
}
+14 -4
View File
@@ -12,6 +12,13 @@ pub(crate) struct Data {
url_previews: Arc<Map>,
}
#[derive(Debug)]
pub(super) struct Metadata {
pub(super) content_disposition: Option<String>,
pub(super) content_type: Option<String>,
pub(super) key: Vec<u8>,
}
impl Data {
pub(super) fn new(db: &Arc<Database>) -> Self {
Self {
@@ -104,9 +111,7 @@ impl Data {
Ok(keys)
}
pub(super) fn search_file_metadata(
&self, mxc: &str, width: u32, height: u32,
) -> Result<(Option<String>, Option<String>, Vec<u8>)> {
pub(super) fn search_file_metadata(&self, mxc: &str, width: u32, height: u32) -> Result<Metadata> {
let mut prefix = mxc.as_bytes().to_vec();
prefix.push(0xFF);
prefix.extend_from_slice(&width.to_be_bytes());
@@ -141,7 +146,12 @@ impl Data {
.map_err(|_| Error::bad_database("Content Disposition in mediaid_file is invalid unicode."))?,
)
};
Ok((content_disposition, content_type, key))
Ok(Metadata {
content_disposition,
content_type,
key,
})
}
/// Gets all the media keys in our database (this includes all the metadata
+33 -183
View File
@@ -1,13 +1,13 @@
mod data;
mod tests;
mod thumbnail;
use std::{collections::HashMap, io::Cursor, num::Saturating as Sat, path::PathBuf, sync::Arc, time::SystemTime};
use std::{collections::HashMap, path::PathBuf, sync::Arc, time::SystemTime};
use async_trait::async_trait;
use base64::{engine::general_purpose, Engine as _};
use conduit::{checked, debug, debug_error, error, utils, Error, Result, Server};
use data::Data;
use image::imageops::FilterType;
use conduit::{debug, debug_error, err, error, utils, Err, Result, Server};
use data::{Data, Metadata};
use ruma::{OwnedMxcUri, OwnedUserId};
use serde::Serialize;
use tokio::{
@@ -20,10 +20,9 @@ use crate::services;
#[derive(Debug)]
pub struct FileMeta {
#[allow(dead_code)]
pub content_disposition: Option<String>,
pub content: Option<Vec<u8>>,
pub content_type: Option<String>,
pub file: Vec<u8>,
pub content_disposition: Option<String>,
}
#[derive(Serialize, Default)]
@@ -101,47 +100,30 @@ impl Service {
Ok(())
} else {
error!("Failed to find any media keys for MXC \"{mxc}\" in our database (MXC does not exist)");
Err(Error::bad_database(
"Failed to find any media keys for the provided MXC in our database (MXC does not exist)",
))
Err!(Database(error!(
"Failed to find any media keys for MXC {mxc:?} in our database."
)))
}
}
/// Uploads or replaces a file thumbnail.
#[allow(clippy::too_many_arguments)]
pub async fn upload_thumbnail(
&self, sender_user: Option<OwnedUserId>, mxc: &str, content_disposition: Option<&str>,
content_type: Option<&str>, width: u32, height: u32, file: &[u8],
) -> Result<()> {
let key = if let Some(user) = sender_user {
self.db
.create_file_metadata(Some(user.as_str()), mxc, width, height, content_disposition, content_type)?
} else {
self.db
.create_file_metadata(None, mxc, width, height, content_disposition, content_type)?
};
//TODO: Dangling metadata in database if creation fails
let mut f = self.create_media_file(&key).await?;
f.write_all(file).await?;
Ok(())
}
/// Downloads a file.
pub async fn get(&self, mxc: &str) -> Result<Option<FileMeta>> {
if let Ok((content_disposition, content_type, key)) = self.db.search_file_metadata(mxc, 0, 0) {
let mut file = Vec::new();
if let Ok(Metadata {
content_disposition,
content_type,
key,
}) = self.db.search_file_metadata(mxc, 0, 0)
{
let mut content = Vec::new();
let path = self.get_media_file(&key);
BufReader::new(fs::File::open(path).await?)
.read_to_end(&mut file)
.read_to_end(&mut content)
.await?;
Ok(Some(FileMeta {
content_disposition,
content: Some(content),
content_type,
file,
content_disposition,
}))
} else {
Ok(None)
@@ -154,23 +136,16 @@ impl Service {
let all_keys = self.db.get_all_media_keys();
let user_duration: SystemTime = match cyborgtime::parse_duration(&time) {
Ok(duration) => {
debug!("Parsed duration: {:?}", duration);
debug!("System time now: {:?}", SystemTime::now());
SystemTime::now().checked_sub(duration).ok_or_else(|| {
Error::bad_database("Duration specified is not valid against the current system time")
})?
},
Err(e) => {
error!("Failed to parse user-specified time duration: {}", e);
return Err(Error::bad_database("Failed to parse user-specified time duration."));
},
Err(e) => return Err!(Database(error!("Failed to parse specified time duration: {e}"))),
Ok(duration) => SystemTime::now()
.checked_sub(duration)
.ok_or(err!(Arithmetic("Duration {duration:?} is too large")))?,
};
let mut remote_mxcs: Vec<String> = vec![];
for key in all_keys {
debug!("Full MXC key from database: {:?}", key);
debug!("Full MXC key from database: {key:?}");
// we need to get the MXC URL from the first part of the key (the first 0xff /
// 255 push). this is all necessary because of conduit using magic keys for
@@ -179,24 +154,19 @@ impl Service {
let mxc = parts
.next()
.map(|bytes| {
utils::string_from_bytes(bytes).map_err(|e| {
error!("Failed to parse MXC unicode bytes from our database: {}", e);
Error::bad_database("Failed to parse MXC unicode bytes from our database")
})
utils::string_from_bytes(bytes)
.map_err(|e| err!(Database(error!("Failed to parse MXC unicode bytes from our database: {e}"))))
})
.transpose()?;
let Some(mxc_s) = mxc else {
return Err(Error::bad_database(
"Parsed MXC URL unicode bytes from database but still is None",
));
return Err!(Database("Parsed MXC URL unicode bytes from database but still is None"));
};
debug!("Parsed MXC key to URL: {}", mxc_s);
debug!("Parsed MXC key to URL: {mxc_s}");
let mxc = OwnedMxcUri::from(mxc_s);
if mxc.server_name() == Ok(services().globals.server_name()) {
debug!("Ignoring local media MXC: {}", mxc);
debug!("Ignoring local media MXC: {mxc}");
// ignore our own MXC URLs as this would be local media.
continue;
}
@@ -215,14 +185,14 @@ impl Service {
},
Err(err) => {
if force {
error!("Could not delete MXC path {:?}: {:?}. Skipping...", path, err);
error!("Could not delete MXC path {path:?}: {err:?}. Skipping...");
continue;
}
return Err(err.into());
},
};
debug!("File created at: {:?}", file_created_at);
debug!("File created at: {file_created_at:?}");
if file_created_at <= user_duration {
debug!("File is within user duration, pushing to list of file paths and keys to delete.");
remote_mxcs.push(mxc.to_string());
@@ -232,15 +202,12 @@ impl Service {
debug!(
"Finished going through all our media in database for eligible keys to delete, checking if these are empty"
);
if remote_mxcs.is_empty() {
return Err(Error::bad_database("Did not found any eligible MXCs to delete."));
return Err!(Database("Did not found any eligible MXCs to delete."));
}
debug!("Deleting media now in the past \"{:?}\".", user_duration);
debug!("Deleting media now in the past {user_duration:?}.");
let mut deletion_count: usize = 0;
for mxc in remote_mxcs {
debug!("Deleting MXC {mxc} from database and filesystem");
self.delete(&mxc).await?;
@@ -250,123 +217,6 @@ impl Service {
Ok(deletion_count)
}
/// Returns width, height of the thumbnail and whether it should be cropped.
/// Returns None when the server should send the original file.
pub fn thumbnail_properties(&self, width: u32, height: u32) -> Option<(u32, u32, bool)> {
match (width, height) {
(0..=32, 0..=32) => Some((32, 32, true)),
(0..=96, 0..=96) => Some((96, 96, true)),
(0..=320, 0..=240) => Some((320, 240, false)),
(0..=640, 0..=480) => Some((640, 480, false)),
(0..=800, 0..=600) => Some((800, 600, false)),
_ => None,
}
}
/// Downloads a file's thumbnail.
///
/// Here's an example on how it works:
///
/// - Client requests an image with width=567, height=567
/// - Server rounds that up to (800, 600), so it doesn't have to save too
/// many thumbnails
/// - Server rounds that up again to (958, 600) to fix the aspect ratio
/// (only for width,height>96)
/// - Server creates the thumbnail and sends it to the user
///
/// For width,height <= 96 the server uses another thumbnailing algorithm
/// which crops the image afterwards.
pub async fn get_thumbnail(&self, mxc: &str, width: u32, height: u32) -> Result<Option<FileMeta>> {
let (width, height, crop) = self
.thumbnail_properties(width, height)
.unwrap_or((0, 0, false)); // 0, 0 because that's the original file
if let Ok((content_disposition, content_type, key)) = self.db.search_file_metadata(mxc, width, height) {
// Using saved thumbnail
let mut file = Vec::new();
let path = self.get_media_file(&key);
fs::File::open(path).await?.read_to_end(&mut file).await?;
Ok(Some(FileMeta {
content_disposition,
content_type,
file: file.clone(),
}))
} else if let Ok((content_disposition, content_type, key)) = self.db.search_file_metadata(mxc, 0, 0) {
// Generate a thumbnail
let mut file = Vec::new();
let path = self.get_media_file(&key);
fs::File::open(path).await?.read_to_end(&mut file).await?;
if let Ok(image) = image::load_from_memory(&file) {
let original_width = image.width();
let original_height = image.height();
if width > original_width || height > original_height {
return Ok(Some(FileMeta {
content_disposition,
content_type,
file: file.clone(),
}));
}
let thumbnail = if crop {
image.resize_to_fill(width, height, FilterType::CatmullRom)
} else {
let (exact_width, exact_height) = {
let ratio = Sat(original_width) * Sat(height);
let nratio = Sat(width) * Sat(original_height);
let use_width = nratio <= ratio;
let intermediate = if use_width {
Sat(original_height) * Sat(checked!(width / original_width)?)
} else {
Sat(original_width) * Sat(checked!(height / original_height)?)
};
if use_width {
(width, intermediate.0)
} else {
(intermediate.0, height)
}
};
image.thumbnail_exact(exact_width, exact_height)
};
let mut thumbnail_bytes = Vec::new();
thumbnail.write_to(&mut Cursor::new(&mut thumbnail_bytes), image::ImageFormat::Png)?;
// Save thumbnail in database so we don't have to generate it again next time
let thumbnail_key = self.db.create_file_metadata(
None,
mxc,
width,
height,
content_disposition.as_deref(),
content_type.as_deref(),
)?;
let mut f = self.create_media_file(&thumbnail_key).await?;
f.write_all(&thumbnail_bytes).await?;
Ok(Some(FileMeta {
content_disposition,
content_type,
file: thumbnail_bytes.clone(),
}))
} else {
// Couldn't parse file to generate thumbnail, send original
Ok(Some(FileMeta {
content_disposition,
content_type,
file: file.clone(),
}))
}
} else {
Ok(None)
}
}
pub async fn get_url_preview(&self, url: &str) -> Option<UrlPreviewData> { self.db.get_url_preview(url) }
/// TODO: use this?
+174
View File
@@ -0,0 +1,174 @@
use std::{cmp, io::Cursor, num::Saturating as Sat};
use conduit::{checked, Result};
use image::{imageops::FilterType, DynamicImage};
use ruma::OwnedUserId;
use tokio::{
fs,
io::{AsyncReadExt, AsyncWriteExt},
};
use super::{data::Metadata, FileMeta};
impl super::Service {
/// Uploads or replaces a file thumbnail.
#[allow(clippy::too_many_arguments)]
pub async fn upload_thumbnail(
&self, sender_user: Option<OwnedUserId>, mxc: &str, content_disposition: Option<&str>,
content_type: Option<&str>, width: u32, height: u32, file: &[u8],
) -> Result<()> {
let key = if let Some(user) = sender_user {
self.db
.create_file_metadata(Some(user.as_str()), mxc, width, height, content_disposition, content_type)?
} else {
self.db
.create_file_metadata(None, mxc, width, height, content_disposition, content_type)?
};
//TODO: Dangling metadata in database if creation fails
let mut f = self.create_media_file(&key).await?;
f.write_all(file).await?;
Ok(())
}
/// Downloads a file's thumbnail.
///
/// Here's an example on how it works:
///
/// - Client requests an image with width=567, height=567
/// - Server rounds that up to (800, 600), so it doesn't have to save too
/// many thumbnails
/// - Server rounds that up again to (958, 600) to fix the aspect ratio
/// (only for width,height>96)
/// - Server creates the thumbnail and sends it to the user
///
/// For width,height <= 96 the server uses another thumbnailing algorithm
/// which crops the image afterwards.
#[tracing::instrument(skip(self), name = "thumbnail", level = "debug")]
pub async fn get_thumbnail(&self, mxc: &str, width: u32, height: u32) -> Result<Option<FileMeta>> {
// 0, 0 because that's the original file
let (width, height, crop) = thumbnail_properties(width, height).unwrap_or((0, 0, false));
if let Ok(metadata) = self.db.search_file_metadata(mxc, width, height) {
self.get_thumbnail_saved(metadata).await
} else if let Ok(metadata) = self.db.search_file_metadata(mxc, 0, 0) {
self.get_thumbnail_generate(mxc, width, height, crop, metadata)
.await
} else {
Ok(None)
}
}
/// Using saved thumbnail
#[tracing::instrument(skip(self), name = "saved", level = "debug")]
async fn get_thumbnail_saved(&self, data: Metadata) -> Result<Option<FileMeta>> {
let mut content = Vec::new();
let path = self.get_media_file(&data.key);
fs::File::open(path)
.await?
.read_to_end(&mut content)
.await?;
Ok(Some(into_filemeta(data, content)))
}
/// Generate a thumbnail
#[tracing::instrument(skip(self), name = "generate", level = "debug")]
async fn get_thumbnail_generate(
&self, mxc: &str, width: u32, height: u32, crop: bool, data: Metadata,
) -> Result<Option<FileMeta>> {
let mut content = Vec::new();
let path = self.get_media_file(&data.key);
fs::File::open(path)
.await?
.read_to_end(&mut content)
.await?;
let Ok(image) = image::load_from_memory(&content) else {
// Couldn't parse file to generate thumbnail, send original
return Ok(Some(into_filemeta(data, content)));
};
if width > image.width() || height > image.height() {
return Ok(Some(into_filemeta(data, content)));
}
let mut thumbnail_bytes = Vec::new();
let thumbnail = thumbnail_generate(&image, width, height, crop)?;
thumbnail.write_to(&mut Cursor::new(&mut thumbnail_bytes), image::ImageFormat::Png)?;
// Save thumbnail in database so we don't have to generate it again next time
let thumbnail_key = self.db.create_file_metadata(
None,
mxc,
width,
height,
data.content_disposition.as_deref(),
data.content_type.as_deref(),
)?;
let mut f = self.create_media_file(&thumbnail_key).await?;
f.write_all(&thumbnail_bytes).await?;
Ok(Some(into_filemeta(data, thumbnail_bytes)))
}
}
fn thumbnail_generate(image: &DynamicImage, width: u32, height: u32, crop: bool) -> Result<DynamicImage> {
let thumbnail = if crop {
image.resize_to_fill(width, height, FilterType::CatmullRom)
} else {
let (exact_width, exact_height) = thumbnail_dimension(image, width, height)?;
image.thumbnail_exact(exact_width, exact_height)
};
Ok(thumbnail)
}
fn thumbnail_dimension(image: &DynamicImage, width: u32, height: u32) -> Result<(u32, u32)> {
let image_width = image.width();
let image_height = image.height();
let width = cmp::min(width, image_width);
let height = cmp::min(height, image_height);
let use_width = Sat(width) * Sat(image_height) < Sat(height) * Sat(image_width);
let x = if use_width {
let dividend = (Sat(height) * Sat(image_width)).0;
checked!(dividend / image_height)?
} else {
width
};
let y = if !use_width {
let dividend = (Sat(width) * Sat(image_height)).0;
checked!(dividend / image_width)?
} else {
height
};
Ok((x, y))
}
/// Returns width, height of the thumbnail and whether it should be cropped.
/// Returns None when the server should send the original file.
fn thumbnail_properties(width: u32, height: u32) -> Option<(u32, u32, bool)> {
match (width, height) {
(0..=32, 0..=32) => Some((32, 32, true)),
(0..=96, 0..=96) => Some((96, 96, true)),
(0..=320, 0..=240) => Some((320, 240, false)),
(0..=640, 0..=480) => Some((640, 480, false)),
(0..=800, 0..=600) => Some((800, 600, false)),
_ => None,
}
}
fn into_filemeta(data: Metadata, content: Vec<u8>) -> FileMeta {
FileMeta {
content: Some(content),
content_type: data.content_type,
content_disposition: data.content_disposition,
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ impl Data {
pub(super) fn new(server: &Arc<Server>, db: &Arc<Database>) -> Self {
let config = &server.config;
let cache_size = f64::from(config.auth_chain_cache_capacity);
let cache_size = usize_from_f64(cache_size * config.conduit_cache_capacity_modifier).expect("valid cache size");
let cache_size = usize_from_f64(cache_size * config.cache_capacity_modifier).expect("valid cache size");
Self {
shorteventid_authchain: db["shorteventid_authchain"].clone(),
auth_chain_cache: Mutex::new(LruCache::new(cache_size)),
+1 -1
View File
@@ -161,7 +161,7 @@ impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
let cache_size = f64::from(config.roomid_spacehierarchy_cache_capacity);
let cache_size = cache_size * config.conduit_cache_capacity_modifier;
let cache_size = cache_size * config.cache_capacity_modifier;
Ok(Arc::new(Self {
roomid_spacehierarchy_cache: Mutex::new(LruCache::new(usize_from_f64(cache_size)?)),
}))
+2 -2
View File
@@ -45,9 +45,9 @@ impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
let server_visibility_cache_capacity =
f64::from(config.server_visibility_cache_capacity) * config.conduit_cache_capacity_modifier;
f64::from(config.server_visibility_cache_capacity) * config.cache_capacity_modifier;
let user_visibility_cache_capacity =
f64::from(config.user_visibility_cache_capacity) * config.conduit_cache_capacity_modifier;
f64::from(config.user_visibility_cache_capacity) * config.cache_capacity_modifier;
Ok(Arc::new(Self {
db: Data::new(args.db),
+1 -1
View File
@@ -55,7 +55,7 @@ pub struct Service {
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
let cache_capacity = f64::from(config.stateinfo_cache_capacity) * config.conduit_cache_capacity_modifier;
let cache_capacity = f64::from(config.stateinfo_cache_capacity) * config.cache_capacity_modifier;
Ok(Arc::new(Self {
db: Data::new(args.db),
stateinfo_cache: StdMutex::new(LruCache::new(usize_from_f64(cache_capacity)?)),
+6 -2
View File
@@ -443,7 +443,9 @@ impl crate::globals::resolver::Resolver {
impl CachedDest {
#[inline]
#[must_use]
pub fn valid(&self) -> bool { self.expire > SystemTime::now() }
pub fn valid(&self) -> bool { true }
//pub fn valid(&self) -> bool { self.expire > SystemTime::now() }
#[must_use]
pub(crate) fn default_expire() -> SystemTime { rand::timepoint_secs(60 * 60 * 18..60 * 60 * 36) }
@@ -452,7 +454,9 @@ impl CachedDest {
impl CachedOverride {
#[inline]
#[must_use]
pub fn valid(&self) -> bool { self.expire > SystemTime::now() }
pub fn valid(&self) -> bool { true }
//pub fn valid(&self) -> bool { self.expire > SystemTime::now() }
#[must_use]
pub(crate) fn default_expire() -> SystemTime { rand::timepoint_secs(60 * 60 * 6..60 * 60 * 12) }
+42 -57
View File
@@ -1,6 +1,6 @@
use std::{collections::BTreeMap, mem::size_of, sync::Arc};
use conduit::{debug_info, utils, warn, Error, Result};
use conduit::{debug_info, err, utils, warn, Err, Error, Result};
use database::{Database, Map};
use ruma::{
api::client::{device::Device, error::ErrorKind, filter::FilterDefinition},
@@ -87,19 +87,19 @@ impl Data {
let mut parts = bytes.split(|&b| b == 0xFF);
let user_bytes = parts
.next()
.ok_or_else(|| Error::bad_database("User ID in token_userdeviceid is invalid."))?;
.ok_or_else(|| err!(Database("User ID in token_userdeviceid is invalid.")))?;
let device_bytes = parts
.next()
.ok_or_else(|| Error::bad_database("Device ID in token_userdeviceid is invalid."))?;
.ok_or_else(|| err!(Database("Device ID in token_userdeviceid is invalid.")))?;
Ok(Some((
UserId::parse(
utils::string_from_bytes(user_bytes)
.map_err(|_| Error::bad_database("User ID in token_userdeviceid is invalid unicode."))?,
.map_err(|e| err!(Database("User ID in token_userdeviceid is invalid unicode. {e}")))?,
)
.map_err(|_| Error::bad_database("User ID in token_userdeviceid is invalid."))?,
.map_err(|e| err!(Database("User ID in token_userdeviceid is invalid. {e}")))?,
utils::string_from_bytes(device_bytes)
.map_err(|_| Error::bad_database("Device ID in token_userdeviceid is invalid."))?,
.map_err(|e| err!(Database("Device ID in token_userdeviceid is invalid. {e}")))?,
)))
})
}
@@ -109,9 +109,9 @@ impl Data {
Box::new(self.userid_password.iter().map(|(bytes, _)| {
UserId::parse(
utils::string_from_bytes(&bytes)
.map_err(|_| Error::bad_database("User ID in userid_password is invalid unicode."))?,
.map_err(|e| err!(Database("User ID in userid_password is invalid unicode. {e}")))?,
)
.map_err(|_| Error::bad_database("User ID in userid_password is invalid."))
.map_err(|e| err!(Database("User ID in userid_password is invalid. {e}")))
}))
}
@@ -165,7 +165,7 @@ impl Data {
.map_or(Ok(None), |bytes| {
Ok(Some(
utils::string_from_bytes(&bytes)
.map_err(|_| Error::bad_database("Displayname in db is invalid."))?,
.map_err(|e| err!(Database("Displayname in db is invalid. {e}")))?,
))
})
}
@@ -188,10 +188,8 @@ impl Data {
self.userid_avatarurl
.get(user_id.as_bytes())?
.map(|bytes| {
let s_bytes = utils::string_from_bytes(&bytes).map_err(|e| {
warn!("Avatar URL in db is invalid: {}", e);
Error::bad_database("Avatar URL in db is invalid.")
})?;
let s_bytes = utils::string_from_bytes(&bytes)
.map_err(|e| err!(Database(warn!("Avatar URL in db is invalid: {e}"))))?;
let mxc_uri: OwnedMxcUri = s_bytes.into();
Ok(mxc_uri)
})
@@ -215,10 +213,7 @@ impl Data {
self.userid_blurhash
.get(user_id.as_bytes())?
.map(|bytes| {
let s = utils::string_from_bytes(&bytes)
.map_err(|_| Error::bad_database("Avatar URL in db is invalid."))?;
Ok(s)
utils::string_from_bytes(&bytes).map_err(|e| err!(Database("Avatar URL in db is invalid. {e}")))
})
.transpose()
}
@@ -314,9 +309,9 @@ impl Data {
bytes
.rsplit(|&b| b == 0xFF)
.next()
.ok_or_else(|| Error::bad_database("UserDevice ID in db is invalid."))?,
.ok_or_else(|| err!(Database("UserDevice ID in db is invalid.")))?,
)
.map_err(|_| Error::bad_database("Device ID in userdeviceid_metadata is invalid."))?
.map_err(|e| err!(Database("Device ID in userdeviceid_metadata is invalid. {e}")))?
.into())
}),
)
@@ -330,13 +325,9 @@ impl Data {
// should not be None, but we shouldn't assert either lol...
if self.userdeviceid_metadata.get(&userdeviceid)?.is_none() {
warn!(
"Called set_token for a non-existent user \"{}\" and/or device ID \"{}\" with no metadata in database",
user_id, device_id
);
return Err(Error::bad_database(
"User does not exist or device ID has no metadata in database.",
));
return Err!(Database(error!(
"User {user_id:?} does not exist or device ID {device_id:?} has no metadata."
)));
}
// Remove old token
@@ -366,14 +357,9 @@ impl Data {
// Only existing devices should be able to call this, but we shouldn't assert
// either...
if self.userdeviceid_metadata.get(&key)?.is_none() {
warn!(
"Called add_one_time_key for a non-existent user \"{}\" and/or device ID \"{}\" with no metadata in \
database",
user_id, device_id
);
return Err(Error::bad_database(
"User does not exist or device ID has no metadata in database.",
));
return Err!(Database(error!(
"User {user_id:?} does not exist or device ID {device_id:?} has no metadata."
)));
}
key.push(0xFF);
@@ -401,7 +387,7 @@ impl Data {
.get(user_id.as_bytes())?
.map_or(Ok(0), |bytes| {
utils::u64_from_bytes(&bytes)
.map_err(|_| Error::bad_database("Count in roomid_lastroomactiveupdate is invalid."))
.map_err(|e| err!(Database("Count in roomid_lastroomactiveupdate is invalid. {e}")))
})
}
@@ -429,11 +415,10 @@ impl Data {
serde_json::from_slice(
key.rsplit(|&b| b == 0xFF)
.next()
.ok_or_else(|| Error::bad_database("OneTimeKeyId in db is invalid."))?,
.ok_or_else(|| err!(Database("OneTimeKeyId in db is invalid.")))?,
)
.map_err(|_| Error::bad_database("OneTimeKeyId in db is invalid."))?,
serde_json::from_slice(&value)
.map_err(|_| Error::bad_database("OneTimeKeys in db are invalid."))?,
.map_err(|e| err!(Database("OneTimeKeyId in db is invalid. {e}")))?,
serde_json::from_slice(&value).map_err(|e| err!(Database("OneTimeKeys in db are invalid. {e}")))?,
))
})
.transpose()
@@ -457,9 +442,9 @@ impl Data {
bytes
.rsplit(|&b| b == 0xFF)
.next()
.ok_or_else(|| Error::bad_database("OneTimeKey ID in db is invalid."))?,
.ok_or_else(|| err!(Database("OneTimeKey ID in db is invalid.")))?,
)
.map_err(|_| Error::bad_database("DeviceKeyId in db is invalid."))?
.map_err(|e| err!(Database("DeviceKeyId in db is invalid. {e}")))?
.algorithm(),
)
}) {
@@ -581,19 +566,19 @@ impl Data {
.get(&key)?
.ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Tried to sign nonexistent key."))?,
)
.map_err(|_| Error::bad_database("key in keyid_key is invalid."))?;
.map_err(|e| err!(Database("key in keyid_key is invalid. {e}")))?;
let signatures = cross_signing_key
.get_mut("signatures")
.ok_or_else(|| Error::bad_database("key in keyid_key has no signatures field."))?
.ok_or_else(|| err!(Database("key in keyid_key has no signatures field.")))?
.as_object_mut()
.ok_or_else(|| Error::bad_database("key in keyid_key has invalid signatures field."))?
.ok_or_else(|| err!(Database("key in keyid_key has invalid signatures field.")))?
.entry(sender_id.to_string())
.or_insert_with(|| serde_json::Map::new().into());
signatures
.as_object_mut()
.ok_or_else(|| Error::bad_database("signatures in keyid_key for a user is invalid."))?
.ok_or_else(|| err!(Database("signatures in keyid_key for a user is invalid.")))?
.insert(signature.0, signature.1.into());
self.keyid_key.insert(
@@ -640,7 +625,7 @@ impl Data {
Error::bad_database("User ID in devicekeychangeid_userid is invalid unicode.")
})?,
)
.map_err(|_| Error::bad_database("User ID in devicekeychangeid_userid is invalid."))
.map_err(|e| err!(Database("User ID in devicekeychangeid_userid is invalid. {e}")))
}),
)
}
@@ -685,7 +670,7 @@ impl Data {
self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| {
Ok(Some(
serde_json::from_slice(&bytes).map_err(|_| Error::bad_database("DeviceKeys in db are invalid."))?,
serde_json::from_slice(&bytes).map_err(|e| err!(Database("DeviceKeys in db are invalid. {e}")))?,
))
})
}
@@ -719,7 +704,7 @@ impl Data {
) -> Result<Option<Raw<CrossSigningKey>>> {
self.keyid_key.get(key)?.map_or(Ok(None), |bytes| {
let mut cross_signing_key = serde_json::from_slice::<serde_json::Value>(&bytes)
.map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?;
.map_err(|e| err!(Database("CrossSigningKey in db is invalid. {e}")))?;
clean_signatures(&mut cross_signing_key, sender_user, user_id, allowed_signatures)?;
Ok(Some(Raw::from_json(
@@ -751,7 +736,7 @@ impl Data {
self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| {
Ok(Some(
serde_json::from_slice(&bytes)
.map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?,
.map_err(|e| err!(Database("CrossSigningKey in db is invalid. {e}")))?,
))
})
})
@@ -792,7 +777,7 @@ impl Data {
for (_, value) in self.todeviceid_events.scan_prefix(prefix) {
events.push(
serde_json::from_slice(&value)
.map_err(|_| Error::bad_database("Event in todeviceid_events is invalid."))?,
.map_err(|e| err!(Database("Event in todeviceid_events is invalid. {e}")))?,
);
}
@@ -816,7 +801,7 @@ impl Data {
Ok::<_, Error>((
key.clone(),
utils::u64_from_bytes(&key[key.len().saturating_sub(size_of::<u64>())..key.len()])
.map_err(|_| Error::bad_database("ToDeviceId has invalid count bytes."))?,
.map_err(|e| err!(Database("ToDeviceId has invalid count bytes. {e}")))?,
))
})
.filter_map(Result::ok)
@@ -877,7 +862,7 @@ impl Data {
.get(user_id.as_bytes())?
.map_or(Ok(None), |bytes| {
utils::u64_from_bytes(&bytes)
.map_err(|_| Error::bad_database("Invalid devicelistversion in db."))
.map_err(|e| err!(Database("Invalid devicelistversion in db. {e}")))
.map(Some)
})
}
@@ -893,7 +878,7 @@ impl Data {
.scan_prefix(key)
.map(|(_, bytes)| {
serde_json::from_slice::<Device>(&bytes)
.map_err(|_| Error::bad_database("Device in userdeviceid_metadata is invalid."))
.map_err(|e| err!(Database("Device in userdeviceid_metadata is invalid. {e}")))
}),
)
}
@@ -920,7 +905,7 @@ impl Data {
let raw = self.userfilterid_filter.get(&key)?;
if let Some(raw) = raw {
serde_json::from_slice(&raw).map_err(|_| Error::bad_database("Invalid filter event in db."))
serde_json::from_slice(&raw).map_err(|e| err!(Database("Invalid filter event in db. {e}")))
} else {
Ok(None)
}
@@ -954,7 +939,7 @@ impl Data {
let expires_at = u64::from_be_bytes(
expires_at_bytes
.try_into()
.map_err(|_| Error::bad_database("expires_at in openid_userid is invalid u64."))?,
.map_err(|e| err!(Database("expires_at in openid_userid is invalid u64. {e}")))?,
);
if expires_at < utils::millis_since_unix_epoch() {
@@ -966,9 +951,9 @@ impl Data {
UserId::parse(
utils::string_from_bytes(user_bytes)
.map_err(|_| Error::bad_database("User ID in openid_userid is invalid unicode."))?,
.map_err(|e| err!(Database("User ID in openid_userid is invalid unicode. {e}")))?,
)
.map_err(|_| Error::bad_database("User ID in openid_userid is invalid."))
.map_err(|e| err!(Database("User ID in openid_userid is invalid. {e}")))
}
}