Compare commits

...

125 Commits

Author SHA1 Message Date
Jason Volk 17a3ed4c56 add admin query resolver commands
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 22:15:54 +00:00
Jason Volk 2dd68d3fa5 add time format string util
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk dc18f89c0b don't cache server name lookups indefinitely (#436)
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk eaf1cf38a5 refactor resolver tuples into structs
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk eeda96d94a inline analysis and symbol reduction; emits smaller than 64 bytes marked inline
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk 1e8b8cce0f even more byte utils optimizations
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk db46d6dd6b optimize millis_since_unix_epoch()
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk 08274150e5 cork database during global counter increment
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk e125af620e impl crate::Service for Service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk 177c9e8bfa add split_once_infallible string util
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk 4f5c6de853 start rand utils suite
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk 25c004f08c remove dead cache
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk f104ced55d remove unnecessary wrapper
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
Jason Volk 0cea64309a move PduEvent from services to core
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-04 21:06:35 +00:00
strawberry 229f2fde7a skip 2 more flakey complement tests still
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-04 11:17:13 -04:00
strawberry 9a0ffd55da skip complement test TestClientSpacesSummary still
too flakey still

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-04 01:55:22 -04:00
renovate[bot] d1b3faf4bd Update Rust crate sd-notify to v0.4.2 2024-07-03 23:02:44 -04:00
strawberry 4014cb4413 document emergency_password
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 23:02:44 -04:00
strawberry b2dbc3bc10 update complement results
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 23:02:38 -04:00
strawberry e2033fb6c1 notify users to update their build scripts if using rocksdb or sha256_media
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 22:12:47 -04:00
strawberry 6b433392a4 slight docs updates
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 22:12:47 -04:00
strawberry 0832c28a40 dedupe some state accessors in various places
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 22:12:47 -04:00
strawberry b0eec60724 add MSC3266 room summary API support
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 22:12:47 -04:00
strawberry 82acc7c0b0 ci: add back ubuntu free disk space
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 22:12:47 -04:00
strawberry c9384e9c78 allow all complement tests again
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 22:12:45 -04:00
strawberry 3502e6ef87 bump conduwuit to 0.4.4
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 11:30:16 -04:00
strawberry deca2c52c6 switch to ruma's X-Matrix parser
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 11:30:16 -04:00
strawberry daa46a0dc4 auto-fix some markdown lints
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 11:30:16 -04:00
strawberry 74791642c1 add markdownlint and run lychee in documentation CI workflow
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 11:30:16 -04:00
strawberry 1a64e42cfe add /openid/request_token and /openid/userinfo routes
heavily changed and improved by me

Co-authored-by: mikoto <avdb@keemail.me>
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-03 11:30:11 -04:00
Jason Volk 5edd391e83 support admin server restart --force
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 7658387a74 remove resolver wrapper; use std mutex
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk be2d1c722b encap dep:chrono in time utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 8cf55c702f split time utils into unit
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 3b9fba233c split bytes utils into unit
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk af81baae44 split string utils into unit
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 52d470058a split hash utils into directory
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk df0328f43f split send txn handler
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 473b29d524 move remaining runtime caches into their respective service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk e1d1dac95e add missing media compat example config
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk a2d25215a3 consolidate key/value types; consistent interface arguments
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 46423cab4f fix counter increment race
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 2e2cf08bb2 optimize increment / increment batch
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk ee64fb149c optimize get w/ zero-copy ref handle
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 0522fe7d92 reimplement iterator from lowlevel
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 6dd6e4bfaf simplify cork interface related
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk a1ced0a56f fix admin query timers not covering full iteration
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jacob Taylor 0171262581 make pduid_pdu/eventid_outlierpdu scale with conduit_cache_capacity_modifier via cache_size(), and fix lint 2024-07-03 06:34:16 +00:00
Jason Volk 972037dcd9 optimize column family handles
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
Jason Volk 0613140130 optimize bytes conversion utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-03 06:34:16 +00:00
morguldir f43c09b05d ci: pin cache-nix-action
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-07-03 06:13:39 +02:00
morguldir b035cd7cbe ci: remove detsys from documentation/build workflow too
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-07-03 04:51:59 +02:00
morguldir b7aa79884d ci: try out cargo caching 2024-07-03 03:39:49 +02:00
morguldir 9c6cc44abb ci: use correct config file
also had to try putting it at the end again
2024-07-03 01:56:14 +02:00
morguldir 9c0d7b1da0 ci: change to cache-nix-action 2024-07-03 01:08:30 +02:00
strawberry ed3a464722 remove uselsss partial_cmp with cmp
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-02 21:21:37 -04:00
strawberry 28ac3790c2 sync upstream spaces/hierarchy federation MR
also had to fix a million clippy lints

fix(spaces): deal with hierarchy recursion
fix(spaces): properly handle max_depth
refactor(spaces): token scheme to prevent clients from modifying max_depth and suggested_only
perf(spaces): use tokens to skip to room to start populating results at
feat(spaces): request hierarchy from servers in via field of child event

Co-authored-by: Matthias Ahouansou <matthias@ahouansou.cz>
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-02 21:20:28 -04:00
strawberry 9115901c66 update complement results
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-02 21:20:24 -04:00
strawberry 652faafe6e bump ruma
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-02 16:46:19 -04:00
strawberry 8deba94a12 update various deps, update rocksdb to v9.3.1
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-02 16:46:13 -04:00
strawberry bb27f21ac1 simplify getting join_authorized_via_users_server for make/send_join, remove unnecessary async
Co-authored-by: Matthias Ahouansou <matthias@ahouansou.cz>
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-02 15:32:40 -04:00
strawberry 339a1fc4e8 only sign /send_join events if restricted join via room version and join_authorised_via_users_server
Co-authored-by: Matthias Ahouansou <matthias@ahouansou.cz>
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-02 15:01:11 -04:00
strawberry 75731671d1 use RoomMemberEventContent for send_join/send_leave
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-02 14:46:53 -04:00
Jason Volk 20aab1792b fix version format regression 3a51e18ce6
Signed-off-by: Jason Volk <jason@zemos.net>
2024-07-01 23:35:04 +00:00
Kimiblock Moe e9f4cd58a9 Bind Mount the old matrix-conduit directory 2024-07-01 17:19:50 -04:00
renovate[bot] 6bae136720 Update Rust crate clap to v4.5.8 2024-07-01 00:18:18 -04:00
renovate[bot] 39a1e994eb chore(deps): update rust crate log to v0.4.22 2024-07-01 00:18:09 -04:00
renovate[bot] c2c36197e9 chore(deps): update nixos/nix docker tag to v2.23.1 2024-07-01 00:17:53 -04:00
Paul Robertson c952db72e7 remove unused CONDUWUIT_CONFIG_FILE variable 2024-07-01 00:16:32 -04:00
Paul Robertson 1ca484f90d explain how to configure conduwuit 2024-07-01 00:16:23 -04:00
Paul Robertson b1150cded9 rename configuruation.md to configuration/examples.md 2024-07-01 00:16:23 -04:00
strawberry 2b35f83089 ci: exclude renovate[bot]
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-01 00:14:16 -04:00
strawberry 792d4aa6ce fix nightly clippy lint
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-01 00:14:16 -04:00
strawberry 6c461025e5 use proper redacts field
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-07-01 00:14:16 -04:00
Jason Volk 9d1db7d171 rename fsck to check
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 2387f7f955 move tester command under debug
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 5805394ca5 add tester timer stub
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 3301cde8e7 add timer around admin command processing
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk b28d216e00 improve debug get-room-state; use RoomOrAliasId
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk f127987c7a add convenience alias resolver to interface
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk fa02d7b7e3 diffuse get_alias_helper into services::rooms::alias
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 96a16190c5 mute dev_release_log_level from --all-features for now
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk d9054f5364 add backreference to layer in capture data struct
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk db288b169e add config option for tokio_console runtime enablement
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk bc50034173 idiomize various expressions
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 20fe84379c rename log::Server to log::Log
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 06f01d384f simplify argon init
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk bd19fac4c5 split tracing init into unit
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 703c275266 split sentry init; add user-agent, trace hooks.
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk c05f00661b use extern namespace in log wrapper macros
convert use tracing statements

Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 0e46b750a0 default to jemalloc when both hardened_malloc and jemalloc enabled.
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 3a51e18ce6 pre-format version strings
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 7638bbc49c keep column list lexically sorted
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 35049c94de simplify db ThreadMode typedef
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 7db8478dc0 hoist iterator modes; group fns
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk df7a1dee15 remove --features=rocksdb from smoketest; use separate target dir
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk dc633100da hoist read_options/write_options instances
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 0f1432f448 improve appservice::Data interface encap
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 30b5ad3870 de-feature rocksdb 2024-06-30 18:02:16 +00:00
Jason Volk cb48e25783 refactor dyn KvTree out of services
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 57acc4f655 fix needless pass by value
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk 875d9e8b07 fix complex types
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:16 +00:00
Jason Volk de21f7442a devirtualize database
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:02:14 +00:00
Jason Volk 7ad7badd60 devirtualize service Data traits
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:01:20 +00:00
Jason Volk a6edaad6fc error enum cleanup
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:01:20 +00:00
Jason Volk fbcdb3860a eliminate dep:rust-rocksdb et al from admin crate
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:01:20 +00:00
Jason Volk 01f4455ceb convert rocksdb errors locally; remove from Error.
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:01:20 +00:00
Jason Volk c1712d4d8b optimize increment
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:01:20 +00:00
Jason Volk 3480074f61 sha256_media integration
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:01:20 +00:00
Jason Volk efbdced535 cleanup migration function a bit
Signed-off-by: Jason Volk <jason@zemos.net>
2024-06-30 18:01:20 +00:00
Paul Robertson 19d8f0b27e dont use any for a single feature check 2024-06-30 10:40:54 -04:00
Paul Robertson 8d5305c769 lock cleanup 2024-06-30 10:40:35 -04:00
Paul Robertson 73b85372d6 drop parking_lot feature 2024-06-29 11:20:48 -04:00
Paul Robertson 5e6b9ec1cf drop thread_local feature 2024-06-29 11:20:48 -04:00
Paul Robertson e24b7d2f3e drop sqlite from docs 2024-06-29 11:20:48 -04:00
Paul Robertson c61258fa0d drop rusqlite dependency 2024-06-29 11:20:48 -04:00
Paul Robertson 65177d237a drop the sqlite feature from core 2024-06-29 11:20:48 -04:00
Paul Robertson 325f1c0bd2 drop the sqlite feature from database 2024-06-29 11:20:45 -04:00
Paul Robertson 68f1b4789a drop the sqlite feature from main 2024-06-29 11:05:33 -04:00
Paul Robertson 624cd2acfa remove sqlite code 2024-06-29 11:05:33 -04:00
morguldir fb758f5f4b chore(deps): bump Cargo.lock (subtle crate was yanked) 2024-06-27 17:41:13 -04:00
morguldir 5d138a7e5e ci: skip development.md file when running lychee 2024-06-27 17:41:13 -04:00
morguldir 563618cc9e ci: free disk space before starting tests 2024-06-27 17:41:13 -04:00
morguldir 0a28d80cf2 ci: try another upstream cache
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-06-27 17:41:13 -04:00
Integral 6f9d7b5667 docs: fix broken link to development.md 2024-06-23 12:20:53 -04:00
218 changed files with 6493 additions and 6118 deletions
+6 -1
View File
@@ -11,5 +11,10 @@ indent_style = space
insert_final_newline = true
max_line_length = 120
[*.{md,txt}]
indent_style = space
indent_size = 4
max_line_length = 80
[*.nix]
indent_size = 2
indent_size = 2
+52 -28
View File
@@ -16,6 +16,7 @@ on:
- 'docker/**'
branches:
- main
- change-ci-cache
tags:
- '*'
# Allows you to run this workflow manually from the Actions tab
@@ -49,6 +50,9 @@ jobs:
name: Test
runs-on: ubuntu-latest
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
- name: Sync repository
uses: actions/checkout@v4
@@ -64,13 +68,7 @@ jobs:
exit 1
fi
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
with:
diagnostic-endpoint: ""
extra-conf: |
experimental-features = nix-command flakes
accept-flake-config = true
- uses: nixbuild/nix-quick-install-action@v28
- name: Enable Cachix binary cache
run: |
@@ -78,15 +76,30 @@ jobs:
cachix use crane
cachix use nix-community
- name: Configure Magic Nix Cache
uses: DeterminateSystems/magic-nix-cache-action@main
- name: Restore and cache Nix store
uses: nix-community/cache-nix-action@v5.1.0
with:
diagnostic-endpoint: ""
upstream-cache: "https://attic.kennel.juneis.dog/conduwuit"
# restore and save a cache using this key
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/.lock') }}
# if there's no cache hit, restore a cache by this prefix
restore-prefixes-first-match: nix-${{ runner.os }}-
# collect garbage until Nix store size (in bytes) is at most this number
# before trying to save a new cache
gc-max-store-size-linux: 2073741824
# do purge caches
purge: true
# purge all versions of the cache
purge-prefixes: nix-${{ runner.os }}-
# created more than this number of seconds ago relative to the start of the `Post Restore` phase
purge-last-accessed: 86400
# except the version with the `primary-key`, if it exists
purge-primary-key: never
# always save the cache
save-always: true
- name: Apply Nix binary cache configuration
run: |
sudo tee -a /etc/nix/nix.conf > /dev/null <<EOF
sudo tee -a "${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf" > /dev/null <<EOF
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=
EOF
@@ -94,7 +107,7 @@ jobs:
- name: Use alternative Nix binary caches if specified
if: ${{ (env.ATTIC_ENDPOINT != '') && (env.ATTIC_PUBLIC_KEY != '') }}
run: |
sudo tee -a /etc/nix/nix.conf > /dev/null <<EOF
sudo tee -a "${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf" > /dev/null <<EOF
extra-substituters = ${{ env.ATTIC_ENDPOINT }}
extra-trusted-public-keys = ${{ env.ATTIC_PUBLIC_KEY }}
EOF
@@ -110,6 +123,8 @@ jobs:
run: |
bin/nix-build-and-cache ci
- uses: Swatinem/rust-cache@v2
- name: Run CI tests
run: |
direnv exec . engage > >(tee -a test_output.log)
@@ -178,29 +193,38 @@ jobs:
- name: Sync repository
uses: actions/checkout@v4
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
with:
diagnostic-endpoint: ""
extra-conf: |
experimental-features = nix-command flakes
accept-flake-config = true
- uses: nixbuild/nix-quick-install-action@v28
- name: Install and enable Cachix binary cache
- name: Enable Cachix binary cache
run: |
nix profile install nixpkgs#cachix
cachix use crane
cachix use nix-community
- name: Configure Magic Nix Cache
uses: DeterminateSystems/magic-nix-cache-action@main
- name: Restore and cache Nix store
uses: nix-community/cache-nix-action@v5.1.0
with:
diagnostic-endpoint: ""
upstream-cache: "https://attic.kennel.juneis.dog/conduwuit"
# restore and save a cache using this key
primary-key: nix-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('**/*.nix', '**/.lock') }}
# if there's no cache hit, restore a cache by this prefix
restore-prefixes-first-match: nix-${{ runner.os }}-
# collect garbage until Nix store size (in bytes) is at most this number
# before trying to save a new cache
gc-max-store-size-linux: 2073741824
# do purge caches
purge: true
# purge all versions of the cache
purge-prefixes: nix-${{ runner.os }}-
# created more than this number of seconds ago relative to the start of the `Post Restore` phase
purge-last-accessed: 86400
# except the version with the `primary-key`, if it exists
purge-primary-key: never
# always save the cache
save-always: true
- name: Apply Nix binary cache configuration
run: |
sudo tee -a /etc/nix/nix.conf > /dev/null <<EOF
sudo tee -a "${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf" > /dev/null <<EOF
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=
EOF
@@ -208,7 +232,7 @@ jobs:
- name: Use alternative Nix binary caches if specified
if: ${{ (env.ATTIC_ENDPOINT != '') && (env.ATTIC_PUBLIC_KEY != '') }}
run: |
sudo tee -a /etc/nix/nix.conf > /dev/null <<EOF
sudo tee -a "${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf" > /dev/null <<EOF
extra-substituters = ${{ env.ATTIC_ENDPOINT }}
extra-trusted-public-keys = ${{ env.ATTIC_PUBLIC_KEY }}
EOF
@@ -267,7 +291,7 @@ jobs:
name: Docker publish
runs-on: ubuntu-latest
needs: build
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' || (github.event.pull_request.draft != true)) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && github.event.pull_request.user.login != 'renovate'
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' || (github.event.pull_request.draft != true)) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && github.event.pull_request.user.login != 'renovate[bot]'
env:
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
+28 -14
View File
@@ -51,13 +51,7 @@ jobs:
if: github.event_name != 'pull_request'
uses: actions/configure-pages@v5
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
with:
diagnostic-endpoint: ""
extra-conf: |
experimental-features = nix-command flakes
accept-flake-config = true
- uses: nixbuild/nix-quick-install-action@v28
- name: Enable Cachix binary cache
run: |
@@ -65,23 +59,38 @@ jobs:
cachix use crane
cachix use nix-community
- name: Configure Magic Nix Cache
uses: DeterminateSystems/magic-nix-cache-action@main
- name: Restore and cache Nix store
uses: nix-community/cache-nix-action@v5.1.0
with:
diagnostic-endpoint: ""
upstream-cache: "https://attic.kennel.juneis.dog/conduwuit"
# restore and save a cache using this key
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/.lock') }}
# if there's no cache hit, restore a cache by this prefix
restore-prefixes-first-match: nix-${{ runner.os }}-
# collect garbage until Nix store size (in bytes) is at most this number
# before trying to save a new cache
gc-max-store-size-linux: 2073741824
# do purge caches
purge: true
# purge all versions of the cache
purge-prefixes: nix-${{ runner.os }}-
# created more than this number of seconds ago relative to the start of the `Post Restore` phase
purge-last-accessed: 86400
# except the version with the `primary-key`, if it exists
purge-primary-key: never
# always save the cache
save-always: true
- name: Apply Nix binary cache configuration
run: |
sudo tee -a /etc/nix/nix.conf > /dev/null <<EOF
sudo tee -a "${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf" > /dev/null <<EOF
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/QmAvQd7HBSm21Wkconduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTEcache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
EOF
- name: Use alternative Nix binary caches if specified
if: ${{ (env.ATTIC_ENDPOINT != '') && (env.ATTIC_PUBLIC_KEY != '') }}
run: |
sudo tee -a /etc/nix/nix.conf > /dev/null <<EOF
sudo tee -a "${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf" > /dev/null <<EOF
extra-substituters = ${{ env.ATTIC_ENDPOINT }}
extra-trusted-public-keys = ${{ env.ATTIC_PUBLIC_KEY }}
EOF
@@ -97,6 +106,11 @@ jobs:
run: |
bin/nix-build-and-cache ci
- name: Run lychee and markdownlint
run: |
direnv exec . engage just lints lychee
direnv exec . engage just lints markdownlint
- name: Build documentation (book)
run: |
./bin/nix-build-and-cache just .#book
+2 -2
View File
@@ -58,7 +58,7 @@ before_script:
ci:
stage: ci
image: nixos/nix:2.23.0
image: nixos/nix:2.23.1
script:
# Cache CI dependencies
- ./bin/nix-build-and-cache ci
@@ -83,7 +83,7 @@ ci:
artifacts:
stage: artifacts
image: nixos/nix:2.23.0
image: nixos/nix:2.23.1
script:
- ./bin/nix-build-and-cache just .#static-x86_64-unknown-linux-musl
- cp result/bin/conduit x86_64-unknown-linux-musl
+1
View File
@@ -0,0 +1 @@
.gitignore
+1 -2
View File
@@ -61,7 +61,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement over email at
strawberry@puppygock.gay or over Matrix at @strawberry:puppygock.gay.
<strawberry@puppygock.gay> or over Matrix at @strawberry:puppygock.gay.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
@@ -131,4 +131,3 @@ For answers to common questions about this code of conduct, see the FAQ at
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
+4 -1
View File
@@ -1,6 +1,6 @@
# Contributing guide
This page is for about contributing to conduwuit. The [development](docs/development.md) page may be of interest for you as well.
This page is for about contributing to conduwuit. The [development](development.md) page may be of interest for you as well.
If you would like to work on an [issue][issues] that is not assigned, preferably ask in the Matrix room first at [#conduwuit:puppygock.gay][conduwuit-matrix], and comment on it.
@@ -19,6 +19,7 @@ To test, format, lint, etc that CI would do, install engage, allow the `.envrc`
All of the tasks are defined at the [engage.toml][engage.toml] file. You can view all of them neatly by running `engage list`
If you would like to run only a specific engage task group, use `just`:
- `engage just <group>`
- Example: `engage just lints`
@@ -37,6 +38,7 @@ The following binaries are used in [`engage.toml`][engage.toml]:
- [`cargo-audit`][cargo-audit]
- [`cargo-deb`][cargo-deb]
- [`lychee`][lychee]
- [`markdownlint-cli`][markdownlint-cli]
### Matrix tests
@@ -86,6 +88,7 @@ By sending a pull request or patch, you are agreeing that your changes are allow
[sytest]: https://github.com/matrix-org/sytest/
[cargo-deb]: https://github.com/kornelski/cargo-deb
[lychee]: https://github.com/lycheeverse/lychee
[markdownlint-cli]: https://github.com/igorshubovych/markdownlint-cli
[cargo-audit]: https://github.com/RustSec/rustsec/tree/main/cargo-audit
[direnv]: https://direnv.net/
[mdbook]: https://rust-lang.github.io/mdBook/
Generated
+136 -192
View File
@@ -17,18 +17,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
@@ -130,7 +118,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -141,7 +129,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -206,7 +194,7 @@ dependencies = [
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.3.1",
"hyper 1.4.0",
"hyper-util",
"itoa",
"matchit",
@@ -310,7 +298,7 @@ dependencies = [
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.3.1",
"hyper 1.4.0",
"hyper-util",
"pin-project-lite",
"rustls 0.21.12",
@@ -378,7 +366,7 @@ version = "0.69.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"cexpr",
"clang-sys",
"itertools 0.12.1",
@@ -389,7 +377,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -400,9 +388,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "blake2"
@@ -486,9 +474,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.99"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490"
dependencies = [
"jobserver",
"libc",
@@ -538,9 +526,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.7"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d"
dependencies = [
"clap_builder",
"clap_derive",
@@ -548,9 +536,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.7"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708"
dependencies = [
"anstyle",
"clap_lex",
@@ -558,14 +546,14 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.5"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -582,7 +570,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "conduit"
version = "0.4.3"
version = "0.4.4"
dependencies = [
"clap",
"conduit_admin",
@@ -610,7 +598,7 @@ dependencies = [
[[package]]
name = "conduit_admin"
version = "0.4.3"
version = "0.4.4"
dependencies = [
"clap",
"conduit_api",
@@ -622,7 +610,6 @@ dependencies = [
"loole",
"regex",
"ruma",
"rust-rocksdb-uwu",
"serde",
"serde_json",
"serde_yaml",
@@ -633,7 +620,7 @@ dependencies = [
[[package]]
name = "conduit_api"
version = "0.4.3"
version = "0.4.4"
dependencies = [
"axum 0.7.5",
"axum-client-ip",
@@ -646,7 +633,7 @@ dependencies = [
"futures-util",
"hmac",
"http 1.1.0",
"hyper 1.3.1",
"hyper 1.4.0",
"image",
"ipaddress",
"jsonwebtoken",
@@ -666,11 +653,12 @@ dependencies = [
[[package]]
name = "conduit_core"
version = "0.4.3"
version = "0.4.4"
dependencies = [
"argon2",
"axum 0.7.5",
"bytes",
"chrono",
"either",
"figment",
"hardened_malloc-rs",
@@ -682,20 +670,16 @@ dependencies = [
"libloading",
"log",
"nix",
"parking_lot",
"rand",
"regex",
"reqwest",
"ring",
"ruma",
"rusqlite",
"rust-rocksdb-uwu",
"sanitize-filename",
"serde",
"serde_json",
"serde_regex",
"thiserror",
"thread_local",
"tikv-jemalloc-ctl",
"tikv-jemalloc-sys",
"tikv-jemallocator",
@@ -708,24 +692,19 @@ dependencies = [
[[package]]
name = "conduit_database"
version = "0.4.3"
version = "0.4.4"
dependencies = [
"chrono",
"conduit_core",
"log",
"lru-cache",
"parking_lot",
"ruma",
"rusqlite",
"rust-rocksdb-uwu",
"thread_local",
"tokio",
"tracing",
]
[[package]]
name = "conduit_router"
version = "0.4.3"
version = "0.4.4"
dependencies = [
"axum 0.7.5",
"axum-client-ip",
@@ -740,7 +719,7 @@ dependencies = [
"conduit_service",
"http 1.1.0",
"http-body-util",
"hyper 1.3.1",
"hyper 1.4.0",
"hyper-util",
"log",
"regex",
@@ -758,7 +737,7 @@ dependencies = [
[[package]]
name = "conduit_service"
version = "0.4.3"
version = "0.4.4"
dependencies = [
"async-trait",
"base64 0.22.1",
@@ -780,7 +759,7 @@ dependencies = [
"regex",
"reqwest",
"ruma",
"ruma-identifiers-validation",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0)",
"rustyline-async",
"serde",
"serde_json",
@@ -973,7 +952,7 @@ version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"crossterm_winapi",
"futures-core",
"libc",
@@ -1027,7 +1006,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -1115,9 +1094,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.12.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
dependencies = [
"serde",
]
@@ -1131,7 +1110,7 @@ dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -1140,18 +1119,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fallible-iterator"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "fdeflate"
version = "0.3.4"
@@ -1279,7 +1246,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -1411,18 +1378,6 @@ name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
]
[[package]]
name = "hashlink"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
dependencies = [
"hashbrown 0.14.5",
]
[[package]]
name = "hdrhistogram"
@@ -1572,7 +1527,7 @@ dependencies = [
"markup5ever",
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -1597,6 +1552,15 @@ dependencies = [
"itoa",
]
[[package]]
name = "http-auth"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "643c9bbf6a4ea8a656d6b4cd53d34f79e3f841ad5203c1a55fb7d761923bc255"
dependencies = [
"memchr",
]
[[package]]
name = "http-body"
version = "0.4.6"
@@ -1675,9 +1639,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.3.1"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d"
checksum = "c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc"
dependencies = [
"bytes",
"futures-channel",
@@ -1702,7 +1666,7 @@ checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
dependencies = [
"futures-util",
"http 1.1.0",
"hyper 1.3.1",
"hyper 1.4.0",
"hyper-util",
"rustls 0.23.10",
"rustls-native-certs",
@@ -1727,16 +1691,16 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56"
checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"hyper 1.3.1",
"hyper 1.4.0",
"pin-project-lite",
"socket2",
"tokio",
@@ -1972,7 +1936,7 @@ dependencies = [
"proc-macro2",
"quote",
"regex",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -1995,24 +1959,14 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libloading"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
dependencies = [
"cfg-if",
"windows-targets 0.52.5",
]
[[package]]
name = "libsqlite3-sys"
version = "0.28.0"
source = "git+https://github.com/rusqlite/rusqlite?rev=e00b626e2b1c67347d789fb7f600281705c89381#e00b626e2b1c67347d789fb7f600281705c89381"
dependencies = [
"cc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "libz-sys"
version = "1.1.18"
@@ -2042,9 +1996,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.21"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "loole"
@@ -2191,7 +2145,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases",
"libc",
@@ -2239,9 +2193,9 @@ dependencies = [
[[package]]
name = "num-bigint"
version = "0.4.5"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
@@ -2314,9 +2268,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.36.0"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434"
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
dependencies = [
"memchr",
]
@@ -2388,7 +2342,7 @@ dependencies = [
"glob",
"once_cell",
"opentelemetry",
"ordered-float 4.2.0",
"ordered-float 4.2.1",
"percent-encoding",
"rand",
"thiserror",
@@ -2407,9 +2361,9 @@ dependencies = [
[[package]]
name = "ordered-float"
version = "4.2.0"
version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e"
checksum = "19ff2cf528c6c03d9ed653d6c4ce1dc0582dc4af309790ad92f07c1cd551b0be"
dependencies = [
"num-traits",
]
@@ -2491,7 +2445,7 @@ dependencies = [
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -2584,7 +2538,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -2672,7 +2626,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
"version_check",
"yansi",
]
@@ -2697,7 +2651,7 @@ dependencies = [
"itertools 0.12.1",
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -2711,11 +2665,11 @@ dependencies = [
[[package]]
name = "pulldown-cmark"
version = "0.10.3"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
checksum = "8746739f11d39ce5ad5c2520a9b75285310dbfe78c541ccf832d38615765aec0"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"memchr",
"pulldown-cmark-escape",
"unicase",
@@ -2723,9 +2677,9 @@ dependencies = [
[[package]]
name = "pulldown-cmark-escape"
version = "0.10.1"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3"
checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
[[package]]
name = "quick-error"
@@ -2825,7 +2779,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
]
[[package]]
@@ -2889,7 +2843,7 @@ dependencies = [
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.3.1",
"hyper 1.4.0",
"hyper-rustls",
"hyper-util",
"ipnet",
@@ -2949,7 +2903,7 @@ dependencies = [
[[package]]
name = "ruma"
version = "0.10.1"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"assign",
"js_int",
@@ -2961,6 +2915,7 @@ dependencies = [
"ruma-federation-api",
"ruma-identity-service-api",
"ruma-push-gateway-api",
"ruma-server-util",
"ruma-signatures",
"ruma-state-res",
"web-time 1.1.0",
@@ -2969,7 +2924,7 @@ dependencies = [
[[package]]
name = "ruma-appservice-api"
version = "0.10.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"js_int",
"ruma-common",
@@ -2981,7 +2936,7 @@ dependencies = [
[[package]]
name = "ruma-client-api"
version = "0.18.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"as_variant",
"assign",
@@ -3004,7 +2959,7 @@ dependencies = [
[[package]]
name = "ruma-common"
version = "0.13.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"as_variant",
"base64 0.22.1",
@@ -3017,7 +2972,7 @@ dependencies = [
"percent-encoding",
"rand",
"regex",
"ruma-identifiers-validation",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-macros",
"serde",
"serde_html_form",
@@ -3034,7 +2989,7 @@ dependencies = [
[[package]]
name = "ruma-events"
version = "0.28.1"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"as_variant",
"indexmap 2.2.6",
@@ -3044,7 +2999,7 @@ dependencies = [
"pulldown-cmark",
"regex",
"ruma-common",
"ruma-identifiers-validation",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-macros",
"serde",
"serde_json",
@@ -3057,7 +3012,7 @@ dependencies = [
[[package]]
name = "ruma-federation-api"
version = "0.9.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"js_int",
"ruma-common",
@@ -3066,6 +3021,15 @@ dependencies = [
"serde_json",
]
[[package]]
name = "ruma-identifiers-validation"
version = "0.9.5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"js_int",
"thiserror",
]
[[package]]
name = "ruma-identifiers-validation"
version = "0.9.5"
@@ -3078,7 +3042,7 @@ dependencies = [
[[package]]
name = "ruma-identity-service-api"
version = "0.9.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"js_int",
"ruma-common",
@@ -3088,22 +3052,22 @@ dependencies = [
[[package]]
name = "ruma-macros"
version = "0.13.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"once_cell",
"proc-macro-crate",
"proc-macro2",
"quote",
"ruma-identifiers-validation",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"serde",
"syn 2.0.67",
"syn 2.0.68",
"toml",
]
[[package]]
name = "ruma-push-gateway-api"
version = "0.9.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"js_int",
"ruma-common",
@@ -3112,10 +3076,23 @@ dependencies = [
"serde_json",
]
[[package]]
name = "ruma-server-util"
version = "0.3.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"headers",
"http 1.1.0",
"http-auth",
"ruma-common",
"thiserror",
"tracing",
]
[[package]]
name = "ruma-signatures"
version = "0.15.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"base64 0.22.1",
"ed25519-dalek",
@@ -3131,7 +3108,7 @@ dependencies = [
[[package]]
name = "ruma-state-res"
version = "0.11.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
dependencies = [
"itertools 0.12.1",
"js_int",
@@ -3143,23 +3120,10 @@ dependencies = [
"tracing",
]
[[package]]
name = "rusqlite"
version = "0.31.0"
source = "git+https://github.com/rusqlite/rusqlite?rev=e00b626e2b1c67347d789fb7f600281705c89381#e00b626e2b1c67347d789fb7f600281705c89381"
dependencies = [
"bitflags 2.5.0",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"smallvec",
]
[[package]]
name = "rust-librocksdb-sys"
version = "0.22.0+9.2.1"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=e9e1cb5ba92a44ea225fe8d13b31aa23621b9035#e9e1cb5ba92a44ea225fe8d13b31aa23621b9035"
version = "0.23.0+9.3.1"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=b4887edfb84771336930855727390edec07d63fa#b4887edfb84771336930855727390edec07d63fa"
dependencies = [
"bindgen",
"bzip2-sys",
@@ -3175,8 +3139,8 @@ dependencies = [
[[package]]
name = "rust-rocksdb"
version = "0.26.0"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=e9e1cb5ba92a44ea225fe8d13b31aa23621b9035#e9e1cb5ba92a44ea225fe8d13b31aa23621b9035"
version = "0.27.0"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=b4887edfb84771336930855727390edec07d63fa#b4887edfb84771336930855727390edec07d63fa"
dependencies = [
"libc",
"rust-librocksdb-sys",
@@ -3366,9 +3330,9 @@ dependencies = [
[[package]]
name = "sd-notify"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "621e3680f3e07db4c9c2c3fb07c6223ab2fab2e54bd3c04c3ae037990f428c32"
checksum = "4646d6f919800cd25c50edb49438a1381e2cd4833c027e75e8897981c50b8b5e"
[[package]]
name = "security-framework"
@@ -3376,7 +3340,7 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"core-foundation",
"core-foundation-sys",
"libc",
@@ -3551,7 +3515,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -3569,9 +3533,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.117"
version = "1.0.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
dependencies = [
"itoa",
"ryu",
@@ -3827,9 +3791,9 @@ dependencies = [
[[package]]
name = "subtle"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
@@ -3844,9 +3808,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.67"
version = "2.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90"
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
dependencies = [
"proc-macro2",
"quote",
@@ -3919,7 +3883,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -4018,9 +3982,9 @@ dependencies = [
[[package]]
name = "tinyvec"
version = "1.6.0"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82"
dependencies = [
"tinyvec_macros",
]
@@ -4068,7 +4032,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -4238,7 +4202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
dependencies = [
"async-compression",
"bitflags 2.5.0",
"bitflags 2.6.0",
"bytes",
"futures-core",
"futures-util",
@@ -4284,7 +4248,7 @@ source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
]
[[package]]
@@ -4493,9 +4457,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "uuid"
version = "1.8.0"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439"
dependencies = [
"getrandom",
"serde",
@@ -4555,7 +4519,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
"wasm-bindgen-shared",
]
@@ -4589,7 +4553,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
"syn 2.0.68",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -4904,26 +4868,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "zerocopy"
version = "0.7.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.67",
]
[[package]]
name = "zeroize"
version = "1.8.1"
+8 -20
View File
@@ -20,7 +20,7 @@ license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/girlbossceo/conduwuit"
rust-version = "1.77.0"
version = "0.4.3"
version = "0.4.4"
[workspace.metadata.crane]
name = "conduit"
@@ -117,7 +117,7 @@ version = "1.0.203"
features = ["rc"]
[workspace.dependencies.serde_json]
version = "1.0.117"
version = "1.0.120"
features = ["raw_value"]
# Used for appservice registration files
@@ -208,11 +208,11 @@ features = ["serde"]
# standard date and time tools
[workspace.dependencies.chrono]
version = "0.4.38"
features = ["alloc"]
features = ["alloc", "std"]
default-features = false
[workspace.dependencies.hyper]
version = "1.3.1"
version = "1.4.0"
features = [
"server",
"http1",
@@ -220,7 +220,7 @@ features = [
]
[workspace.dependencies.hyper-util]
version = "0.1.5"
version = "0.1.6"
features = [
"client",
"server-auto",
@@ -274,7 +274,7 @@ version = "0.1.2"
[workspace.dependencies.ruma]
git = "https://github.com/girlbossceo/ruwuma"
#branch = "conduwuit-changes"
rev = "fd686e77950680462377c9105dfb4136dd49c7a0"
rev = "c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
features = [
"compat",
"rand",
@@ -284,6 +284,7 @@ features = [
"markdown",
"push-gateway-api-c",
"state-res",
"server-util",
"unstable-exhaustive-types",
"ring-compat",
"unstable-unspecified",
@@ -293,6 +294,7 @@ features = [
"unstable-msc2870",
"unstable-msc3026",
"unstable-msc3061",
"unstable-msc3266",
"unstable-msc3575",
"unstable-msc4121",
"unstable-msc4125",
@@ -378,20 +380,6 @@ version = "0.5.4"
default-features = false
features = ["use_std"]
[workspace.dependencies.rusqlite]
git = "https://github.com/rusqlite/rusqlite"
#branch = "master"
rev = "e00b626e2b1c67347d789fb7f600281705c89381"
features = ["bundled"]
# used only by rusqlite
[workspace.dependencies.parking_lot]
version = "0.12.3"
# used only by rusqlite
[workspace.dependencies.thread_local]
version = "1.1.8"
[workspace.dependencies.tokio-metrics]
version = "0.3.1"
default-features = false
+1
View File
@@ -43,6 +43,7 @@ from time to time.
#### Contact
If you run into any question, feel free to
- Ask us in `#conduwuit:puppygock.gay` on Matrix
- [Open an issue on GitHub](https://github.com/girlbossceo/conduwuit/issues/new)
+2
View File
@@ -45,6 +45,8 @@ RuntimeDirectory=conduwuit
RuntimeDirectoryMode=0750
Environment="CONDUWUIT_CONFIG=/etc/conduwuit/conduwuit.toml"
BindPaths=/var/lib/private/conduwuit:/var/lib/matrix-conduit
BindPaths=/var/lib/private/conduwuit:/var/lib/private/matrix-conduit
ExecStart=/usr/bin/conduwuit
Restart=on-failure
+1 -1
View File
@@ -21,7 +21,7 @@ OCI_IMAGE="complement-conduit:main"
# Complement itself induced based on various open issues)
#
# According to Go docs, these are separated by forward slashes and not pipes (why)
SKIPPED_COMPLEMENT_TESTS='-skip=TestJumpToDateEndpoint.*|TestJoinFederatedRoomFromApplicationServiceBridgeUser.*|TestFederationRoomsInvite.*|TestClientSpacesSummary.*'
SKIPPED_COMPLEMENT_TESTS='-skip=TestClientSpacesSummary.*|TestJoinFederatedRoomFromApplicationServiceBridgeUser.*|TestJumpToDateEndpoint.*'
toplevel="$(git rev-parse --show-toplevel)"
+37 -3
View File
@@ -64,9 +64,7 @@
# Note: this was previously "/var/lib/matrix-conduit"
database_path = "/var/lib/conduwuit"
# Database backend: Only rocksdb and sqlite are supported. Please note that sqlite
# will perform significantly worse than rocksdb as it is not intended to be used the
# way it is by conduwuit. sqlite only exists for historical reasons.
# Database backend: Only rocksdb is supported.
database_backend = "rocksdb"
@@ -373,6 +371,42 @@ allow_profile_lookup_federation_requests = true
# If 'tracing_flame' is enabled, set the path to write the generated profile.
# tracing_flame_output_path = "./tracing.folded"
# Enable the tokio-console. This option is only relevant to developers.
# See: docs/development.md#debugging-with-tokio-console for more information.
#tokio_console = false
# Enable backward-compatibility with Conduit's media directory by creating symlinks of media. This
# option is only necessary if you plan on using Conduit again. Otherwise setting this to false
# reduces filesystem clutter and overhead for managing these symlinks in the directory.
#
# Enabled by default.
#media_compat_file_link = true
# Checks consistency of the media directory at startup:
# 1. When `media_compat_file_link` is enbled, this check will upgrade media when switching back
# and forth between Conduit and Conduwuit. Both options must be enabled to handle this.
# 2. When media is deleted from the directory, this check will also delete its database entry.
#
# If none of these checks apply to your use cases, and your media directory is significantly large
# setting this to false may reduce startup time.
#
# Enabled by default.
#media_statup_check = true
# OpenID token expiration/TTL in seconds
#
# These are the OpenID tokens that are primarily used for Matrix account integrations, *not* OIDC/OpenID Connect/etc
#
# Defaults to 3600 (1 hour)
#openid_token_ttl = 3600
# Emergency password feature. This password set here will let you login to the server service account (e.g. `@conduit`)
# and let you run admin commands, invite yourself to the admin room, etc.
#
# no default.
#emergency_password = ""
### Generic database options
# Set this to any float value to multiply conduwuit's in-memory LRU caches with.
+1 -1
View File
@@ -15,7 +15,7 @@ in `/etc/conduwuit/conduwuit.toml`.
### Running
The package uses the [`conduwuit.service`](../configuration.md#example-systemd-unit-file) systemd unit file to start and stop conduwuit. The binary is installed at `/usr/sbin/conduwuit`.
The package uses the [`conduwuit.service`](../configuration/examples.md#example-systemd-unit-file) systemd unit file to start and stop conduwuit. The binary is installed at `/usr/sbin/conduwuit`.
This package assumes by default that conduwuit will be placed behind a reverse proxy. The default config options apply (listening on `localhost` and TCP port `6167`). Matrix federation requires a valid domain name and TLS, so you will need to set up TLS certificates and renewal for it to work properly if you intend to federate.
-1
View File
@@ -6,7 +6,6 @@ set -e
CONDUWUIT_DATABASE_PATH=/var/lib/conduwuit
CONDUWUIT_CONFIG_PATH=/etc/conduwuit
CONDUWUIT_CONFIG_FILE="${CONDUWUIT_CONFIG_PATH}/conduwuit.toml"
case "$1" in
configure)
+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 = "e9e1cb5ba92a44ea225fe8d13b31aa23621b9035"
rev = "b4887edfb84771336930855727390edec07d63fa"
#branch = "master"
default-features = false
+10 -9
View File
@@ -2,19 +2,20 @@
- [Introduction](introduction.md)
- [Differences from upstream Conduit](differences.md)
- [Example configuration](configuration.md)
- [Configuration](configuration.md)
- [Examples](configuration/examples.md)
- [Deploying](deploying.md)
- [Generic](deploying/generic.md)
- [NixOS](deploying/nixos.md)
- [Docker](deploying/docker.md)
- [Arch Linux](deploying/arch-linux.md)
- [Debian](deploying/debian.md)
- [Generic](deploying/generic.md)
- [NixOS](deploying/nixos.md)
- [Docker](deploying/docker.md)
- [Arch Linux](deploying/arch-linux.md)
- [Debian](deploying/debian.md)
- [TURN](turn.md)
- [Appservices](appservices.md)
- [Maintenance](maintenance.md)
- [Troubleshooting](troubleshooting.md)
- [Development](development.md)
- [Contributing](contributing.md)
- [Testing](development/testing.md)
- [Hot Reloading ("Live" Development)](development/hot_reload.md)
- [Contributing](contributing.md)
- [Testing](development/testing.md)
- [Hot Reloading ("Live" Development)](development/hot_reload.md)
- [conduwuit Community Code of Conduct](conduwuit_coc.md)
+13 -27
View File
@@ -1,32 +1,18 @@
## Example configuration
# Configuration
<details>
<summary>Example configuration</summary>
This chapter describes various ways to configure conduwuit.
```toml
{{#include ../conduwuit-example.toml}}
```
## Basics
</details>
Conduwuit uses a config file for the majority of the settings. Please refer to the
[example config file](./configuration/examples.md#example-configuration) for all of those settings.
The config file to use can either be specified on the command line when running conduwuit by specifying the
`-c`, `--config` flag. Alternatively, you can use the environment variable `CONDUWUIT_CONFIG` to specify the config
file to used.
## Debian systemd unit file
## Environment variables
<details>
<summary>Debian systemd unit file</summary>
```
{{#include ../debian/conduwuit.service}}
```
</details>
## Arch Linux systemd unit file
<details>
<summary>Arch Linux systemd unit file</summary>
```
{{#include ../arch/conduwuit.service}}
```
</details>
All of the settings that are found in the config file can be specified by using environment variables.
The environment variable names should be all caps and prefixed with `CONDUWUIT_`.
For example, if the setting you are changing is `max_request_size`, then the environment variable to set is
`CONDUWUIT_MAX_REQUEST_SIZE`.
+32
View File
@@ -0,0 +1,32 @@
## Example configuration
<details>
<summary>Example configuration</summary>
```toml
{{#include ../../conduwuit-example.toml}}
```
</details>
## Debian systemd unit file
<details>
<summary>Debian systemd unit file</summary>
```
{{#include ../../debian/conduwuit.service}}
```
</details>
## Arch Linux systemd unit file
<details>
<summary>Arch Linux systemd unit file</summary>
```
{{#include ../../arch/conduwuit.service}}
```
</details>
+4 -2
View File
@@ -24,9 +24,11 @@ OCI images for conduwuit are available in the registries listed below.
[shield-main]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main
Use
```bash
docker image pull <link>
```
to pull it to your machine.
### Run
@@ -44,7 +46,7 @@ docker run -d -p 8448:6167 \
or you can use [docker compose](#docker-compose).
The `-d` flag lets the container run in detached mode. You may supply an optional `conduwuit.toml` config file, the example config can be found [here](../configuration.md).
The `-d` flag lets the container run in detached mode. You may supply an optional `conduwuit.toml` config file, the example config can be found [here](../configuration/examples.md).
You can pass in different env vars to change config values on the fly. You can even configure conduwuit completely by using env vars. For an overview of possible
values, please take a look at the [`docker-compose.yml`](docker-compose.yml) file.
@@ -55,6 +57,7 @@ If you just want to test conduwuit for a short time, you can use the `--rm` flag
If the `docker run` command is not for you or your setup, you can also use one of the provided `docker-compose` files.
Depending on your proxy setup, you can use one of the following files;
- If you already have a `traefik` instance set up, use [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml)
- If you don't have a `traefik` instance set up (or any other reverse proxy), use [`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)
- For any other reverse proxy, use [`docker-compose.yml`](docker-compose.yml)
@@ -100,7 +103,6 @@ either expose ports `443` and `8448` or serve two endpoints `.well-known/matrix/
With the service `well-known` we use a single `nginx` container that will serve those two files.
## Voice communication
See the [TURN](../turn.md) page.
+7 -7
View File
@@ -43,13 +43,13 @@ If conduwuit runs behind a router or in a container and has a different public I
## Setting up a systemd service
The systemd unit for conduwuit can be found [here](../configuration.md#example-systemd-unit-file). You may need to change the `ExecStart=` path to where you placed the conduwuit binary.
The systemd unit for conduwuit can be found [here](../configuration/examples.md#example-systemd-unit-file). You may need to change the `ExecStart=` path to where you placed the conduwuit binary.
## Creating the conduwuit configuration file
Now we need to create the conduwuit's config file in `/etc/conduwuit/conduwuit.toml`. The example config can be found at [conduwuit-example.toml](../configuration.md).**Please take a moment to read it. You need to change at least the server name.**
Now we need to create the conduwuit's config file in `/etc/conduwuit/conduwuit.toml`. The example config can be found at [conduwuit-example.toml](../configuration/examples.md).**Please take a moment to read it. You need to change at least the server name.**
RocksDB is the only supported database backend. SQLite only exists for historical reasons, is not recommended, and will be removed soon (likely in v0.5.0). Any performance issues, storage issues, database issues, etc will not be assisted if using SQLite and you will be asked to migrate to RocksDB first.
RocksDB is the only supported database backend.
## Setting the correct file permissions
@@ -93,21 +93,21 @@ your.server.name, your.server.name:8448 {
That's it! Just start and enable the service and you're set.
```bash
$ sudo systemctl enable --now caddy
sudo systemctl enable --now caddy
```
## You're done!
## You're done
Now you can start conduwuit with:
```bash
$ sudo systemctl start conduwuit
sudo systemctl start conduwuit
```
Set it to start automatically when your system boots with:
```bash
$ sudo systemctl enable conduwuit
sudo systemctl enable conduwuit
```
## How do I know it works?
+1
View File
@@ -8,6 +8,7 @@ conduwuit can be acquired by [Lix][lix] from various places:
A binary cache for conduwuit that the CI/CD publishes to is available at the
following places (both are the same just different names):
```
https://attic.kennel.juneis.dog/conduit
conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk=
+1 -1
View File
@@ -16,7 +16,7 @@ look like this:
RUSTFLAGS="--cfg tokio_unstable" cargo build \
--release \
--no-default-features \
--features=rocksdb,systemd,element_hacks,gzip_compression,brotli_compression,zstd_compression,tokio_console
--features=systemd,element_hacks,gzip_compression,brotli_compression,zstd_compression,tokio_console
```
[1]: https://docs.rs/tokio-console/latest/tokio_console/
+3
View File
@@ -65,14 +65,17 @@ When a symbol is referenced between crates they become bound: **crates cannot be
Proper resource management is essential for reliable reloading to occur. This is a very basic ask in RAII-idiomatic Rust and the exposure to reloading hazards is remarkably low, generally stemming from poor patterns and practices. Unfortunately static analysis doesn't enforce reload-safety programmatically (though it could one day), for now hazards can be avoided by knowing a few basic do's and dont's:
1. Understand that code is memory. Just like one is forbidden from referencing free'd memory, one must not transfer control to free'd code. Exposure to this is primarily from two things:
- Callbacks, which this project makes very little use of.
- Async tasks, which are addressed below.
2. Tie all resources to a scope or object lifetime with greatest possible symmetry (locality). For our purposes this applies to code resources, which means async blocks and tokio tasks.
- **Never spawn a task without receiving and storing its JoinHandle**.
- **Always wait on join handles** before leaving a scope or in another cleanup function called by an owning scope.
3. Know any minor specific quirks documented in code or here:
- Don't use `tokio::spawn`, instead use our `Handle` in `core/server.rs`, which is reachable in most of the codebase via `services()` or other state. This is due to some bugs or assumptions made in tokio, as it happens in `unsafe {}` blocks, which are mitigated by circumventing some thread-local variables. Using runtime handles is good practice in any case.
The initial implementation PR is available [here][1].
+17 -13
View File
@@ -1,10 +1,11 @@
#### **Note: This list may not up to date. There are rapidly more and more improvements, fixes, changes, etc being made that it is becoming more difficult to maintain this list. I recommend that you give conduwuit a try and see the differences for yourself. If you have any concerns, feel free to join the conduwuit Matrix room and ask any pre-usage questions.**
### list of features, bug fixes, etc that conduwuit does that Conduit does not:
### list of features, bug fixes, etc that conduwuit does that Conduit does not
Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
## Performance:
## Performance
- Concurrency support for individual homeserver key fetching for faster remote room joins and room joins that will error less frequently
- Send `Cache-Control` response header with `immutable` and 1 year cache length for all media requests (download and thumbnail) to instruct clients to cache media, and reduce server load from media requests that could be otherwise cached
- Add feature flags and config options to enable/build with zstd, brotli, and/or gzip HTTP body compression (response and request)
@@ -25,9 +26,10 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
- Use `tracing`/`log`'s `release_max_level_info` feature to improve performance, build speeds, binary size, and CPU usage in release builds by avoid compiling debug/trace log level macros that users will generally never use (can be disabled with a build-time feature flag)
- Remove some unnecessary checks on EDU handling for incoming transactions, effectively speeding them up
- Simplify, dedupe, etc huge chunks of the codebase, including some that were unnecessary overhead, binary bloats, or preventing compiler/linker optimisations
- Implement zero-copy RocksDB database accessors, substantially improving performance caused by unnecessary memory allocations
## General Fixes/Features
## General Fixes/Features:
- Add legacy Element client hack fixing password changes and deactivations on legacy Element Android/iOS due to usage of an unspecced `user` field for UIAA
- Raise and improve all the various request timeouts making some things like room joins and client bugs error less or none at all than they should, and make them all user configurable
- Add missing `reason` field to user ban events (`/ban`)
@@ -56,11 +58,11 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
- Explicitly define support for sliding sync at `/_matrix/client/versions` (`org.matrix.msc3575`)
- Fix seeing empty status messages on user presences
## Moderation
## Moderation:
- (Also see [Admin Room](#admin-room) for all the admin commands pertaining to moderation, there's a lot!)
- Add support for room banning/blocking by ID using admin command
- Add support for serving `support` well-known from `[well_known.support]` (MSC1929)
- Add support for serving `support` well-known from `[global.well_known]` (MSC1929) (`/.well-known/matrix/support`)
- Config option to forbid publishing rooms to the room directory (`lockdown_public_room_directory`) except for admins
- Admin commands to delete room aliases and unpublish rooms from our room directory
- For all [`/report`](https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3roomsroomidreporteventid) requests: check if the reported event ID belongs to the reported room ID, raise report reasoning character limit to 750, fix broken formatting, make a small delayed random response per spec suggestion on privacy, and check if the sender user is in the reported room.
@@ -73,8 +75,8 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
- Deactivating users will remove their profile picture, blurhash, display name, and leave all rooms by default just like Synapse and for additional privacy
- Reject some EDUs from ACL'd users such as read receipts and typing indicators
## Privacy/Security
## Privacy/Security:
- Add config option for device name federation with a privacy-friendly default (disabled)
- Add config option for requiring authentication to the `/publicRooms` endpoint (room directory) with a default enabled for privacy
- Add config option for federating `/publicRooms` endpoint (room directory) to other servers with a default disabled for privacy
@@ -89,8 +91,8 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
- Media repository on handling `Content-Disposition` and `Content-Type` is fully spec compliant and secured
- Send secure default HTTP headers such as a strong restrictive CSP (see MSC4149), deny iframes, disable `X-XSS-Protection`, disable interest cohort in `Permission-Policy`, etc to mitigate any potential attack surface such as from untrusted media
## Administration/Logging
## Administration/Logging:
- Commandline argument to specify the path to a config file instead of relying on `CONDUIT_CONFIG`
- Revamped admin room infrastructure and commands
- Substantially clean up, improve, and fix logging (less noisy dead server logging, registration attempts, more useful troubleshooting logging, proper error propagation, etc)
@@ -108,8 +110,8 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
- Log the client IP on various requests such as registrations, banned room join attempts, logins, deactivations, federation transactions, etc
- Fix Conduit dropping some remote server federation response errors
## Maintenance/Stability
## Maintenance/Stability:
- GitLab CI ported to GitHub Actions
- Add support for the Matrix spec compliance test suite [Complement](https://github.com/matrix-org/complement/) via the Nix flake and various other fixes for it
- Implement running and diff'ing Complement results in CI and error if any mismatch occurs to prevent large cases of conduwuit regressions
@@ -119,19 +121,21 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
- Fixed every single clippy (default lints) and rustc warnings, including some that were performance related or potential safety issues / unsoundness
- Add a **lot** of other clippy and rustc lints and a rustfmt.toml file
- Repo uses [Renovate](https://docs.renovatebot.com/), [Trivy](https://github.com/aquasecurity/trivy-action), and keeps ALL dependencies as up to date as possible
- Attempts and interest in removing extreme and unnecessary panics/unwraps/expects that can lead to denial of service or such (upstream and upstream contributors want this unusual behaviour for some reason)
- Purge unmaintained/irrelevant/broken database backends (heed, sled, persy) and other unnecessary code or overhead
- webp support for images
- Add cargo audit support to CI
- Add documentation lints via lychee and markdownlint-cli to CI
- CI tests for all sorts of feature matrixes (jemalloc, non-defaullt, all features, etc)
- Add static and dynamic linking smoke tests in CI to prevent any potential linking regressions for Complement, static binaries, Nix devshells, etc
- Add timestamp by commit date when building OCI images for keeping image build reproducibility and still have a meaningful "last modified date" for OCI image
- Add timestamp by commit date via `SOURCE_DATE_EPOCH` for Debian packages
- Startup check if conduwuit running in a container and is listening on 127.0.0.1 (generally containers are using NAT networking and 0.0.0.0 is the intended listening address)
- Add a panic catcher layer to return panic messages in HTTP responses if a panic occurs
- Add full compatibility support for SHA256 media file names instead of base64 file names to overcome filesystem file name length limitations (OS error file name too long) while still retaining upstream database compatibility
- Remove SQLite support due to being very poor performance, difficult to maintain against RocksDB, and is a blocker to significantly improved database code
## Admin Room
## Admin Room:
- Add support for a console CLI interface that can issue admin commands and output them in your terminal
- Add support for an admin-user-only commandline admin room interface that can be issued in any room with the `\\!admin` or `\!admin` prefix and returns the response as yourself in the same room
- Add admin commands for uptime, server startup, server shutdown, and server restart
@@ -165,12 +169,11 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
- Extend memory usage admin server command to support showing memory allocator stats such as jemalloc's
- Add admin debug command to see memory allocator's full extended debug statistics such as jemalloc's
## Misc
## Misc:
- Add guest support for accessing TURN servers via `turn_allow_guests` like Synapse
- Support for creating rooms with custom room IDs like Maunium Synapse (`room_id` request body field to `/createRoom`)
- Query parameter `?format=event|content` for returning either the room state event's content (default) for the full room state event on ` /_matrix/client/v3/rooms/{roomId}/state/{eventType}[/{stateKey}]` requests (see https://github.com/matrix-org/matrix-spec/issues/1047)
- Add **optional** feature flag to use SHA256 key names for media instead of base64 to overcome filesystem file name length limitations (OS error file name too long)
- Query parameter `?format=event|content` for returning either the room state event's content (default) for the full room state event on `/_matrix/client/v3/rooms/{roomId}/state/{eventType}[/{stateKey}]` requests (see <https://github.com/matrix-org/matrix-spec/issues/1047>)
- Send a User-Agent on all of our requests
- Send `avatar_url` on invite room membership events/changes
- Support sending [`well_known` response to client login responses](https://spec.matrix.org/v1.10/client-server-api/#post_matrixclientv3login) if using config option `[well_known.client]`
@@ -179,6 +182,7 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
- Implement legacy Matrix `/v1/` media endpoints that some clients and servers may still call
- Config option to change Conduit's behaviour of homeserver key fetching (`query_trusted_key_servers_first`). This option sets whether conduwuit will query trusted notary key servers first before the individual homeserver(s), or vice versa which may help in joining certain rooms.
- Implement unstable MSC2666 support for querying mutual rooms with a user
- Implement unstable MSC3266 room summary API support
- Implement unstable MSC4125 support for specifying servers to join via on federated invites
- Make conduwuit build and be functional under Nix + macOS
- Log out all sessions after unsetting the emergency password
+4 -1
View File
@@ -5,6 +5,7 @@
conduwuit has moderation through admin room commands. "binary commands" (medium priority) and an admin API (low priority) is planned. Some moderation-related config options are available in the example config such as "global ACLs" and blocking media requests to certain servers. See the example config for the moderation config options under the "Moderation / Privacy / Security" section.
conduwuit has moderation admin commands for:
- managing room aliases (`!admin rooms alias`)
- managing room directory (`!admin rooms directory`)
- managing room banning/blocking and user removal (`!admin rooms moderation`)
@@ -28,7 +29,7 @@ Any commands with `-list` in them will require a codeblock in the message with e
If using RocksDB, there's very little you need to do. Compaction is ran automatically based on various defined thresholds tuned for conduwuit to be high performance with the least I/O amplifcation or overhead. Manually running compaction is not recommended, or compaction via a timer. RocksDB is built with io_uring support via liburing for async read I/O.
Some RocksDB settings can be adjusted such as the compression method chosen. See the RocksDB section in the [example config](configuration.md). btrfs users may benefit from disabling compression on RocksDB if CoW is in use.
Some RocksDB settings can be adjusted such as the compression method chosen. See the RocksDB section in the [example config](configuration/examples.md). btrfs users may benefit from disabling compression on RocksDB if CoW is in use.
RocksDB troubleshooting can be found [in the RocksDB section of troubleshooting](troubleshooting.md).
@@ -37,6 +38,7 @@ RocksDB troubleshooting can be found [in the RocksDB section of troubleshooting]
Currently only RocksDB supports online backups. If you'd like to backup your database online without any downtime, see the `!admin server` command for the backup commands and the `database_backup_path` config options in the example config. Please note that the format of the database backup is not the exact same. This is unfortunately a bad design choice by Facebook as we are using the database backup engine API from RocksDB, however the data is still there and can still be joined together.
To restore a backup from an online RocksDB backup:
- shutdown conduwuit
- create a new directory for merging together the data
- in the online backup created, copy all `.sst` files in `$DATABASE_BACKUP_PATH/shared_checksum` to your new directory
@@ -52,6 +54,7 @@ Backing up media is also just copying the `media/` directory from your database
## Media
Media still needs various work, however conduwuit implements media deletion via:
- MXC URI or Event ID (unencrypted and attempts to find the MXC URI in the event)
- Delete list of MXC URIs
- Delete remote media in the past `N` seconds/minutes via filesystem metadata on the file created time (`btime`) or file modified time (`mtime`)
+3 -6
View File
@@ -12,7 +12,7 @@
#### Direct IO
Some filesystems may not like RocksDB using [Direct IO](https://github.com/facebook/rocksdb/wiki/Direct-IO). Direct IO is for non-buffered I/O which improves conduwuit performance, but at least FUSE is a filesystem potentially known to not like this. See the [example config](configuration.md) for disabling it if needed. Issues from Direct IO on unsupported filesystems are usually shown as startup errors.
Some filesystems may not like RocksDB using [Direct IO](https://github.com/facebook/rocksdb/wiki/Direct-IO). Direct IO is for non-buffered I/O which improves conduwuit performance, but at least FUSE is a filesystem potentially known to not like this. See the [example config](configuration/examples.md) for disabling it if needed. Issues from Direct IO on unsupported filesystems are usually shown as startup errors.
#### Database corruption
@@ -32,17 +32,14 @@ By default, conduwuit uses `TolerateCorruptedTailRecords` as generally these may
`AbsoluteConsistency` will fail to start the database if any sign of corruption is detected. `SkipAnyCorruptedRecord` will skip all forms of corruption unless it forbids the database from opening (e.g. too severe). Usage of `SkipAnyCorruptedRecord` voids any support as this may cause more damage and/or leave your database in a permanently inconsistent state, but it may do something if `PointInTime` does not work as a last ditch effort.
With this in mind:
- First start conduwuit with the `PointInTime` recovery method. See the [example config](configuration.md) for how to do this using `rocksdb_recovery_mode`
- First start conduwuit with the `PointInTime` recovery method. See the [example config](configuration/examples.md) for how to do this using `rocksdb_recovery_mode`
- If your database successfully opens, clients are recommended to clear their client cache to account for the rollback
- Leave your conduwuit running in `PointInTime` for at least 30-60 minutes so as much possible corruption is restored
- If all goes will, you should be able to restore back to using `TolerateCorruptedTailRecords` and you have successfully recovered your database
## Media
#### "File name too long"
If you are running into the "file name is too long" OS error for media requests, your filesystem cannot handle file name lengths >=255 characters. This is unfortuntely due to Conduit (upstream) using base64 for file name keys which is very problematic for some filesystems as the base64 input is untrusted and long file names or specific inputs can cause this. If you would like to avoid this, you may build conduwuit yourself with the `sha256_media` feature. **This will lose database compatibility with upstream**.
## Debugging
Note that users should not really be debugging things. If you find yourself debugging and find the issue, please let us know and/or how we can fix it. Various debug commands can be found in `!admin debug`.
+4 -1
View File
@@ -11,12 +11,15 @@ use-auth-secret
static-auth-secret=<a secret key>
realm=<your server domain>
```
A common way to generate a suitable alphanumeric secret key is by using `pwgen -s 64 1`.
These same values need to be set in conduwuit. See the [example config](configuration.md) in the TURN section for configuring these and restart conduwuit after.
These same values need to be set in conduwuit. See the [example config](configuration/examples.md) in the TURN section for configuring these and restart conduwuit after.
### Run
Run the [Coturn](https://hub.docker.com/r/coturn/coturn) image using
```bash
docker run -d --network=host -v $(pwd)/coturn.conf:/etc/coturn/turnserver.conf coturn/coturn
```
+11 -1
View File
@@ -55,6 +55,11 @@ name = "lychee"
group = "versions"
script = "lychee --version"
[[task]]
name = "markdownlint"
group = "versions"
script = "markdownlint --version"
[[task]]
name = "cargo-audit"
group = "security"
@@ -136,7 +141,12 @@ cargo clippy \
[[task]]
name = "lychee"
group = "lints"
script = "lychee --verbose --offline docs *.md"
script = "lychee --verbose --offline docs *.md --exclude development.md"
[[task]]
name = "markdownlint"
group = "lints"
script = "markdownlint docs *.md || true" # TODO: fix the ton of markdown lints so we can drop `|| true`
[[task]]
name = "cargo/all"
Generated
+151 -66
View File
@@ -9,11 +9,11 @@
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1711742460,
"narHash": "sha256-0O4v6e4a1toxXZ2gf5INhg4WPE5C5T+SVvsBt+45Mcc=",
"lastModified": 1717279440,
"narHash": "sha256-kH04ReTjxOpQumgWnqy40vvQLSnLGxWP6RF3nq5Esrk=",
"owner": "zhaofengli",
"repo": "attic",
"rev": "4dbdbee45728d8ce5788db6461aaaa89d98081f0",
"rev": "717cc95983cdc357bc347d70be20ced21f935843",
"type": "github"
},
"original": {
@@ -31,11 +31,11 @@
"pre-commit-hooks": "pre-commit-hooks"
},
"locked": {
"lastModified": 1717420532,
"narHash": "sha256-OCCmI69EMaA4BcxRKrXJsx5Ozua2f/PKEy4aJbE7ziM=",
"lastModified": 1719923519,
"narHash": "sha256-7Rhljj2fsklFRsu+eq7N683Z9qukmreMEj5C1GqCrSA=",
"owner": "cachix",
"repo": "cachix",
"rev": "5727f0676f08a4b41ed13d403ec64dcce989f6e5",
"rev": "4e9e71f78b9500fa6210cf1eaa4d75bdbab777c3",
"type": "github"
},
"original": {
@@ -45,14 +45,47 @@
"type": "github"
}
},
"cachix_2": {
"inputs": {
"devenv": "devenv_2",
"flake-compat": [
"cachix",
"devenv",
"flake-compat"
],
"nixpkgs": [
"cachix",
"devenv",
"nixpkgs"
],
"pre-commit-hooks": [
"cachix",
"devenv",
"pre-commit-hooks"
]
},
"locked": {
"lastModified": 1712055811,
"narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=",
"owner": "cachix",
"repo": "cachix",
"rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "cachix",
"type": "github"
}
},
"complement": {
"flake": false,
"locked": {
"lastModified": 1715700731,
"narHash": "sha256-cie+b5N/TQAFD8vF/XbqfyFJkFU0qUPDbtJQDm/TfQc=",
"lastModified": 1719903368,
"narHash": "sha256-PPzgxM4Bir+Zh9FUV/v+RBxEYeJxYVmi/BYo3uqt268=",
"owner": "matrix-org",
"repo": "complement",
"rev": "8587fb3cbe746754b2c883ff6c818ca4d987d0a5",
"rev": "bc97f1ddc1cd7485faf80c8935ee2641f3e1b57c",
"type": "github"
},
"original": {
@@ -70,11 +103,11 @@
]
},
"locked": {
"lastModified": 1702918879,
"narHash": "sha256-tWJqzajIvYcaRWxn+cLUB9L9Pv4dQ3Bfit/YjU5ze3g=",
"lastModified": 1717025063,
"narHash": "sha256-dIubLa56W9sNNz0e8jGxrX3CAkPXsq7snuFA/Ie6dn8=",
"owner": "ipetkov",
"repo": "crane",
"rev": "7195c00c272fdd92fc74e7d5a0a2844b9fadb2fb",
"rev": "480dff0be03dac0e51a8dfc26e882b0d123a450e",
"type": "github"
},
"original": {
@@ -106,14 +139,49 @@
},
"devenv": {
"inputs": {
"cachix": "cachix_2",
"flake-compat": [
"cachix",
"flake-compat"
],
"nix": "nix_2",
"nixpkgs": [
"cachix",
"nixpkgs"
],
"pre-commit-hooks": [
"cachix",
"pre-commit-hooks"
]
},
"locked": {
"lastModified": 1719759336,
"narHash": "sha256-3a34VL/QnHprl5gMy9xlx6d8J+iNp+W88Ex8smkgH9M=",
"owner": "cachix",
"repo": "devenv",
"rev": "bb32aa986f2f695385e54428d0eaf7d05b31466e",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"devenv_2": {
"inputs": {
"flake-compat": [
"cachix",
"devenv",
"cachix",
"flake-compat"
],
"nix": "nix",
"nixpkgs": "nixpkgs_2",
"poetry2nix": "poetry2nix",
"pre-commit-hooks": [
"cachix",
"devenv",
"cachix",
"pre-commit-hooks"
]
@@ -281,24 +349,6 @@
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_4": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"ref": "main",
@@ -331,11 +381,11 @@
"liburing": {
"flake": false,
"locked": {
"lastModified": 1716565485,
"narHash": "sha256-4R19aJNQYs6vb0/Hz4bWT56YN1P1DkFL/sxdE4Yj0CE=",
"lastModified": 1719025212,
"narHash": "sha256-kD0yhjNStqC6uFqC1AxBwUpc/HlSFtiKrV+gwDyroDc=",
"owner": "axboe",
"repo": "liburing",
"rev": "b90c0e670a93caabbebe2d9e24ff85cece4cfe0e",
"rev": "7b3245583069bd481190c9da18f22e9fc8c3a805",
"type": "github"
},
"original": {
@@ -349,6 +399,8 @@
"inputs": {
"flake-compat": "flake-compat_2",
"nixpkgs": [
"cachix",
"devenv",
"cachix",
"devenv",
"nixpkgs"
@@ -356,11 +408,11 @@
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
"lastModified": 1708577783,
"narHash": "sha256-92xq7eXlxIT5zFNccLpjiP7sdQqQI30Gyui2p/PfKZM=",
"lastModified": 1712911606,
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
"owner": "domenkozar",
"repo": "nix",
"rev": "ecd0af0c1f56de32cbad14daa1d82a132bf298f8",
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
"type": "github"
},
"original": {
@@ -389,6 +441,8 @@
"nix-github-actions": {
"inputs": {
"nixpkgs": [
"cachix",
"devenv",
"cachix",
"devenv",
"poetry2nix",
@@ -409,6 +463,35 @@
"type": "github"
}
},
"nix_2": {
"inputs": {
"flake-compat": [
"cachix",
"devenv",
"flake-compat"
],
"nixpkgs": [
"cachix",
"devenv",
"nixpkgs"
],
"nixpkgs-regression": "nixpkgs-regression_2"
},
"locked": {
"lastModified": 1712911606,
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
"owner": "domenkozar",
"repo": "nix",
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
"type": "github"
},
"original": {
"owner": "domenkozar",
"ref": "devenv-2.21",
"repo": "nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1711401922,
@@ -441,6 +524,22 @@
"type": "github"
}
},
"nixpkgs-regression_2": {
"locked": {
"lastModified": 1643052045,
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1711460390,
@@ -459,11 +558,11 @@
},
"nixpkgs-stable_2": {
"locked": {
"lastModified": 1710695816,
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
"lastModified": 1718811006,
"narHash": "sha256-0Y8IrGhRmBmT7HHXlxxepg2t8j1X90++qRN3lukGaIk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
"rev": "03d771e513ce90147b65fe922d87d3a0356fc125",
"type": "github"
},
"original": {
@@ -491,11 +590,11 @@
},
"nixpkgs_3": {
"locked": {
"lastModified": 1715534503,
"narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
"lastModified": 1719848872,
"narHash": "sha256-H3+EC5cYuq+gQW8y0lSrrDZfH71LB4DAf+TDFyvwCNA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
"rev": "00d80d13810dbfea8ab4ed1009b09100cca86ba8",
"type": "github"
},
"original": {
@@ -526,6 +625,8 @@
"flake-utils": "flake-utils_2",
"nix-github-actions": "nix-github-actions",
"nixpkgs": [
"cachix",
"devenv",
"cachix",
"devenv",
"nixpkgs"
@@ -548,7 +649,6 @@
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat_4",
"flake-utils": "flake-utils_3",
"gitignore": "gitignore",
"nixpkgs": [
"cachix",
@@ -557,11 +657,11 @@
"nixpkgs-stable": "nixpkgs-stable_2"
},
"locked": {
"lastModified": 1715609711,
"narHash": "sha256-/5u29K0c+4jyQ8x7dUIEUWlz2BoTSZWUP2quPwFCE7M=",
"lastModified": 1719259945,
"narHash": "sha256-F1h+XIsGKT9TkGO3omxDLEb/9jOOsI6NnzsXFsZhry4=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "c182c876690380f8d3b9557c4609472ebfa1b141",
"rev": "0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07",
"type": "github"
},
"original": {
@@ -573,16 +673,16 @@
"rocksdb": {
"flake": false,
"locked": {
"lastModified": 1716773462,
"narHash": "sha256-5kUH+XK+2lbFfUgbxuNy3YMLHbp6scfWPdtc8za1wDM=",
"lastModified": 1719949653,
"narHash": "sha256-DYx7XHH2GEh17GukKhXs6laM6l+eugCmRkF0adpi9wk=",
"owner": "girlbossceo",
"repo": "rocksdb",
"rev": "c8a1450231e9c608edf535538dbe8ca1a8d2f3bc",
"rev": "a935c0273e1ba44eacf88ce3685a9b9831486155",
"type": "github"
},
"original": {
"owner": "girlbossceo",
"ref": "v9.2.1",
"ref": "v9.3.1",
"repo": "rocksdb",
"type": "github"
}
@@ -595,7 +695,7 @@
"crane": "crane_2",
"fenix": "fenix",
"flake-compat": "flake-compat_5",
"flake-utils": "flake-utils_4",
"flake-utils": "flake-utils_3",
"liburing": "liburing",
"nix-filter": "nix-filter",
"nixpkgs": "nixpkgs_4",
@@ -648,21 +748,6 @@
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
+4 -1
View File
@@ -10,7 +10,7 @@
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.2.1"; flake = false; };
rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.3.1"; flake = false; };
liburing = { url = "github:axboe/liburing?ref=master"; flake = false; };
};
@@ -108,6 +108,9 @@
# Needed for finding broken markdown links
lychee
# Needed for linting markdown files
markdownlint-cli
# Useful for editing the book locally
mdbook
])
+1 -15
View File
@@ -17,25 +17,13 @@ crate-type = [
]
[features]
dev_release_log_level = []
#dev_release_log_level = []
release_max_log_level = [
"tracing/max_level_trace",
"tracing/release_max_level_info",
"log/max_level_trace",
"log/release_max_level_info",
]
rocksdb = [
"dep:rust-rocksdb",
]
jemalloc = [
"rust-rocksdb/jemalloc",
]
io_uring = [
"rust-rocksdb/io-uring",
]
zstd_compression = [
"rust-rocksdb/zstd",
]
[dependencies]
clap.workspace = true
@@ -48,8 +36,6 @@ log.workspace = true
loole.workspace = true
regex.workspace = true
ruma.workspace = true
rust-rocksdb.optional = true
rust-rocksdb.workspace = true
serde_json.workspace = true
serde.workspace = true
serde_yaml.workspace = true
@@ -19,7 +19,7 @@ pub(super) async fn check_all_users(_body: Vec<&str>) -> Result<RoomMessageEvent
let message = format!(
"Database query completed in {query_time:?}:\n\n```\nTotal entries: {total:?}\nFailure/Invalid user count: \
{err_count:?}\nSuccess/Valid user count: {ok_count:?}```"
{err_count:?}\nSuccess/Valid user count: {ok_count:?}\n```"
);
Ok(RoomMessageEventContent::notice_markdown(message))
@@ -8,12 +8,12 @@ use self::commands::*;
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
pub(super) enum FsckCommand {
CheckAllUsers,
pub(super) enum CheckCommand {
AllUsers,
}
pub(super) async fn process(command: FsckCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(command: CheckCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
FsckCommand::CheckAllUsers => check_all_users(body).await?,
CheckCommand::AllUsers => check_all_users(body).await?,
})
}
+14 -15
View File
@@ -13,9 +13,9 @@ use conduit::{
use ruma::{
api::{client::error::ErrorKind, federation::event::get_room_state},
events::room::message::RoomMessageEventContent,
CanonicalJsonObject, EventId, RoomId, RoomVersionId, ServerName,
CanonicalJsonObject, EventId, OwnedRoomOrAliasId, RoomId, RoomVersionId, ServerName,
};
use service::{rooms::event_handler::parse_incoming_pdu, sending::resolve::resolve_actual_dest, services, PduEvent};
use service::{rooms::event_handler::parse_incoming_pdu, sending::resolve_actual_dest, services, PduEvent};
use tokio::sync::RwLock;
use tracing_subscriber::EnvFilter;
@@ -236,7 +236,8 @@ pub(super) async fn get_remote_pdu(
}
}
pub(super) async fn get_room_state(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
pub(super) async fn get_room_state(_body: Vec<&str>, room: OwnedRoomOrAliasId) -> Result<RoomMessageEventContent> {
let room_id = services().rooms.alias.resolve(&room).await?;
let room_state = services()
.rooms
.state_accessor
@@ -252,17 +253,14 @@ pub(super) async fn get_room_state(_body: Vec<&str>, room_id: Box<RoomId>) -> Re
));
}
let json_text = serde_json::to_string_pretty(&room_state).map_err(|e| {
let json = serde_json::to_string_pretty(&room_state).map_err(|e| {
warn!("Failed converting room state vector in our database to pretty JSON: {e}");
Error::bad_database(
"Failed to convert room state events to pretty JSON, possible invalid room state events in our database",
)
})?;
Ok(RoomMessageEventContent::notice_markdown(format!(
"{}\n```json\n{}\n```",
"Found full room state", json_text
)))
Ok(RoomMessageEventContent::notice_markdown(format!("```json\n{json}\n```")))
}
pub(super) async fn ping(_body: Vec<&str>, server: Box<ServerName>) -> Result<RoomMessageEventContent> {
@@ -616,15 +614,16 @@ pub(super) async fn resolve_true_destination(
let state = &services().server.log.capture;
let logs = Arc::new(Mutex::new(String::new()));
let capture = Capture::new(state, Some(filter), capture::fmt_markdown(logs.clone()));
let (actual_dest, hostname_uri);
{
let _capture_scope = capture.start();
(actual_dest, hostname_uri) = resolve_actual_dest(&server_name, !no_cache).await?;
};
let capture_scope = capture.start();
let actual = resolve_actual_dest(&server_name, !no_cache).await?;
drop(capture_scope);
let msg = format!(
"{}\nDestination: {actual_dest}\nHostname URI: {hostname_uri}",
logs.lock().expect("locked")
"{}\nDestination: {}\nHostname URI: {}",
logs.lock().expect("locked"),
actual.dest,
actual.host,
);
Ok(RoomMessageEventContent::text_markdown(msg))
}
+9 -2
View File
@@ -1,8 +1,10 @@
mod commands;
pub(crate) mod tester;
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, EventId, RoomId, ServerName};
use ruma::{events::room::message::RoomMessageEventContent, EventId, OwnedRoomOrAliasId, RoomId, ServerName};
use tester::TesterCommand;
use self::commands::*;
@@ -71,7 +73,7 @@ pub(super) enum DebugCommand {
/// Of course the check is still done on the actual client API.
GetRoomState {
/// Room ID
room_id: Box<RoomId>,
room_id: OwnedRoomOrAliasId,
},
/// - Sends a federation request to the remote server's
@@ -157,6 +159,10 @@ pub(super) enum DebugCommand {
/// - Print extended memory usage
MemoryStats,
/// - Developer test stubs
#[command(subcommand)]
Tester(TesterCommand),
}
pub(super) async fn process(command: DebugCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
@@ -207,5 +213,6 @@ pub(super) async fn process(command: DebugCommand, body: Vec<&str>) -> Result<Ro
no_cache,
} => resolve_true_destination(body, server_name, no_cache).await?,
DebugCommand::MemoryStats => memory_stats(),
DebugCommand::Tester(command) => tester::process(command, body).await?,
})
}
+42
View File
@@ -0,0 +1,42 @@
use ruma::events::room::message::RoomMessageEventContent;
use crate::Result;
#[derive(clap::Subcommand)]
#[cfg_attr(test, derive(Debug))]
pub(crate) enum TesterCommand {
Tester,
Timer,
}
pub(super) async fn process(command: TesterCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
match command {
TesterCommand::Tester => tester(body).await,
TesterCommand::Timer => timer(body).await,
}
}
#[inline(never)]
#[rustfmt::skip]
#[allow(unused_variables)]
async fn tester(body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(RoomMessageEventContent::notice_plain("completed"))
}
#[inline(never)]
#[rustfmt::skip]
async fn timer(body: Vec<&str>) -> Result<RoomMessageEventContent> {
let started = std::time::Instant::now();
timed(&body);
let elapsed = started.elapsed();
Ok(RoomMessageEventContent::notice_plain(format!("completed in {elapsed:#?}")))
}
#[inline(never)]
#[rustfmt::skip]
#[allow(unused_variables)]
fn timed(body: &[&str]) {
}
+7 -3
View File
@@ -15,14 +15,18 @@ pub(super) async fn enable_room(_body: Vec<&str>, room_id: Box<RoomId>) -> Resul
}
pub(super) async fn incoming_federation(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
let map = services().globals.roomid_federationhandletime.read().await;
let map = services()
.globals
.roomid_federationhandletime
.read()
.expect("locked");
let mut msg = format!("Handling {} incoming pdus:\n", map.len());
for (r, (e, i)) in map.iter() {
let elapsed = i.elapsed();
writeln!(msg, "{} {}: {}m{}s", r, e, elapsed.as_secs() / 60, elapsed.as_secs() % 60,)
.expect("should be able to write to string buffer");
writeln!(msg, "{} {}: {}m{}s", r, e, elapsed.as_secs() / 60, elapsed.as_secs() % 60)?;
}
Ok(RoomMessageEventContent::text_plain(&msg))
}
+23 -24
View File
@@ -1,3 +1,5 @@
use std::time::Instant;
use clap::Parser;
use conduit::trace;
use ruma::events::{
@@ -11,11 +13,10 @@ use conduit::Result;
pub(crate) use service::admin::{Command, Service};
use service::admin::{CommandOutput, CommandResult, HandlerResult};
use self::{fsck::FsckCommand, tester::TesterCommands};
use crate::{
appservice, appservice::AppserviceCommand, debug, debug::DebugCommand, federation, federation::FederationCommand,
fsck, media, media::MediaCommand, query, query::QueryCommand, room, room::RoomCommand, server,
server::ServerCommand, services, tester, user, user::UserCommand,
appservice, appservice::AppserviceCommand, check, check::CheckCommand, debug, debug::DebugCommand, federation,
federation::FederationCommand, media, media::MediaCommand, query, query::QueryCommand, room, room::RoomCommand,
server, server::ServerCommand, services, user, user::UserCommand,
};
pub(crate) const PAGE_SIZE: usize = 100;
@@ -47,20 +48,17 @@ pub(crate) enum AdminCommand {
/// - Commands for managing media
Media(MediaCommand),
#[command(subcommand)]
/// - Commands for checking integrity
Check(CheckCommand),
#[command(subcommand)]
/// - Commands for debugging things
Debug(DebugCommand),
#[command(subcommand)]
/// - Query all the database getters and iterators
/// - Low-level queries for database getters and iterators
Query(QueryCommand),
#[command(subcommand)]
/// - Query all the database getters and iterators
Fsck(FsckCommand),
#[command(subcommand)]
Tester(TesterCommands),
}
#[must_use]
@@ -84,11 +82,10 @@ async fn handle_command(command: Command) -> CommandResult {
// Parse and process a message from the admin room
async fn process_admin_message(msg: String) -> CommandOutput {
let mut lines = msg.lines().filter(|l| !l.trim().is_empty());
let command_line = lines.next().expect("each string has at least one line");
let command = lines.next().expect("each string has at least one line");
let body = lines.collect::<Vec<_>>();
let admin_command = match parse_admin_command(command_line) {
Ok(command) => command,
let parsed = match parse_admin_command(command) {
Ok(parsed) => parsed,
Err(error) => {
let server_name = services().globals.server_name();
let message = error.replace("server.name", server_name.as_str());
@@ -96,12 +93,15 @@ async fn process_admin_message(msg: String) -> CommandOutput {
},
};
match process_admin_command(admin_command, body).await {
Ok(reply_message) => Some(reply_message),
Err(error) => {
let markdown_message = format!("Encountered an error while handling the command:\n```\n{error}\n```",);
Some(RoomMessageEventContent::notice_markdown(markdown_message))
},
let timer = Instant::now();
let result = process_admin_command(parsed, body).await;
let elapsed = timer.elapsed();
conduit::debug!(?command, ok = result.is_ok(), "command processed in {elapsed:?}");
match result {
Ok(reply) => Some(reply),
Err(error) => Some(RoomMessageEventContent::notice_markdown(format!(
"Encountered an error while handling the command:\n```\n{error}\n```"
))),
}
}
@@ -164,8 +164,7 @@ async fn process_admin_command(command: AdminCommand, body: Vec<&str>) -> Result
AdminCommand::Server(command) => server::process(command, body).await?,
AdminCommand::Debug(command) => debug::process(command, body).await?,
AdminCommand::Query(command) => query::process(command, body).await?,
AdminCommand::Fsck(command) => fsck::process(command, body).await?,
AdminCommand::Tester(command) => tester::process(command, body).await?,
AdminCommand::Check(command) => check::process(command, body).await?,
};
Ok(reply_message_content)
+3 -3
View File
@@ -15,7 +15,7 @@ pub(super) async fn delete(
if let Some(mxc) = mxc {
debug!("Got MXC URL: {mxc}");
services().media.delete(mxc.to_string()).await?;
services().media.delete(mxc.as_ref()).await?;
return Ok(RoomMessageEventContent::text_plain(
"Deleted the MXC from our database and on our filesystem.",
@@ -123,7 +123,7 @@ pub(super) async fn delete(
}
for mxc_url in mxc_urls {
services().media.delete(mxc_url).await?;
services().media.delete(&mxc_url).await?;
mxc_deletion_count = mxc_deletion_count.saturating_add(1);
}
@@ -154,7 +154,7 @@ pub(super) async fn delete_list(body: Vec<&str>) -> Result<RoomMessageEventConte
for mxc in mxc_list {
debug!("Deleting MXC {mxc} in bulk");
services().media.delete(mxc.to_owned()).await?;
services().media.delete(mxc).await?;
mxc_deletion_count = mxc_deletion_count
.checked_add(1)
.expect("mxc_deletion_count should not get this high");
+1 -2
View File
@@ -1,15 +1,14 @@
#![allow(clippy::wildcard_imports)]
pub(crate) mod appservice;
pub(crate) mod check;
pub(crate) mod debug;
pub(crate) mod federation;
pub(crate) mod fsck;
pub(crate) mod handler;
pub(crate) mod media;
pub(crate) mod query;
pub(crate) mod room;
pub(crate) mod server;
pub(crate) mod tester;
pub(crate) mod user;
pub(crate) mod utils;
-2
View File
@@ -14,7 +14,6 @@ pub(super) async fn account_data(subcommand: AccountData) -> Result<RoomMessageE
let timer = tokio::time::Instant::now();
let results = services()
.account_data
.db
.changes_since(room_id.as_deref(), &user_id, since)?;
let query_time = timer.elapsed();
@@ -30,7 +29,6 @@ pub(super) async fn account_data(subcommand: AccountData) -> Result<RoomMessageE
let timer = tokio::time::Instant::now();
let results = services()
.account_data
.db
.get(room_id.as_deref(), &user_id, kind)?;
let query_time = timer.elapsed();
+1 -1
View File
@@ -22,7 +22,7 @@ pub(super) async fn appservice(subcommand: Appservice) -> Result<RoomMessageEven
},
Appservice::All => {
let timer = tokio::time::Instant::now();
let results = services().appservice.db.all();
let results = services().appservice.all();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
+24 -3
View File
@@ -2,6 +2,7 @@ mod account_data;
mod appservice;
mod globals;
mod presence;
mod resolver;
mod room_alias;
mod room_state_cache;
mod sending;
@@ -12,12 +13,12 @@ use conduit::Result;
use room_state_cache::room_state_cache;
use ruma::{
events::{room::message::RoomMessageEventContent, RoomAccountDataEventType},
RoomAliasId, RoomId, ServerName, UserId,
OwnedServerName, RoomAliasId, RoomId, ServerName, UserId,
};
use self::{
account_data::account_data, appservice::appservice, globals::globals, presence::presence, room_alias::room_alias,
sending::sending, users::users,
account_data::account_data, appservice::appservice, globals::globals, presence::presence, resolver::resolver,
room_alias::room_alias, sending::sending, users::users,
};
#[cfg_attr(test, derive(Debug))]
@@ -55,6 +56,10 @@ pub(super) enum QueryCommand {
/// - users.rs iterators and getters
#[command(subcommand)]
Users(Users),
/// - resolver service
#[command(subcommand)]
Resolver(Resolver),
}
#[cfg_attr(test, derive(Debug))]
@@ -287,6 +292,21 @@ pub(super) enum Users {
Iter,
}
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// Resolver service and caches
pub(super) enum Resolver {
/// Query the destinations cache
DestinationsCache {
server_name: Option<OwnedServerName>,
},
/// Query the overrides cache
OverridesCache {
name: Option<String>,
},
}
/// Processes admin query commands
pub(super) async fn process(command: QueryCommand, _body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
@@ -298,5 +318,6 @@ pub(super) async fn process(command: QueryCommand, _body: Vec<&str>) -> Result<R
QueryCommand::Globals(command) => globals(command).await?,
QueryCommand::Sending(command) => sending(command).await?,
QueryCommand::Users(command) => users(command).await?,
QueryCommand::Resolver(command) => resolver(command).await?,
})
}
+1 -2
View File
@@ -22,9 +22,8 @@ pub(super) async fn presence(subcommand: Presence) -> Result<RoomMessageEventCon
} => {
let timer = tokio::time::Instant::now();
let results = services().presence.db.presence_since(since);
let query_time = timer.elapsed();
let presence_since: Vec<(_, _, _)> = results.collect();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{presence_since:#?}\n```"
+87
View File
@@ -0,0 +1,87 @@
use std::fmt::Write;
use conduit::{utils::time, Result};
use ruma::{events::room::message::RoomMessageEventContent, OwnedServerName};
use super::Resolver;
use crate::services;
/// All the getters and iterators in key_value/users.rs
pub(super) async fn resolver(subcommand: Resolver) -> Result<RoomMessageEventContent> {
match subcommand {
Resolver::DestinationsCache {
server_name,
} => destinations_cache(server_name).await,
Resolver::OverridesCache {
name,
} => overrides_cache(name).await,
}
}
async fn destinations_cache(server_name: Option<OwnedServerName>) -> Result<RoomMessageEventContent> {
use service::sending::CachedDest;
let mut out = String::new();
writeln!(out, "| Server Name | Destination | Hostname | Expires |")?;
writeln!(out, "| ----------- | ----------- | -------- | ------- |")?;
let row = |(
name,
&CachedDest {
ref dest,
ref host,
expire,
},
)| {
let expire = time::format(expire, "%+");
writeln!(out, "| {name} | {dest} | {host} | {expire} |").expect("wrote line");
};
let map = services()
.globals
.resolver
.destinations
.read()
.expect("locked");
if let Some(server_name) = server_name.as_ref() {
map.get_key_value(server_name).map(row);
} else {
map.iter().for_each(row);
}
Ok(RoomMessageEventContent::notice_markdown(out))
}
async fn overrides_cache(server_name: Option<String>) -> Result<RoomMessageEventContent> {
use service::sending::CachedOverride;
let mut out = String::new();
writeln!(out, "| Server Name | IP | Port | Expires |")?;
writeln!(out, "| ----------- | --- | ----:| ------- |")?;
let row = |(
name,
&CachedOverride {
ref ips,
port,
expire,
},
)| {
let expire = time::format(expire, "%+");
writeln!(out, "| {name} | {ips:?} | {port} | {expire} |").expect("wrote line");
};
let map = services()
.globals
.resolver
.overrides
.read()
.expect("locked");
if let Some(server_name) = server_name.as_ref() {
map.get_key_value(server_name).map(row);
} else {
map.iter().for_each(row);
}
Ok(RoomMessageEventContent::notice_markdown(out))
}
+5 -7
View File
@@ -10,7 +10,7 @@ pub(super) async fn room_alias(subcommand: RoomAlias) -> Result<RoomMessageEvent
alias,
} => {
let timer = tokio::time::Instant::now();
let results = services().rooms.alias.db.resolve_local_alias(&alias);
let results = services().rooms.alias.resolve_local_alias(&alias);
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
@@ -21,10 +21,9 @@ pub(super) async fn room_alias(subcommand: RoomAlias) -> Result<RoomMessageEvent
room_id,
} => {
let timer = tokio::time::Instant::now();
let results = services().rooms.alias.db.local_aliases_for_room(&room_id);
let query_time = timer.elapsed();
let results = services().rooms.alias.local_aliases_for_room(&room_id);
let aliases: Vec<_> = results.collect();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```"
@@ -32,10 +31,9 @@ pub(super) async fn room_alias(subcommand: RoomAlias) -> Result<RoomMessageEvent
},
RoomAlias::AllLocalAliases => {
let timer = tokio::time::Instant::now();
let results = services().rooms.alias.db.all_local_aliases();
let query_time = timer.elapsed();
let results = services().rooms.alias.all_local_aliases();
let aliases: Vec<_> = results.collect();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```"
+23 -49
View File
@@ -9,9 +9,8 @@ pub(super) async fn sending(subcommand: Sending) -> Result<RoomMessageEventConte
Sending::ActiveRequests => {
let timer = tokio::time::Instant::now();
let results = services().sending.db.active_requests();
let query_time = timer.elapsed();
let active_requests: Result<Vec<(_, _, _)>> = results.collect();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{active_requests:#?}\n```"
@@ -29,8 +28,8 @@ pub(super) async fn sending(subcommand: Sending) -> Result<RoomMessageEventConte
--help for more details.",
));
}
let (results, query_time) = match (appservice_id, server_name, user_id, push_key) {
let timer = tokio::time::Instant::now();
let results = match (appservice_id, server_name, user_id, push_key) {
(Some(appservice_id), None, None, None) => {
if appservice_id.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
@@ -39,25 +38,15 @@ pub(super) async fn sending(subcommand: Sending) -> Result<RoomMessageEventConte
));
}
let timer = tokio::time::Instant::now();
let results = services()
services()
.sending
.db
.queued_requests(&Destination::Appservice(appservice_id));
let query_time = timer.elapsed();
(results, query_time)
},
(None, Some(server_name), None, None) => {
let timer = tokio::time::Instant::now();
let results = services()
.sending
.db
.queued_requests(&Destination::Normal(server_name.into()));
let query_time = timer.elapsed();
(results, query_time)
.queued_requests(&Destination::Appservice(appservice_id))
},
(None, Some(server_name), None, None) => services()
.sending
.db
.queued_requests(&Destination::Normal(server_name.into())),
(None, None, Some(user_id), Some(push_key)) => {
if push_key.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
@@ -66,14 +55,10 @@ pub(super) async fn sending(subcommand: Sending) -> Result<RoomMessageEventConte
));
}
let timer = tokio::time::Instant::now();
let results = services()
services()
.sending
.db
.queued_requests(&Destination::Push(user_id.into(), push_key));
let query_time = timer.elapsed();
(results, query_time)
.queued_requests(&Destination::Push(user_id.into(), push_key))
},
(Some(_), Some(_), Some(_), Some(_)) => {
return Ok(RoomMessageEventContent::text_plain(
@@ -90,6 +75,7 @@ pub(super) async fn sending(subcommand: Sending) -> Result<RoomMessageEventConte
};
let queued_requests = results.collect::<Result<Vec<(_, _)>>>();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{queued_requests:#?}\n```"
@@ -108,7 +94,8 @@ pub(super) async fn sending(subcommand: Sending) -> Result<RoomMessageEventConte
));
}
let (results, query_time) = match (appservice_id, server_name, user_id, push_key) {
let timer = tokio::time::Instant::now();
let results = match (appservice_id, server_name, user_id, push_key) {
(Some(appservice_id), None, None, None) => {
if appservice_id.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
@@ -117,25 +104,15 @@ pub(super) async fn sending(subcommand: Sending) -> Result<RoomMessageEventConte
));
}
let timer = tokio::time::Instant::now();
let results = services()
services()
.sending
.db
.active_requests_for(&Destination::Appservice(appservice_id));
let query_time = timer.elapsed();
(results, query_time)
},
(None, Some(server_name), None, None) => {
let timer = tokio::time::Instant::now();
let results = services()
.sending
.db
.active_requests_for(&Destination::Normal(server_name.into()));
let query_time = timer.elapsed();
(results, query_time)
.active_requests_for(&Destination::Appservice(appservice_id))
},
(None, Some(server_name), None, None) => services()
.sending
.db
.active_requests_for(&Destination::Normal(server_name.into())),
(None, None, Some(user_id), Some(push_key)) => {
if push_key.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
@@ -144,14 +121,10 @@ pub(super) async fn sending(subcommand: Sending) -> Result<RoomMessageEventConte
));
}
let timer = tokio::time::Instant::now();
let results = services()
services()
.sending
.db
.active_requests_for(&Destination::Push(user_id.into(), push_key));
let query_time = timer.elapsed();
(results, query_time)
.active_requests_for(&Destination::Push(user_id.into(), push_key))
},
(Some(_), Some(_), Some(_), Some(_)) => {
return Ok(RoomMessageEventContent::text_plain(
@@ -168,6 +141,7 @@ pub(super) async fn sending(subcommand: Sending) -> Result<RoomMessageEventConte
};
let active_requests = results.collect::<Result<Vec<(_, _)>>>();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{active_requests:#?}\n```"
+1 -2
View File
@@ -9,9 +9,8 @@ pub(super) async fn users(subcommand: Users) -> Result<RoomMessageEventContent>
Users::Iter => {
let timer = tokio::time::Instant::now();
let results = services().users.db.iter();
let query_time = timer.elapsed();
let users = results.collect::<Vec<_>>();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{users:#?}\n```"
+31 -15
View File
@@ -1,4 +1,4 @@
use api::client::{get_alias_helper, leave_room};
use api::client::leave_room;
use ruma::{
events::room::message::RoomMessageEventContent, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId, RoomOrAliasId,
};
@@ -76,13 +76,18 @@ async fn ban_room(
} else {
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
match get_alias_helper(room_alias, None).await {
Ok(response) => {
debug!("Got federation response fetching room ID for room {room}: {:?}", response);
response.room_id
match services()
.rooms
.alias
.resolve_alias(&room_alias, None)
.await
{
Ok((room_id, servers)) => {
debug!(?room_id, ?servers, "Got federation response fetching room ID for {room}");
room_id
},
Err(e) => {
return Ok(RoomMessageEventContent::text_plain(format!(
return Ok(RoomMessageEventContent::notice_plain(format!(
"Failed to resolve room alias {room} to a room ID: {e}"
)));
},
@@ -237,13 +242,19 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo
ID over federation"
);
match get_alias_helper(room_alias, None).await {
Ok(response) => {
match services()
.rooms
.alias
.resolve_alias(&room_alias, None)
.await
{
Ok((room_id, servers)) => {
debug!(
"Got federation response fetching room ID for room {room}: {:?}",
response
?room_id,
?servers,
"Got federation response fetching room ID for {room}",
);
response.room_id
room_id
},
Err(e) => {
// don't fail if force blocking
@@ -426,10 +437,15 @@ async fn unban_room(
} else {
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
match get_alias_helper(room_alias, None).await {
Ok(response) => {
debug!("Got federation response fetching room ID for room {room}: {:?}", response);
response.room_id
match services()
.rooms
.alias
.resolve_alias(&room_alias, None)
.await
{
Ok((room_id, servers)) => {
debug!(?room_id, ?servers, "Got federation response fetching room ID for room {room}");
room_id
},
Err(e) => {
return Ok(RoomMessageEventContent::text_plain(format!(
+17 -25
View File
@@ -1,4 +1,4 @@
use conduit::{warn, Result};
use conduit::{warn, Error, Result};
use ruma::events::room::message::RoomMessageEventContent;
use crate::services;
@@ -27,12 +27,12 @@ pub(super) async fn show_config(_body: Vec<&str>) -> Result<RoomMessageEventCont
}
pub(super) async fn memory_usage(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
let response0 = services().memory_usage().await;
let response1 = services().globals.db.memory_usage();
let response0 = services().memory_usage().await?;
let response1 = services().db.db.memory_usage()?;
let response2 = conduit::alloc::memory_usage();
Ok(RoomMessageEventContent::text_plain(format!(
"Services:\n{response0}\n\nDatabase:\n{response1}\n{}",
"Services:\n{response0}\nDatabase:\n{response1}\n{}",
if !response2.is_empty() {
format!("Allocator:\n {response2}")
} else {
@@ -41,14 +41,8 @@ pub(super) async fn memory_usage(_body: Vec<&str>) -> Result<RoomMessageEventCon
)))
}
pub(super) async fn clear_database_caches(_body: Vec<&str>, amount: u32) -> Result<RoomMessageEventContent> {
services().globals.db.clear_caches(amount);
Ok(RoomMessageEventContent::text_plain("Done."))
}
pub(super) async fn clear_service_caches(_body: Vec<&str>, amount: u32) -> Result<RoomMessageEventContent> {
services().clear_caches(amount).await;
pub(super) async fn clear_caches(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
services().clear_cache().await;
Ok(RoomMessageEventContent::text_plain("Done."))
}
@@ -64,12 +58,6 @@ pub(super) async fn list_backups(_body: Vec<&str>) -> Result<RoomMessageEventCon
}
pub(super) async fn backup_database(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
if !cfg!(feature = "rocksdb") {
return Ok(RoomMessageEventContent::text_plain(
"Only RocksDB supports online backups in conduwuit.",
));
}
let mut result = services()
.server
.runtime()
@@ -88,12 +76,6 @@ pub(super) async fn backup_database(_body: Vec<&str>) -> Result<RoomMessageEvent
}
pub(super) async fn list_database_files(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
if !cfg!(feature = "rocksdb") {
return Ok(RoomMessageEventContent::text_plain(
"Only RocksDB supports listing files in conduwuit.",
));
}
let result = services().globals.db.file_list()?;
Ok(RoomMessageEventContent::notice_markdown(result))
@@ -114,7 +96,17 @@ pub(super) async fn reload(_body: Vec<&str>) -> Result<RoomMessageEventContent>
}
#[cfg(unix)]
pub(super) async fn restart(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
pub(super) async fn restart(_body: Vec<&str>, force: bool) -> Result<RoomMessageEventContent> {
use conduit::utils::sys::current_exe_deleted;
if !force && current_exe_deleted() {
return Err(Error::Err(
"The server cannot be restarted because the executable was tampered with. If this is expected use --force \
to override."
.to_owned(),
));
}
services().server.restart()?;
Ok(RoomMessageEventContent::notice_plain("Restarting server..."))
+10 -19
View File
@@ -18,17 +18,8 @@ pub(super) enum ServerCommand {
/// - Print database memory usage statistics
MemoryUsage,
/// - Clears all of Conduit's database caches with index smaller than the
/// amount
ClearDatabaseCaches {
amount: u32,
},
/// - Clears all of Conduit's service caches with index smaller than the
/// amount
ClearServiceCaches {
amount: u32,
},
/// - Clears all of Conduwuit's caches
ClearCaches,
/// - Performs an online backup of the database (only available for RocksDB
/// at the moment)
@@ -51,7 +42,10 @@ pub(super) enum ServerCommand {
#[cfg(unix)]
/// - Restart the server
Restart,
Restart {
#[arg(short, long)]
force: bool,
},
/// - Shutdown the server
Shutdown,
@@ -62,12 +56,7 @@ pub(super) async fn process(command: ServerCommand, body: Vec<&str>) -> Result<R
ServerCommand::Uptime => uptime(body).await?,
ServerCommand::ShowConfig => show_config(body).await?,
ServerCommand::MemoryUsage => memory_usage(body).await?,
ServerCommand::ClearDatabaseCaches {
amount,
} => clear_database_caches(body, amount).await?,
ServerCommand::ClearServiceCaches {
amount,
} => clear_service_caches(body, amount).await?,
ServerCommand::ClearCaches => clear_caches(body).await?,
ServerCommand::ListBackups => list_backups(body).await?,
ServerCommand::BackupDatabase => backup_database(body).await?,
ServerCommand::ListDatabaseFiles => list_database_files(body).await?,
@@ -77,7 +66,9 @@ pub(super) async fn process(command: ServerCommand, body: Vec<&str>) -> Result<R
#[cfg(conduit_mods)]
ServerCommand::Reload => reload(body).await?,
#[cfg(unix)]
ServerCommand::Restart => restart(body).await?,
ServerCommand::Restart {
force,
} => restart(body, force).await?,
ServerCommand::Shutdown => shutdown(body).await?,
})
}
-14
View File
@@ -1,14 +0,0 @@
use ruma::events::room::message::RoomMessageEventContent;
use crate::Result;
#[cfg_attr(test, derive(Debug))]
#[derive(clap::Subcommand)]
pub(super) enum TesterCommands {
Tester,
}
pub(super) async fn process(command: TesterCommands, _body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
TesterCommands::Tester => RoomMessageEventContent::notice_plain(String::from("completed")),
})
}
+1 -1
View File
@@ -18,7 +18,7 @@ crate-type = [
[features]
element_hacks = []
dev_release_log_level = []
#dev_release_log_level = []
release_max_log_level = [
"tracing/max_level_trace",
"tracing/release_max_level_info",
+17 -145
View File
@@ -1,22 +1,14 @@
use rand::seq::SliceRandom;
use ruma::{
api::{
appservice,
client::{
alias::{create_alias, delete_alias, get_alias},
error::ErrorKind,
},
federation,
api::client::{
alias::{create_alias, delete_alias, get_alias},
error::ErrorKind,
},
OwnedRoomAliasId, OwnedServerName, RoomAliasId, RoomId,
OwnedServerName, RoomAliasId, RoomId,
};
use tracing::debug;
use crate::{
debug_info, debug_warn,
service::{appservice::RegistrationInfo, server_is_ours},
services, Error, Result, Ruma,
};
use crate::{service::server_is_ours, services, Error, Result, Ruma};
/// # `PUT /_matrix/client/v3/directory/room/{roomAlias}`
///
@@ -24,7 +16,7 @@ use crate::{
pub(crate) async fn create_alias_route(body: Ruma<create_alias::v3::Request>) -> Result<create_alias::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
alias_checks(&body.room_alias, &body.appservice_info).await?;
service::rooms::alias::appservice_checks(&body.room_alias, &body.appservice_info).await?;
// this isn't apart of alias_checks or delete alias route because we should
// allow removing forbidden room aliases
@@ -61,7 +53,7 @@ pub(crate) async fn create_alias_route(body: Ruma<create_alias::v3::Request>) ->
pub(crate) async fn delete_alias_route(body: Ruma<delete_alias::v3::Request>) -> Result<delete_alias::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
alias_checks(&body.room_alias, &body.appservice_info).await?;
service::rooms::alias::appservice_checks(&body.room_alias, &body.appservice_info).await?;
if services()
.rooms
@@ -87,124 +79,20 @@ pub(crate) async fn delete_alias_route(body: Ruma<delete_alias::v3::Request>) ->
///
/// Resolve an alias locally or over federation.
pub(crate) async fn get_alias_route(body: Ruma<get_alias::v3::Request>) -> Result<get_alias::v3::Response> {
get_alias_helper(body.body.room_alias, None).await
}
let room_alias = body.body.room_alias;
let servers = None;
pub async fn get_alias_helper(
room_alias: OwnedRoomAliasId, servers: Option<Vec<OwnedServerName>>,
) -> Result<get_alias::v3::Response> {
debug!("get_alias_helper servers: {servers:?}");
if !server_is_ours(room_alias.server_name())
&& (!servers
.as_ref()
.is_some_and(|servers| servers.contains(&services().globals.server_name().to_owned()))
|| servers.as_ref().is_none())
{
let mut response = services()
.sending
.send_federation_request(
room_alias.server_name(),
federation::query::get_room_information::v1::Request {
room_alias: room_alias.clone(),
},
)
.await;
debug!("room alias server_name get_alias_helper response: {response:?}");
if let Err(ref e) = response {
debug_info!(
"Server {} of the original room alias failed to assist in resolving room alias: {e}",
room_alias.server_name()
);
}
if response.as_ref().is_ok_and(|resp| resp.servers.is_empty()) || response.as_ref().is_err() {
if let Some(servers) = servers {
for server in servers {
response = services()
.sending
.send_federation_request(
&server,
federation::query::get_room_information::v1::Request {
room_alias: room_alias.clone(),
},
)
.await;
debug!("Got response from server {server} for room aliases: {response:?}");
if let Ok(ref response) = response {
if !response.servers.is_empty() {
break;
}
debug_warn!(
"Server {server} responded with room aliases, but was empty? Response: {response:?}"
);
}
}
}
}
if let Ok(response) = response {
let room_id = response.room_id;
let mut pre_servers = response.servers;
// since the room alis server responded, insert it into the list
pre_servers.push(room_alias.server_name().into());
let servers = room_available_servers(&room_id, &room_alias, &Some(pre_servers));
debug!(
"room alias servers from federation response for room ID {room_id} and room alias {room_alias}: \
{servers:?}"
);
return Ok(get_alias::v3::Response::new(room_id, servers));
}
return Err(Error::BadRequest(
ErrorKind::NotFound,
"No servers could assist in resolving the room alias",
));
}
let mut room_id = None;
match services().rooms.alias.resolve_local_alias(&room_alias)? {
Some(r) => room_id = Some(r),
None => {
for appservice in services().appservice.read().await.values() {
if appservice.aliases.is_match(room_alias.as_str())
&& matches!(
services()
.sending
.send_appservice_request(
appservice.registration.clone(),
appservice::query::query_room_alias::v1::Request {
room_alias: room_alias.clone(),
},
)
.await,
Ok(Some(_opt_result))
) {
room_id = Some(
services()
.rooms
.alias
.resolve_local_alias(&room_alias)?
.ok_or_else(|| Error::bad_config("Room does not exist."))?,
);
break;
}
}
},
};
let Some(room_id) = room_id else {
let Ok((room_id, pre_servers)) = services()
.rooms
.alias
.resolve_alias(&room_alias, servers.as_ref())
.await
else {
return Err(Error::BadRequest(ErrorKind::NotFound, "Room with alias not found."));
};
let servers = room_available_servers(&room_id, &room_alias, &None);
debug!("room alias servers for room ID {room_id} and room alias {room_alias}");
let servers = room_available_servers(&room_id, &room_alias, &pre_servers);
debug!(?room_alias, ?room_id, "available servers: {servers:?}");
Ok(get_alias::v3::Response::new(room_id, servers))
}
@@ -250,19 +138,3 @@ fn room_available_servers(
servers
}
async fn alias_checks(room_alias: &RoomAliasId, appservice_info: &Option<RegistrationInfo>) -> Result<()> {
if !server_is_ours(room_alias.server_name()) {
return Err(Error::BadRequest(ErrorKind::InvalidParam, "Alias is from another server."));
}
if let Some(ref info) = appservice_info {
if !info.aliases.is_match(room_alias.as_str()) {
return Err(Error::BadRequest(ErrorKind::Exclusive, "Room alias is not in namespace."));
}
} else if services().appservice.is_exclusive_alias(room_alias).await {
return Err(Error::BadRequest(ErrorKind::Exclusive, "Room alias reserved by appservice."));
}
Ok(())
}
+6 -23
View File
@@ -10,11 +10,7 @@ use ruma::{
},
directory::{Filter, PublicRoomJoinRule, PublicRoomsChunk, RoomNetwork},
events::{
room::{
avatar::RoomAvatarEventContent,
create::RoomCreateEventContent,
join_rules::{JoinRule, RoomJoinRulesEventContent},
},
room::join_rules::{JoinRule, RoomJoinRulesEventContent},
StateEventType,
},
uint, ServerName, UInt,
@@ -256,15 +252,10 @@ pub(crate) async fn get_public_rooms_filtered_helper(
avatar_url: services()
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomAvatar, "")?
.map(|s| {
serde_json::from_str(s.content.get())
.map(|c: RoomAvatarEventContent| c.url)
.map_err(|_| Error::bad_database("Invalid room avatar event in database."))
})
.transpose()?
// url is now an Option<String> so we must flatten
.flatten(),
.get_avatar(&room_id)?
.into_option()
.unwrap_or_default()
.url,
join_rule: services()
.rooms
.state_accessor
@@ -287,15 +278,7 @@ pub(crate) async fn get_public_rooms_filtered_helper(
room_type: services()
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomCreate, "")?
.map(|s| {
serde_json::from_str::<RoomCreateEventContent>(s.content.get()).map_err(|e| {
error!("Invalid room create event in database: {}", e);
Error::BadDatabase("Invalid room create event in database.")
})
})
.transpose()?
.and_then(|e| e.room_type),
.get_room_type(&room_id)?,
room_id,
};
Ok(chunk)
+2 -2
View File
@@ -334,7 +334,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool + Send>(
.globals
.bad_query_ratelimiter
.write()
.await
.expect("locked")
.entry(id)
{
hash_map::Entry::Vacant(e) => {
@@ -353,7 +353,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool + Send>(
.globals
.bad_query_ratelimiter
.read()
.await
.expect("locked")
.get(server)
{
// Exponential backoff
+10 -7
View File
@@ -1,3 +1,5 @@
#![allow(deprecated)]
use std::{io::Cursor, sync::Arc, time::Duration};
use image::io::Reader as ImgReader;
@@ -133,7 +135,7 @@ pub(crate) async fn create_content_route(
.media
.create(
Some(sender_user.clone()),
mxc.clone(),
&mxc,
body.filename
.as_ref()
.map(|filename| {
@@ -186,7 +188,7 @@ pub(crate) async fn get_content_route(body: Ruma<get_content::v3::Request>) -> R
content_type,
file,
content_disposition,
}) = services().media.get(mxc.clone()).await?
}) = services().media.get(&mxc).await?
{
let content_disposition = Some(make_content_disposition(&content_type, content_disposition, None));
@@ -264,7 +266,7 @@ pub(crate) async fn get_content_as_filename_route(
content_type,
file,
content_disposition,
}) = services().media.get(mxc.clone()).await?
}) = services().media.get(&mxc).await?
{
let content_disposition = Some(make_content_disposition(
&content_type,
@@ -352,7 +354,7 @@ pub(crate) async fn get_content_thumbnail_route(
}) = services()
.media
.get_thumbnail(
mxc.clone(),
&mxc,
body.width
.try_into()
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Width is invalid."))?,
@@ -396,6 +398,7 @@ pub(crate) async fn get_content_thumbnail_route(
media_id: body.media_id.clone(),
timeout_ms: body.timeout_ms,
allow_redirect: body.allow_redirect,
animated: body.animated,
},
)
.await
@@ -405,7 +408,7 @@ pub(crate) async fn get_content_thumbnail_route(
.media
.upload_thumbnail(
None,
mxc,
&mxc,
None,
get_thumbnail_response.content_type.as_deref(),
body.width.try_into().expect("all UInts are valid u32s"),
@@ -494,7 +497,7 @@ async fn get_remote_content(
.media
.create(
None,
mxc.to_owned(),
mxc,
content_disposition.as_deref(),
content_response.content_type.as_deref(),
&content_response.file,
@@ -520,7 +523,7 @@ async fn download_image(client: &reqwest::Client, url: &str) -> Result<UrlPrevie
services()
.media
.create(None, mxc.clone(), None, None, &image)
.create(None, &mxc, None, None, &image)
.await?;
let (width, height) = match ImgReader::new(Cursor::new(&image)).with_guessed_format() {
+23 -17
View File
@@ -33,10 +33,10 @@ use ruma::{
OwnedUserId, RoomId, RoomVersionId, ServerName, UserId,
};
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
use service::sending::convert_to_outgoing_federation_event;
use tokio::sync::RwLock;
use tracing::{debug, error, info, trace, warn};
use super::get_alias_helper;
use crate::{
client::{update_avatar_url, update_displayname},
service::{
@@ -259,17 +259,24 @@ pub(crate) async fn join_room_by_id_or_alias_route(
(servers, room_id)
},
Err(room_alias) => {
let response = get_alias_helper(room_alias.clone(), Some(body.server_name.clone())).await?;
let response = services()
.rooms
.alias
.resolve_alias(&room_alias, Some(&body.server_name.clone()))
.await?;
let (room_id, mut pre_servers) = response;
banned_room_check(sender_user, Some(&response.room_id), Some(room_alias.server_name()), client).await?;
banned_room_check(sender_user, Some(&room_id), Some(room_alias.server_name()), client).await?;
let mut servers = body.server_name;
servers.extend(response.servers);
if let Some(pre_servers) = &mut pre_servers {
servers.append(pre_servers);
}
servers.extend(
services()
.rooms
.state_cache
.servers_invite_via(&response.room_id)
.servers_invite_via(&room_id)
.filter_map(Result::ok),
);
@@ -277,7 +284,7 @@ pub(crate) async fn join_room_by_id_or_alias_route(
services()
.rooms
.state_cache
.invite_state(sender_user, &response.room_id)?
.invite_state(sender_user, &room_id)?
.unwrap_or_default()
.iter()
.filter_map(|event| serde_json::from_str(event.json().get()).ok())
@@ -287,7 +294,7 @@ pub(crate) async fn join_room_by_id_or_alias_route(
.map(|user| user.server_name().to_owned()),
);
(servers, response.room_id)
(servers, room_id)
},
};
@@ -773,7 +780,7 @@ async fn join_room_by_id_helper_remote(
federation::membership::create_join_event::v2::Request {
room_id: room_id.to_owned(),
event_id: event_id.to_owned(),
pdu: PduEvent::convert_to_outgoing_federation_event(join_event.clone()),
pdu: convert_to_outgoing_federation_event(join_event.clone()),
omit_members: false,
},
)
@@ -1049,7 +1056,7 @@ async fn join_room_by_id_helper_local(
.filter(|user| user_is_local(user))
.collect::<Vec<OwnedUserId>>();
let mut authorized_user: Option<OwnedUserId> = None;
let mut join_authorized_via_users_server: Option<OwnedUserId> = None;
if restriction_rooms.iter().any(|restriction_room_id| {
services()
@@ -1063,10 +1070,9 @@ async fn join_room_by_id_helper_local(
.rooms
.state_accessor
.user_can_invite(room_id, &user, sender_user, &state_lock)
.await
.unwrap_or(false)
{
authorized_user = Some(user);
join_authorized_via_users_server = Some(user);
break;
}
}
@@ -1080,7 +1086,7 @@ async fn join_room_by_id_helper_local(
third_party_invite: None,
blurhash: services().users.blurhash(sender_user)?,
reason: reason.clone(),
join_authorized_via_users_server: authorized_user,
join_authorized_via_users_server,
};
// Try normal join first
@@ -1202,7 +1208,7 @@ async fn join_room_by_id_helper_local(
federation::membership::create_join_event::v2::Request {
room_id: room_id.to_owned(),
event_id: event_id.to_owned(),
pdu: PduEvent::convert_to_outgoing_federation_event(join_event.clone()),
pdu: convert_to_outgoing_federation_event(join_event.clone()),
omit_members: false,
},
)
@@ -1337,7 +1343,7 @@ pub async fn validate_and_add_event_id(
.globals
.bad_event_ratelimiter
.write()
.await
.expect("locked")
.entry(id)
{
Entry::Vacant(e) => {
@@ -1353,7 +1359,7 @@ pub async fn validate_and_add_event_id(
.globals
.bad_event_ratelimiter
.read()
.await
.expect("locked")
.get(&event_id)
{
// Exponential backoff
@@ -1433,7 +1439,7 @@ pub(crate) async fn invite_helper(
room_id: room_id.to_owned(),
event_id: (*pdu.event_id).to_owned(),
room_version: room_version_id.clone(),
event: PduEvent::convert_to_outgoing_federation_event(pdu_json.clone()),
event: convert_to_outgoing_federation_event(pdu_json.clone()),
invite_room_state,
via: services().rooms.state_cache.servers_route_via(room_id).ok(),
},
@@ -1770,7 +1776,7 @@ async fn remote_leave_room(user_id: &UserId, room_id: &RoomId) -> Result<()> {
federation::membership::create_leave_event::v2::Request {
room_id: room_id.to_owned(),
event_id,
pdu: PduEvent::convert_to_outgoing_federation_event(leave_event.clone()),
pdu: convert_to_outgoing_federation_event(leave_event.clone()),
},
)
.await?;
+2 -1
View File
@@ -11,6 +11,7 @@ pub(super) mod keys;
pub(super) mod media;
pub(super) mod membership;
pub(super) mod message;
pub(super) mod openid;
pub(super) mod presence;
pub(super) mod profile;
pub(super) mod push;
@@ -35,7 +36,6 @@ pub(super) mod user_directory;
pub(super) mod voip;
pub(super) use account::*;
pub use alias::get_alias_helper;
pub(super) use alias::*;
pub(super) use backup::*;
pub(super) use capabilities::*;
@@ -49,6 +49,7 @@ pub(super) use media::*;
pub(super) use membership::*;
pub use membership::{join_room_by_id_helper, leave_all_rooms, leave_room, validate_and_add_event_id};
pub(super) use message::*;
pub(super) use openid::*;
pub(super) use presence::*;
pub(super) use profile::*;
pub use profile::{update_all_rooms, update_avatar_url, update_displayname};
+41
View File
@@ -0,0 +1,41 @@
use std::time::Duration;
use conduit::utils;
use ruma::{
api::client::{account, error::ErrorKind},
authentication::TokenType,
};
use super::TOKEN_LENGTH;
use crate::{services, Error, Result, Ruma};
/// # `POST /_matrix/client/v3/user/{userId}/openid/request_token`
///
/// Request an OpenID token to verify identity with third-party services.
///
/// - The token generated is only valid for the OpenID API
pub(crate) async fn create_openid_token_route(
body: Ruma<account::request_openid_token::v3::Request>,
) -> Result<account::request_openid_token::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
if sender_user != &body.user_id {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Not allowed to request OpenID tokens on behalf of other users",
));
}
let access_token = utils::random_string(TOKEN_LENGTH);
let expires_in = services()
.users
.create_openid_token(&body.user_id, &access_token)?;
Ok(account::request_openid_token::v3::Response {
access_token,
token_type: TokenType::Bearer,
matrix_server_name: services().globals.config.server_name.clone(),
expires_in: Duration::from_secs(expires_in),
})
}
+1 -3
View File
@@ -365,9 +365,7 @@ pub(crate) async fn get_pushers_route(body: Ruma<get_pushers::v3::Request>) -> R
pub(crate) async fn set_pushers_route(body: Ruma<set_pusher::v3::Request>) -> Result<set_pusher::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
services()
.pusher
.set_pusher(sender_user, body.action.clone())?;
services().pusher.set_pusher(sender_user, &body.action)?;
Ok(set_pusher::v3::Response::default())
}
+2 -2
View File
@@ -85,7 +85,7 @@ pub(crate) async fn set_read_marker_route(
services().rooms.read_receipt.readreceipt_update(
sender_user,
&body.room_id,
ruma::events::receipt::ReceiptEvent {
&ruma::events::receipt::ReceiptEvent {
content: ruma::events::receipt::ReceiptEventContent(receipt_content),
room_id: body.room_id.clone(),
},
@@ -145,7 +145,7 @@ pub(crate) async fn create_receipt_route(
services().rooms.read_receipt.readreceipt_update(
sender_user,
&body.room_id,
ruma::events::receipt::ReceiptEvent {
&ruma::events::receipt::ReceiptEvent {
content: ruma::events::receipt::ReceiptEventContent(receipt_content),
room_id: body.room_id.clone(),
},
+1 -1
View File
@@ -118,7 +118,7 @@ pub(crate) async fn search_events_route(body: Ruma<search_events::v3::Request>)
};
let mut results = Vec::new();
let next_batch: usize = skip.saturating_add(limit);
let next_batch = skip.saturating_add(limit);
for _ in 0..next_batch {
if let Some(s) = searches
+8 -10
View File
@@ -2,10 +2,10 @@ use std::str::FromStr;
use ruma::{
api::client::{error::ErrorKind, space::get_hierarchy},
uint, UInt,
UInt,
};
use crate::{service::rooms::spaces::PagnationToken, services, Error, Result, Ruma};
use crate::{service::rooms::spaces::PaginationToken, services, Error, Result, Ruma};
/// # `GET /_matrix/client/v1/rooms/{room_id}/hierarchy`
///
@@ -14,12 +14,10 @@ use crate::{service::rooms::spaces::PagnationToken, services, Error, Result, Rum
pub(crate) async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>) -> Result<get_hierarchy::v1::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let limit: usize = body
let limit = body
.limit
.unwrap_or_else(|| uint!(10))
.try_into()
.unwrap_or(10)
.min(100);
.unwrap_or_else(|| UInt::from(10_u32))
.min(UInt::from(100_u32));
let max_depth = body
.max_depth
@@ -29,7 +27,7 @@ pub(crate) async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>)
let key = body
.from
.as_ref()
.and_then(|s| PagnationToken::from_str(s).ok());
.and_then(|s| PaginationToken::from_str(s).ok());
// Should prevent unexpeded behaviour in (bad) clients
if let Some(ref token) = key {
@@ -47,8 +45,8 @@ pub(crate) async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>)
.get_client_hierarchy(
sender_user,
&body.room_id,
limit,
key.map_or(0, |token| token.skip.try_into().unwrap_or(0)),
limit.try_into().unwrap_or(10),
key.map_or(vec![], |token| token.short_room_ids),
max_depth.try_into().unwrap_or(3),
body.suggested_only,
)
+1 -1
View File
@@ -1,5 +1,6 @@
use std::sync::Arc;
use conduit::{error, warn};
use ruma::{
api::client::{
error::ErrorKind,
@@ -16,7 +17,6 @@ use ruma::{
serde::Raw,
EventId, RoomId, UserId,
};
use tracing::{error, log::warn};
use crate::{
service::{pdu::PduBuilder, server_is_ours},
+1 -1
View File
@@ -138,7 +138,7 @@ pub(crate) async fn sync_events_route(
.collect::<Vec<_>>();
// Coalesce database writes for the remainder of this scope.
let _cork = services().globals.db.cork_and_flush();
let _cork = services().db.cork_and_flush();
for room_id in all_joined_rooms {
let room_id = room_id?;
+120 -2
View File
@@ -1,5 +1,8 @@
use axum_client_ip::InsecureClientIp;
use conduit::{warn, RumaResponse};
use ruma::{
api::client::{error::ErrorKind, membership::mutual_rooms},
api::client::{error::ErrorKind, membership::mutual_rooms, room::get_summary},
events::room::member::MembershipState,
OwnedRoomId,
};
@@ -12,8 +15,9 @@ use crate::{services, Error, Result, Ruma};
/// TODO: Implement pagination, currently this just returns everything
///
/// An implementation of [MSC2666](https://github.com/matrix-org/matrix-spec-proposals/pull/2666)
#[tracing::instrument(skip_all, fields(%client), name = "mutual_rooms")]
pub(crate) async fn get_mutual_rooms_route(
body: Ruma<mutual_rooms::unstable::Request>,
InsecureClientIp(client): InsecureClientIp, body: Ruma<mutual_rooms::unstable::Request>,
) -> Result<mutual_rooms::unstable::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@@ -43,3 +47,117 @@ pub(crate) async fn get_mutual_rooms_route(
next_batch_token: None,
})
}
/// # `GET /_matrix/client/unstable/im.nheko.summary/rooms/{roomIdOrAlias}/summary`
///
/// Returns a short description of the state of a room.
///
/// This is the "wrong" endpoint that some implementations/clients may use
/// according to the MSC. Request and response bodies are the same as
/// `get_room_summary`.
///
/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266)
pub(crate) async fn get_room_summary_legacy(
InsecureClientIp(client): InsecureClientIp, body: Ruma<get_summary::msc3266::Request>,
) -> Result<RumaResponse<get_summary::msc3266::Response>> {
get_room_summary(InsecureClientIp(client), body)
.await
.map(RumaResponse)
}
/// # `GET /_matrix/client/unstable/im.nheko.summary/summary/{roomIdOrAlias}`
///
/// Returns a short description of the state of a room.
///
/// TODO: support fetching remote room info if we don't know the room
///
/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266)
#[tracing::instrument(skip_all, fields(%client), name = "room_summary")]
pub(crate) async fn get_room_summary(
InsecureClientIp(client): InsecureClientIp, body: Ruma<get_summary::msc3266::Request>,
) -> Result<get_summary::msc3266::Response> {
let sender_user = body.sender_user.as_ref();
let room_id = services()
.rooms
.alias
.resolve(&body.room_id_or_alias)
.await?;
if !services().rooms.metadata.exists(&room_id)? {
return Err(Error::BadRequest(ErrorKind::NotFound, "Room is unknown to this server"));
}
if sender_user.is_none()
&& !services()
.rooms
.state_accessor
.is_world_readable(&room_id)
.unwrap_or(false)
{
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Room is not world readable, authentication is required",
));
}
Ok(get_summary::msc3266::Response {
room_id: room_id.clone(),
canonical_alias: services()
.rooms
.state_accessor
.get_canonical_alias(&room_id)
.unwrap_or(None),
avatar_url: services()
.rooms
.state_accessor
.get_avatar(&room_id)?
.into_option()
.unwrap_or_default()
.url,
guest_can_join: services().rooms.state_accessor.guest_can_join(&room_id)?,
name: services()
.rooms
.state_accessor
.get_name(&room_id)
.unwrap_or(None),
num_joined_members: services()
.rooms
.state_cache
.room_joined_count(&room_id)
.unwrap_or_default()
.unwrap_or_else(|| {
warn!("Room {room_id} has no member count");
0
})
.try_into()
.expect("user count should not be that big"),
topic: services()
.rooms
.state_accessor
.get_room_topic(&room_id)
.unwrap_or(None),
world_readable: services()
.rooms
.state_accessor
.is_world_readable(&room_id)
.unwrap_or(false),
join_rule: services().rooms.state_accessor.get_join_rule(&room_id)?.0,
room_type: services().rooms.state_accessor.get_room_type(&room_id)?,
room_version: Some(services().rooms.state.get_room_version(&room_id)?),
membership: if let Some(sender_user) = sender_user {
services()
.rooms
.state_accessor
.get_member(&room_id, sender_user)?
.map_or_else(|| Some(MembershipState::Leave), |content| Some(content.membership))
} else {
None
},
encryption: services()
.rooms
.state_accessor
.get_room_encryption(&room_id)
.unwrap_or_else(|_e| None),
})
}
+3 -3
View File
@@ -145,7 +145,7 @@ pub(crate) async fn syncv3_client_server_json() -> Result<impl IntoResponse> {
Ok(Json(serde_json::json!({
"server": server_url,
"version": conduit::version::conduwuit(),
"version": conduit::version(),
})))
}
@@ -155,8 +155,8 @@ pub(crate) async fn syncv3_client_server_json() -> Result<impl IntoResponse> {
/// `/_matrix/federation/v1/version`
pub(crate) async fn conduwuit_server_version() -> Result<impl IntoResponse> {
Ok(Json(serde_json::json!({
"name": "conduwuit",
"version": conduit::version::conduwuit(),
"name": conduit::version::name(),
"version": conduit::version::version(),
})))
}
+34 -10
View File
@@ -9,11 +9,12 @@ use axum_extra::{
use http::uri::PathAndQuery;
use ruma::{
api::{client::error::ErrorKind, AuthScheme, Metadata},
server_util::authorization::XMatrix,
CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
};
use tracing::warn;
use super::{request::Request, xmatrix::XMatrix};
use super::request::Request;
use crate::{service::appservice::RegistrationInfo, services, Error, Result};
enum Token {
@@ -76,12 +77,26 @@ pub(super) async fn auth(
}
match (metadata.authentication, token) {
(_, Token::Invalid) => Err(Error::BadRequest(
ErrorKind::UnknownToken {
soft_logout: false,
},
"Unknown access token.",
)),
(_, Token::Invalid) => {
// OpenID endpoint uses a query param with the same name, drop this once query
// params for user auth are removed from the spec. This is required to make
// integration manager work.
if request.query.access_token.is_some() && request.parts.uri.path().contains("/openid/") {
Ok(Auth {
origin: None,
sender_user: None,
sender_device: None,
appservice_info: None,
})
} else {
Err(Error::BadRequest(
ErrorKind::UnknownToken {
soft_logout: false,
},
"Unknown access token.",
))
}
},
(AuthScheme::AccessToken, Token::Appservice(info)) => Ok(auth_appservice(request, info)?),
(AuthScheme::None | AuthScheme::AccessTokenOptional | AuthScheme::AppserviceToken, Token::Appservice(info)) => {
Ok(Auth {
@@ -188,8 +203,17 @@ async fn auth_server(request: &mut Request, json_body: &Option<CanonicalJsonValu
})?;
let origin = &x_matrix.origin;
let signatures = BTreeMap::from_iter([(x_matrix.key.clone(), CanonicalJsonValue::String(x_matrix.sig))]);
let signatures = BTreeMap::from_iter([(origin.as_str().to_owned(), CanonicalJsonValue::Object(signatures))]);
let signatures =
BTreeMap::from_iter([(x_matrix.key.clone(), CanonicalJsonValue::String(x_matrix.sig.to_string()))]);
let signatures = BTreeMap::from_iter([(
origin.as_str().to_owned(),
CanonicalJsonValue::Object(
signatures
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect(),
),
)]);
let server_destination = services().globals.server_name().as_str().to_owned();
if let Some(destination) = x_matrix.destination.as_ref() {
@@ -225,7 +249,7 @@ async fn auth_server(request: &mut Request, json_body: &Option<CanonicalJsonValu
let keys_result = services()
.rooms
.event_handler
.fetch_signing_keys_for_server(origin, vec![x_matrix.key.clone()])
.fetch_signing_keys_for_server(origin, vec![x_matrix.key.to_string()])
.await;
let keys = keys_result.map_err(|e| {
-1
View File
@@ -1,7 +1,6 @@
mod auth;
mod handler;
mod request;
mod xmatrix;
use std::{mem, ops::Deref};
-61
View File
@@ -1,61 +0,0 @@
use std::str;
use axum_extra::headers::authorization::Credentials;
use ruma::OwnedServerName;
use tracing::debug;
pub(crate) struct XMatrix {
pub(crate) origin: OwnedServerName,
pub(crate) destination: Option<String>,
pub(crate) key: String, // KeyName?
pub(crate) sig: String,
}
impl Credentials for XMatrix {
const SCHEME: &'static str = "X-Matrix";
fn decode(value: &http::HeaderValue) -> Option<Self> {
debug_assert!(
value.as_bytes().starts_with(b"X-Matrix "),
"HeaderValue to decode should start with \"X-Matrix ..\", received = {value:?}",
);
let parameters = str::from_utf8(&value.as_bytes()["X-Matrix ".len()..])
.ok()?
.trim_start();
let mut origin = None;
let mut destination = None;
let mut key = None;
let mut sig = None;
for entry in parameters.split_terminator(',') {
let (name, value) = entry.split_once('=')?;
// It's not at all clear why some fields are quoted and others not in the spec,
// let's simply accept either form for every field.
let value = value
.strip_prefix('"')
.and_then(|rest| rest.strip_suffix('"'))
.unwrap_or(value);
// FIXME: Catch multiple fields of the same name
match name {
"origin" => origin = Some(value.try_into().ok()?),
"key" => key = Some(value.to_owned()),
"sig" => sig = Some(value.to_owned()),
"destination" => destination = Some(value.to_owned()),
_ => debug!("Unexpected field `{name}` in X-Matrix Authorization header"),
}
}
Some(Self {
origin: origin?,
key: key?,
sig: sig?,
destination,
})
}
fn encode(&self) -> http::HeaderValue { todo!() }
}
+7 -1
View File
@@ -39,6 +39,7 @@ pub fn build(router: Router, server: &Server) -> Router {
.ruma_route(client::get_room_aliases_route)
.ruma_route(client::get_filter_route)
.ruma_route(client::create_filter_route)
.ruma_route(client::create_openid_token_route)
.ruma_route(client::set_global_account_data_route)
.ruma_route(client::set_room_account_data_route)
.ruma_route(client::get_global_account_data_route)
@@ -171,7 +172,6 @@ pub fn build(router: Router, server: &Server) -> Router {
.ruma_route(client::get_key_changes_route)
.ruma_route(client::get_pushers_route)
.ruma_route(client::set_pushers_route)
// .ruma_route(client::third_party_route)
.ruma_route(client::upgrade_room_route)
.ruma_route(client::get_threads_route)
.ruma_route(client::get_relating_events_with_rel_type_and_event_type_route)
@@ -179,6 +179,11 @@ pub fn build(router: Router, server: &Server) -> Router {
.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))
@@ -212,6 +217,7 @@ pub fn build(router: Router, server: &Server) -> Router {
.ruma_route(server::get_profile_information_route)
.ruma_route(server::get_keys_route)
.ruma_route(server::claim_keys_route)
.ruma_route(server::get_openid_userinfo_route)
.ruma_route(server::get_hierarchy_route)
.ruma_route(server::well_known_server)
.route("/_conduwuit/local_user_count", get(client::conduwuit_local_user_count))
+4 -2
View File
@@ -1,9 +1,11 @@
use conduit::{Error, Result};
use ruma::{
api::{client::error::ErrorKind, federation::backfill::get_backfill},
uint, user_id, MilliSecondsSinceUnixEpoch,
};
use service::{sending::convert_to_outgoing_federation_event, services};
use crate::{services, Error, PduEvent, Result, Ruma};
use crate::Ruma;
/// # `GET /_matrix/federation/v1/backfill/<room_id>`
///
@@ -62,7 +64,7 @@ pub(crate) async fn get_backfill_route(body: Ruma<get_backfill::v1::Request>) ->
})
.map(|(_, pdu)| services().rooms.timeline.get_pdu_json(&pdu.event_id))
.filter_map(|r| r.ok().flatten())
.map(PduEvent::convert_to_outgoing_federation_event)
.map(convert_to_outgoing_federation_event)
.collect();
Ok(get_backfill::v1::Response {
+4 -2
View File
@@ -1,9 +1,11 @@
use conduit::{Error, Result};
use ruma::{
api::{client::error::ErrorKind, federation::event::get_event},
MilliSecondsSinceUnixEpoch, RoomId,
};
use service::{sending::convert_to_outgoing_federation_event, services};
use crate::{services, Error, PduEvent, Result, Ruma};
use crate::Ruma;
/// # `GET /_matrix/federation/v1/event/{eventId}`
///
@@ -48,6 +50,6 @@ pub(crate) async fn get_event_route(body: Ruma<get_event::v1::Request>) -> Resul
Ok(get_event::v1::Response {
origin: services().globals.server_name().to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
pdu: PduEvent::convert_to_outgoing_federation_event(event),
pdu: convert_to_outgoing_federation_event(event),
})
}
+4 -2
View File
@@ -1,11 +1,13 @@
use std::sync::Arc;
use conduit::{Error, Result};
use ruma::{
api::{client::error::ErrorKind, federation::authorization::get_event_authorization},
RoomId,
};
use service::{sending::convert_to_outgoing_federation_event, services};
use crate::{services, Error, PduEvent, Result, Ruma};
use crate::Ruma;
/// # `GET /_matrix/federation/v1/event_auth/{roomId}/{eventId}`
///
@@ -57,7 +59,7 @@ pub(crate) async fn get_event_authorization_route(
Ok(get_event_authorization::v1::Response {
auth_chain: auth_chain_ids
.filter_map(|id| services().rooms.timeline.get_pdu_json(&id).ok()?)
.map(PduEvent::convert_to_outgoing_federation_event)
.map(convert_to_outgoing_federation_event)
.collect(),
})
}
+4 -2
View File
@@ -1,9 +1,11 @@
use conduit::{Error, Result};
use ruma::{
api::{client::error::ErrorKind, federation::event::get_missing_events},
OwnedEventId, RoomId,
};
use service::{sending::convert_to_outgoing_federation_event, services};
use crate::{services, Error, PduEvent, Result, Ruma};
use crate::Ruma;
/// # `POST /_matrix/federation/v1/get_missing_events/{roomId}`
///
@@ -79,7 +81,7 @@ pub(crate) async fn get_missing_events_route(
)
.map_err(|_| Error::bad_database("Invalid prev_events in event in database."))?,
);
events.push(PduEvent::convert_to_outgoing_federation_event(pdu));
events.push(convert_to_outgoing_federation_event(pdu));
}
i = i.saturating_add(1);
}
+4 -8
View File
@@ -1,18 +1,14 @@
use axum_client_ip::InsecureClientIp;
use conduit::{utils, warn, Error, PduEvent, Result};
use ruma::{
api::{client::error::ErrorKind, federation::membership::create_invite},
events::room::member::{MembershipState, RoomMemberEventContent},
serde::JsonObject,
CanonicalJsonValue, EventId, OwnedUserId,
};
use tracing::warn;
use service::{sending::convert_to_outgoing_federation_event, server_is_ours, services};
use crate::{
service::server_is_ours,
services,
utils::{self},
Error, PduEvent, Result, Ruma,
};
use crate::Ruma;
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
///
@@ -176,6 +172,6 @@ pub(crate) async fn create_invite_route(
}
Ok(create_invite::v2::Response {
event: PduEvent::convert_to_outgoing_federation_event(signed_event),
event: convert_to_outgoing_federation_event(signed_event),
})
}
+97 -85
View File
@@ -7,15 +7,12 @@ use ruma::{
},
StateEventType, TimelineEventType,
},
RoomVersionId,
RoomId, RoomVersionId, UserId,
};
use serde_json::value::to_raw_value;
use tracing::warn;
use crate::{
service::{pdu::PduBuilder, user_is_local},
services, Error, Result, Ruma,
};
use crate::{service::pdu::PduBuilder, services, Error, Result, Ruma};
/// # `GET /_matrix/federation/v1/make_join/{roomId}/{userId}`
///
@@ -72,95 +69,42 @@ pub(crate) async fn create_join_event_template_route(
}
}
let room_version_id = services().rooms.state.get_room_version(&body.room_id)?;
let state_lock = services()
.globals
.roomid_mutex_state
.lock(&body.room_id)
.await;
let join_rules_event =
services()
let join_authorized_via_users_server = if (services()
.rooms
.state_cache
.is_left(&body.user_id, &body.room_id)
.unwrap_or(true))
&& user_can_perform_restricted_join(&body.user_id, &body.room_id, &room_version_id)?
{
let auth_user = services()
.rooms
.state_accessor
.room_state_get(&body.room_id, &StateEventType::RoomJoinRules, "")?;
let join_rules_event_content: Option<RoomJoinRulesEventContent> = join_rules_event
.as_ref()
.map(|join_rules_event| {
serde_json::from_str(join_rules_event.content.get())
.map_err(|_| Error::bad_database("Invalid join rules event in db."))
})
.transpose()?;
let join_authorized_via_users_server = if let Some(join_rules_event_content) = join_rules_event_content {
if let JoinRule::Restricted(r) | JoinRule::KnockRestricted(r) = join_rules_event_content.join_rule {
if r.allow
.iter()
.filter_map(|rule| {
if let AllowRule::RoomMembership(membership) = rule {
Some(membership)
} else {
None
}
})
.any(|m| {
services()
.rooms
.state_cache
.is_joined(&body.user_id, &m.room_id)
.unwrap_or(false)
}) {
if services()
.state_cache
.room_members(&body.room_id)
.filter_map(Result::ok)
.filter(|user| user.server_name() == services().globals.server_name())
.find(|user| {
services()
.rooms
.state_cache
.is_left(&body.user_id, &body.room_id)
.unwrap_or(true)
{
let members: Vec<_> = services()
.rooms
.state_cache
.room_members(&body.room_id)
.filter_map(Result::ok)
.filter(|user| user_is_local(user))
.collect();
.state_accessor
.user_can_invite(&body.room_id, user, &body.user_id, &state_lock)
.unwrap_or(false)
});
let mut auth_user = None;
for user in members {
if services()
.rooms
.state_accessor
.user_can_invite(&body.room_id, &user, &body.user_id, &state_lock)
.await
.unwrap_or(false)
{
auth_user = Some(user);
break;
}
}
if auth_user.is_some() {
auth_user
} else {
return Err(Error::BadRequest(
ErrorKind::UnableToGrantJoin,
"No user on this server is able to assist in joining.",
));
}
} else {
// If the user has any state other than leave, either:
// - the auth_check will deny them (ban, knock - (until/unless MSC4123 is
// merged))
// - they are able to join via other methods (invite)
// - they are already in the room (join)
None
}
} else {
return Err(Error::BadRequest(
ErrorKind::UnableToAuthorizeJoin,
"User is not known to be in any required room.",
));
}
if auth_user.is_some() {
auth_user
} else {
None
return Err(Error::BadRequest(
ErrorKind::UnableToGrantJoin,
"No user on this server is able to assist in joining.",
));
}
} else {
None
@@ -231,3 +175,71 @@ pub(crate) async fn create_join_event_template_route(
event: to_raw_value(&pdu_json).expect("CanonicalJson can be serialized to JSON"),
})
}
/// Checks whether the given user can join the given room via a restricted join.
/// This doesn't check the current user's membership. This should be done
/// externally, either by using the state cache or attempting to authorize the
/// event.
pub(crate) fn user_can_perform_restricted_join(
user_id: &UserId, room_id: &RoomId, room_version_id: &RoomVersionId,
) -> Result<bool> {
let join_rules_event =
services()
.rooms
.state_accessor
.room_state_get(room_id, &StateEventType::RoomJoinRules, "")?;
let Some(join_rules_event_content) = join_rules_event
.as_ref()
.map(|join_rules_event| {
serde_json::from_str::<RoomJoinRulesEventContent>(join_rules_event.content.get()).map_err(|e| {
warn!("Invalid join rules event in database: {e}");
Error::bad_database("Invalid join rules event in database")
})
})
.transpose()?
else {
return Ok(false);
};
if matches!(
room_version_id,
RoomVersionId::V1
| RoomVersionId::V2
| RoomVersionId::V3
| RoomVersionId::V4
| RoomVersionId::V5
| RoomVersionId::V6
| RoomVersionId::V7
) {
return Ok(false);
}
let (JoinRule::Restricted(r) | JoinRule::KnockRestricted(r)) = join_rules_event_content.join_rule else {
return Ok(false);
};
if r.allow
.iter()
.filter_map(|rule| {
if let AllowRule::RoomMembership(membership) = rule {
Some(membership)
} else {
None
}
})
.any(|m| {
services()
.rooms
.state_cache
.is_joined(user_id, &m.room_id)
.unwrap_or(false)
}) {
Ok(true)
} else {
Err(Error::BadRequest(
ErrorKind::UnableToAuthorizeJoin,
"User is not known to be in any required room.",
))
}
}
+2
View File
@@ -7,6 +7,7 @@ pub(super) mod invite;
pub(super) mod key;
pub(super) mod make_join;
pub(super) mod make_leave;
pub(super) mod openid;
pub(super) mod publicrooms;
pub(super) mod query;
pub(super) mod send;
@@ -27,6 +28,7 @@ pub(super) use invite::*;
pub(super) use key::*;
pub(super) use make_join::*;
pub(super) use make_leave::*;
pub(super) use openid::*;
pub(super) use publicrooms::*;
pub(super) use query::*;
pub(super) use send::*;
+16
View File
@@ -0,0 +1,16 @@
use ruma::api::federation::openid::get_openid_userinfo;
use crate::{services, Result, Ruma};
/// # `GET /_matrix/federation/v1/openid/userinfo`
///
/// Get information about the user that generated the OpenID token.
pub(crate) async fn get_openid_userinfo_route(
body: Ruma<get_openid_userinfo::v1::Request>,
) -> Result<get_openid_userinfo::v1::Response> {
Ok(get_openid_userinfo::v1::Response::new(
services()
.users
.find_from_openid_token(&body.access_token)?,
))
}
+321 -247
View File
@@ -1,4 +1,4 @@
use std::{collections::BTreeMap, time::Instant};
use std::{collections::BTreeMap, net::IpAddr, time::Instant};
use axum_client_ip::InsecureClientIp;
use conduit::debug_warn;
@@ -6,12 +6,16 @@ use ruma::{
api::{
client::error::ErrorKind,
federation::transactions::{
edu::{DeviceListUpdateContent, DirectDeviceContent, Edu, SigningKeyUpdateContent},
edu::{
DeviceListUpdateContent, DirectDeviceContent, Edu, PresenceContent, ReceiptContent,
SigningKeyUpdateContent, TypingContent,
},
send_transaction_message,
},
},
events::receipt::{ReceiptEvent, ReceiptEventContent, ReceiptType},
to_device::DeviceIdOrAllDevices,
OwnedEventId, ServerName,
};
use tokio::sync::RwLock;
use tracing::{debug, error, trace, warn};
@@ -23,6 +27,8 @@ use crate::{
Error, Result, Ruma,
};
type ResolvedMap = BTreeMap<OwnedEventId, Result<(), Error>>;
/// # `PUT /_matrix/federation/v1/send/{txnId}`
///
/// Push EDUs and PDUs to this server.
@@ -53,15 +59,39 @@ pub(crate) async fn send_transaction_message_route(
));
}
// This is all the auth_events that have been recursively fetched so they don't
// have to be deserialized over and over again.
// TODO: make this persist across requests but not in a DB Tree (in globals?)
// TODO: This could potentially also be some sort of trie (suffix tree) like
// structure so that once an auth event is known it would know (using indexes
// maybe) all of the auth events that it references.
// let mut auth_cache = EventMap::new();
let txn_start_time = Instant::now();
trace!(
pdus = ?body.pdus.len(),
edus = ?body.edus.len(),
elapsed = ?txn_start_time.elapsed(),
id = ?body.transaction_id,
origin =?body.origin,
"Starting txn",
);
let resolved_map = handle_pdus(&client, &body, origin, &txn_start_time).await?;
handle_edus(&client, &body, origin).await?;
debug!(
pdus = ?body.pdus.len(),
edus = ?body.edus.len(),
elapsed = ?txn_start_time.elapsed(),
id = ?body.transaction_id,
origin =?body.origin,
"Finished txn",
);
Ok(send_transaction_message::v1::Response {
pdus: resolved_map
.into_iter()
.map(|(e, r)| (e, r.map_err(|e| e.sanitized_error())))
.collect(),
})
}
async fn handle_pdus(
_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 {
parsed_pdus.push(match parse_incoming_pdu(pdu) {
@@ -76,15 +106,6 @@ pub(crate) async fn send_transaction_message_route(
// and hashes checks
}
trace!(
pdus = ?parsed_pdus.len(),
edus = ?body.edus.len(),
elapsed = ?txn_start_time.elapsed(),
id = ?body.transaction_id,
origin =?body.origin,
"Starting txn",
);
// We go through all the signatures we see on the PDUs and fetch the
// corresponding signing keys
let pub_key_map = RwLock::new(BTreeMap::new());
@@ -94,9 +115,7 @@ pub(crate) async fn send_transaction_message_route(
.event_handler
.fetch_required_signing_keys(parsed_pdus.iter().map(|(_event_id, event, _room_id)| event), &pub_key_map)
.await
.unwrap_or_else(|e| {
warn!("Could not fetch all signatures for PDUs from {origin}: {:?}", e);
});
.unwrap_or_else(|e| warn!("Could not fetch all signatures for PDUs from {origin}: {e:?}"));
debug!(
elapsed = ?txn_start_time.elapsed(),
@@ -133,244 +152,299 @@ pub(crate) async fn send_transaction_message_route(
for pdu in &resolved_map {
if let Err(e) = pdu.1 {
if matches!(e, Error::BadRequest(ErrorKind::NotFound, _)) {
warn!("Incoming PDU failed {:?}", pdu);
warn!("Incoming PDU failed {pdu:?}");
}
}
}
Ok(resolved_map)
}
async fn handle_edus(
client: &IpAddr, body: &Ruma<send_transaction_message::v1::Request>, origin: &ServerName,
) -> Result<()> {
for edu in body
.edus
.iter()
.filter_map(|edu| serde_json::from_str::<Edu>(edu.json().get()).ok())
{
match edu {
Edu::Presence(presence) => {
if !services().globals.allow_incoming_presence() {
continue;
}
for update in presence.push {
if update.user_id.server_name() != origin {
debug_warn!(%update.user_id, %origin, "received presence EDU for user not belonging to origin");
continue;
}
services().presence.set_presence(
&update.user_id,
&update.presence,
Some(update.currently_active),
Some(update.last_active_ago),
update.status_msg.clone(),
)?;
}
},
Edu::Receipt(receipt) => {
if !services().globals.allow_incoming_read_receipts() {
continue;
}
for (room_id, room_updates) in receipt.receipts {
if services()
.rooms
.event_handler
.acl_check(origin, &room_id)
.is_err()
{
debug_warn!(%origin, %room_id, "received read receipt EDU from ACL'd server");
continue;
}
for (user_id, user_updates) in room_updates.read {
if user_id.server_name() != origin {
debug_warn!(%user_id, %origin, "received read receipt EDU for user not belonging to origin");
continue;
}
if services()
.rooms
.state_cache
.room_members(&room_id)
.filter_map(Result::ok)
.any(|member| member.server_name() == user_id.server_name())
{
for event_id in &user_updates.event_ids {
let user_receipts = BTreeMap::from([(user_id.clone(), user_updates.data.clone())]);
let receipts = BTreeMap::from([(ReceiptType::Read, user_receipts)]);
let receipt_content = BTreeMap::from([(event_id.to_owned(), receipts)]);
let event = ReceiptEvent {
content: ReceiptEventContent(receipt_content),
room_id: room_id.clone(),
};
services()
.rooms
.read_receipt
.readreceipt_update(&user_id, &room_id, event)?;
}
} else {
debug_warn!(%user_id, %room_id, %origin, "received read receipt EDU from server who does not have a single member from their server in the room");
continue;
}
}
}
},
Edu::Typing(typing) => {
if !services().globals.config.allow_incoming_typing {
continue;
}
if typing.user_id.server_name() != origin {
debug_warn!(%typing.user_id, %origin, "received typing EDU for user not belonging to origin");
continue;
}
if services()
.rooms
.event_handler
.acl_check(typing.user_id.server_name(), &typing.room_id)
.is_err()
{
debug_warn!(%typing.user_id, %typing.room_id, %origin, "received typing EDU for ACL'd user's server");
continue;
}
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()
.globals
.config
.typing_federation_timeout_s
.saturating_mul(1000),
);
services()
.rooms
.typing
.typing_add(&typing.user_id, &typing.room_id, timeout)
.await?;
} else {
services()
.rooms
.typing
.typing_remove(&typing.user_id, &typing.room_id)
.await?;
}
} else {
debug_warn!(%typing.user_id, %typing.room_id, %origin, "received typing EDU for user not in room");
continue;
}
},
Edu::DeviceListUpdate(DeviceListUpdateContent {
user_id,
..
}) => {
if user_id.server_name() != origin {
debug_warn!(%user_id, %origin, "received device list update EDU for user not belonging to origin");
continue;
}
services().users.mark_device_key_update(&user_id)?;
},
Edu::DirectToDevice(DirectDeviceContent {
sender,
ev_type,
message_id,
messages,
}) => {
if sender.server_name() != origin {
debug_warn!(%sender, %origin, "received direct to device EDU for user not belonging to origin");
continue;
}
// Check if this is a new transaction id
if services()
.transaction_ids
.existing_txnid(&sender, None, &message_id)?
.is_some()
{
continue;
}
for (target_user_id, map) in &messages {
for (target_device_id_maybe, event) in map {
match target_device_id_maybe {
DeviceIdOrAllDevices::DeviceId(target_device_id) => {
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")
})?,
)?;
},
DeviceIdOrAllDevices::AllDevices => {
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")
})?,
)?;
}
},
}
}
}
// Save transaction id with empty data
services()
.transaction_ids
.add_txnid(&sender, None, &message_id, &[])?;
},
Edu::SigningKeyUpdate(SigningKeyUpdateContent {
user_id,
master_key,
self_signing_key,
}) => {
if user_id.server_name() != origin {
debug_warn!(%user_id, %origin, "received signing key update EDU from server that does not belong to user's server");
continue;
}
if let Some(master_key) = master_key {
services()
.users
.add_cross_signing_keys(&user_id, &master_key, &self_signing_key, &None, true)?;
}
},
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::_Custom(ref _custom) => {
debug_warn!(?edu, "received custom/unknown EDU");
debug_warn!(?body.edus, "received custom/unknown EDU");
},
}
}
debug!(
pdus = ?body.pdus.len(),
edus = ?body.edus.len(),
elapsed = ?txn_start_time.elapsed(),
id = ?body.transaction_id,
origin =?body.origin,
"Finished txn",
);
Ok(send_transaction_message::v1::Response {
pdus: resolved_map
.into_iter()
.map(|(e, r)| (e, r.map_err(|e| e.sanitized_error())))
.collect(),
})
Ok(())
}
async fn handle_edu_presence(_client: &IpAddr, origin: &ServerName, presence: PresenceContent) -> Result<()> {
if !services().globals.allow_incoming_presence() {
return Ok(());
}
for update in presence.push {
if update.user_id.server_name() != origin {
debug_warn!(
%update.user_id, %origin,
"received presence EDU for user not belonging to origin"
);
continue;
}
services().presence.set_presence(
&update.user_id,
&update.presence,
Some(update.currently_active),
Some(update.last_active_ago),
update.status_msg.clone(),
)?;
}
Ok(())
}
async fn handle_edu_receipt(_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()
.rooms
.event_handler
.acl_check(origin, &room_id)
.is_err()
{
debug_warn!(
%origin, %room_id,
"received read receipt EDU from ACL'd server"
);
continue;
}
for (user_id, user_updates) in room_updates.read {
if user_id.server_name() != origin {
debug_warn!(
%user_id, %origin,
"received read receipt EDU for user not belonging to origin"
);
continue;
}
if services()
.rooms
.state_cache
.room_members(&room_id)
.filter_map(Result::ok)
.any(|member| member.server_name() == user_id.server_name())
{
for event_id in &user_updates.event_ids {
let user_receipts = BTreeMap::from([(user_id.clone(), user_updates.data.clone())]);
let receipts = BTreeMap::from([(ReceiptType::Read, user_receipts)]);
let receipt_content = BTreeMap::from([(event_id.to_owned(), receipts)]);
let event = ReceiptEvent {
content: ReceiptEventContent(receipt_content),
room_id: room_id.clone(),
};
services()
.rooms
.read_receipt
.readreceipt_update(&user_id, &room_id, &event)?;
}
} else {
debug_warn!(
%user_id, %room_id, %origin,
"received read receipt EDU from server who does not have a member in the room",
);
continue;
}
}
}
Ok(())
}
async fn handle_edu_typing(_client: &IpAddr, origin: &ServerName, typing: TypingContent) -> Result<()> {
if !services().globals.config.allow_incoming_typing {
return Ok(());
}
if typing.user_id.server_name() != origin {
debug_warn!(
%typing.user_id, %origin,
"received typing EDU for user not belonging to origin"
);
return Ok(());
}
if services()
.rooms
.event_handler
.acl_check(typing.user_id.server_name(), &typing.room_id)
.is_err()
{
debug_warn!(
%typing.user_id, %typing.room_id, %origin,
"received typing EDU for ACL'd user's server"
);
return Ok(());
}
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()
.globals
.config
.typing_federation_timeout_s
.saturating_mul(1000),
);
services()
.rooms
.typing
.typing_add(&typing.user_id, &typing.room_id, timeout)
.await?;
} else {
services()
.rooms
.typing
.typing_remove(&typing.user_id, &typing.room_id)
.await?;
}
} else {
debug_warn!(
%typing.user_id, %typing.room_id, %origin,
"received typing EDU for user not in room"
);
return Ok(());
}
Ok(())
}
async fn handle_edu_device_list_update(
_client: &IpAddr, origin: &ServerName, content: DeviceListUpdateContent,
) -> Result<()> {
let DeviceListUpdateContent {
user_id,
..
} = content;
if user_id.server_name() != origin {
debug_warn!(
%user_id, %origin,
"received device list update EDU for user not belonging to origin"
);
return Ok(());
}
services().users.mark_device_key_update(&user_id)?;
Ok(())
}
async fn handle_edu_direct_to_device(
_client: &IpAddr, origin: &ServerName, content: DirectDeviceContent,
) -> Result<()> {
let DirectDeviceContent {
sender,
ev_type,
message_id,
messages,
} = content;
if sender.server_name() != origin {
debug_warn!(
%sender, %origin,
"received direct to device EDU for user not belonging to origin"
);
return Ok(());
}
// Check if this is a new transaction id
if services()
.transaction_ids
.existing_txnid(&sender, None, &message_id)?
.is_some()
{
return Ok(());
}
for (target_user_id, map) in &messages {
for (target_device_id_maybe, event) in map {
match target_device_id_maybe {
DeviceIdOrAllDevices::DeviceId(target_device_id) => {
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")
})?,
)?;
},
DeviceIdOrAllDevices::AllDevices => {
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"))?,
)?;
}
},
}
}
}
// Save transaction id with empty data
services()
.transaction_ids
.add_txnid(&sender, None, &message_id, &[])?;
Ok(())
}
async fn handle_edu_signing_key_update(
_client: &IpAddr, origin: &ServerName, content: SigningKeyUpdateContent,
) -> Result<()> {
let SigningKeyUpdateContent {
user_id,
master_key,
self_signing_key,
} = content;
if user_id.server_name() != origin {
debug_warn!(
%user_id, %origin,
"received signing key update EDU from server that does not belong to user's server"
);
return Ok(());
}
if let Some(master_key) = master_key {
services()
.users
.add_cross_signing_keys(&user_id, &master_key, &self_signing_key, &None, true)?;
}
Ok(())
}
+37 -30
View File
@@ -2,16 +2,23 @@
use std::collections::BTreeMap;
use conduit::{Error, Result};
use ruma::{
api::{client::error::ErrorKind, federation::membership::create_join_event},
events::{room::member::MembershipState, StateEventType},
events::{
room::member::{MembershipState, RoomMemberEventContent},
StateEventType,
},
CanonicalJsonValue, OwnedServerName, OwnedUserId, RoomId, ServerName,
};
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
use service::{
pdu::gen_event_id_canonical_json, sending::convert_to_outgoing_federation_event, services, user_is_local,
};
use tokio::sync::RwLock;
use tracing::warn;
use crate::{service::pdu::gen_event_id_canonical_json, services, Error, PduEvent, Result, Ruma};
use crate::Ruma;
/// helper method for /send_join v1 and v2
async fn create_join_event(
@@ -63,22 +70,16 @@ async fn create_join_event(
));
}
let content = value
.get("content")
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Event missing content property."))?
.as_object()
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Event content is empty or invalid."))?;
let membership: MembershipState = serde_json::from_value(
content
.get("membership")
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Event content missing membership property."))?
let content: RoomMemberEventContent = serde_json::from_value(
value
.get("content")
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Event missing content property"))?
.clone()
.into(),
)
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Event has an invalid membership state."))?;
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Event content is empty or invalid"))?;
if membership != MembershipState::Join {
if content.membership != MembershipState::Join {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Not allowed to send a non-join membership event to join endpoint.",
@@ -122,15 +123,27 @@ async fn create_join_event(
ErrorKind::InvalidParam,
"State key does not match sender user",
));
};
if content
.join_authorized_via_users_server
.is_some_and(|user| user_is_local(&user))
&& super::user_can_perform_restricted_join(&sender, room_id, &room_version_id).unwrap_or_default()
{
ruma::signatures::hash_and_sign_event(
services().globals.server_name().as_str(),
services().globals.keypair(),
&mut value,
&room_version_id,
)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Failed to sign event."))?;
}
ruma::signatures::hash_and_sign_event(
services().globals.server_name().as_str(),
services().globals.keypair(),
&mut value,
&room_version_id,
)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Failed to sign event."))?;
services()
.rooms
.event_handler
.fetch_required_signing_keys([&value], &pub_key_map)
.await?;
let origin: OwnedServerName = serde_json::from_value(
serde_json::to_value(
@@ -142,12 +155,6 @@ async fn create_join_event(
)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "origin is not a server name."))?;
services()
.rooms
.event_handler
.fetch_required_signing_keys([&value], &pub_key_map)
.await?;
let mutex_lock = services()
.globals
.roomid_mutex_federation
@@ -177,16 +184,16 @@ async fn create_join_event(
Ok(create_join_event::v1::RoomState {
auth_chain: auth_chain_ids
.filter_map(|id| services().rooms.timeline.get_pdu_json(&id).ok().flatten())
.map(PduEvent::convert_to_outgoing_federation_event)
.map(convert_to_outgoing_federation_event)
.collect(),
state: state_ids
.iter()
.filter_map(|(_, id)| services().rooms.timeline.get_pdu_json(id).ok().flatten())
.map(PduEvent::convert_to_outgoing_federation_event)
.map(convert_to_outgoing_federation_event)
.collect(),
// Event field is required if the room version supports restricted join rules.
event: Some(
to_raw_value(&CanonicalJsonValue::Object(value.clone()))
to_raw_value(&CanonicalJsonValue::Object(value))
.expect("To raw json should not fail since only change was adding signature"),
),
})
+10 -13
View File
@@ -4,7 +4,10 @@ use std::collections::BTreeMap;
use ruma::{
api::{client::error::ErrorKind, federation::membership::create_leave_event},
events::{room::member::MembershipState, StateEventType},
events::{
room::member::{MembershipState, RoomMemberEventContent},
StateEventType,
},
OwnedServerName, OwnedUserId, RoomId, ServerName,
};
use serde_json::value::RawValue as RawJsonValue;
@@ -62,22 +65,16 @@ async fn create_leave_event(origin: &ServerName, room_id: &RoomId, pdu: &RawJson
));
};
let content = value
.get("content")
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Event missing content property."))?
.as_object()
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Event content not an object."))?;
let membership: MembershipState = serde_json::from_value(
content
.get("membership")
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Event membership is missing."))?
let content: RoomMemberEventContent = serde_json::from_value(
value
.get("content")
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Event missing content property"))?
.clone()
.into(),
)
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Event membership state is not valid."))?;
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Event content is empty or invalid"))?;
if membership != MembershipState::Leave {
if content.membership != MembershipState::Leave {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Not allowed to send a non-leave membership event to leave endpoint.",
+5 -3
View File
@@ -1,8 +1,10 @@
use std::sync::Arc;
use conduit::{Error, Result};
use ruma::api::{client::error::ErrorKind, federation::event::get_room_state};
use service::{sending::convert_to_outgoing_federation_event, services};
use crate::{services, Error, PduEvent, Result, Ruma};
use crate::Ruma;
/// # `GET /_matrix/federation/v1/state/{roomId}`
///
@@ -42,7 +44,7 @@ pub(crate) async fn get_room_state_route(
.await?
.into_values()
.map(|id| {
PduEvent::convert_to_outgoing_federation_event(
convert_to_outgoing_federation_event(
services()
.rooms
.timeline
@@ -67,7 +69,7 @@ pub(crate) async fn get_room_state_route(
.timeline
.get_pdu_json(&id)
.ok()?
.map(PduEvent::convert_to_outgoing_federation_event)
.map(convert_to_outgoing_federation_event)
})
.collect(),
pdus,
+2 -2
View File
@@ -10,8 +10,8 @@ pub(crate) async fn get_server_version_route(
) -> Result<get_server_version::v1::Response> {
Ok(get_server_version::v1::Response {
server: Some(get_server_version::v1::Server {
name: Some("Conduwuit".to_owned()),
version: Some(conduit::version::conduwuit()),
name: Some(conduit::version::name().into()),
version: Some(conduit::version::version().into()),
}),
})
}
+7 -24
View File
@@ -17,26 +17,17 @@ crate-type = [
]
[features]
dev_release_log_level = []
#dev_release_log_level = []
release_max_log_level = [
"tracing/max_level_trace",
"tracing/release_max_level_info",
"log/max_level_trace",
"log/release_max_level_info",
]
sqlite = [
"dep:rusqlite",
"dep:parking_lot",
"dep:thread_local",
]
rocksdb = [
"dep:rust-rocksdb",
]
jemalloc = [
"dep:tikv-jemalloc-sys",
"dep:tikv-jemalloc-ctl",
"dep:tikv-jemallocator",
"rust-rocksdb/jemalloc",
]
jemalloc_prof = [
"tikv-jemalloc-sys/profiling",
@@ -44,25 +35,25 @@ jemalloc_prof = [
hardened_malloc = [
"dep:hardened_malloc-rs"
]
io_uring = [
"rust-rocksdb/io-uring",
]
zstd_compression = [
"rust-rocksdb/zstd",
]
gzip_compression = [
"reqwest/gzip",
]
brotli_compression = [
"reqwest/brotli",
]
zstd_compression =[]
perf_measurements = []
sentry_telemetry = []
# these do nothing, these are purely for informing users to update their build scripts if they use one
rocksdb = []
sha256_media = []
[dependencies]
argon2.workspace = true
axum.workspace = true
bytes.workspace = true
chrono.workspace = true
either.workspace = true
figment.workspace = true
http-body-util.workspace = true
@@ -72,24 +63,16 @@ ipaddress.workspace = true
itertools.workspace = true
libloading.workspace = true
log.workspace = true
parking_lot.optional = true
parking_lot.workspace = true
rand.workspace = true
regex.workspace = true
reqwest.workspace = true
ring.workspace = true
ruma.workspace = true
rusqlite.optional = true
rusqlite.workspace = true
rust-rocksdb.optional = true
rust-rocksdb.workspace = true
sanitize-filename.workspace = true
serde_json.workspace = true
serde_regex.workspace = true
serde.workspace = true
thiserror.workspace = true
thread_local.optional = true
thread_local.workspace = true
tikv-jemallocator.optional = true
tikv-jemallocator.workspace = true
tikv-jemalloc-ctl.optional = true
+2
View File
@@ -1,3 +1,5 @@
//! hmalloc allocator
#[global_allocator]
static HMALLOC: hardened_malloc_rs::HardenedMalloc = hardened_malloc_rs::HardenedMalloc;
+3 -1
View File
@@ -1,3 +1,5 @@
//! jemalloc allocator
use std::ffi::{c_char, c_void};
use tikv_jemalloc_ctl as mallctl;
@@ -17,7 +19,7 @@ pub fn memory_usage() -> String {
let resident = stats::resident::read().unwrap_or_default() as f64 / 1024.0 / 1024.0;
let retained = stats::retained::read().unwrap_or_default() as f64 / 1024.0 / 1024.0;
format!(
" allocated: {allocated:.2} MiB\n active: {active:.2} MiB\n mapped: {mapped:.2} MiB\n metadata: {metadata:.2} \
"allocated: {allocated:.2} MiB\n active: {active:.2} MiB\n mapped: {mapped:.2} MiB\n metadata: {metadata:.2} \
MiB\n resident: {resident:.2} MiB\n retained: {retained:.2} MiB\n "
)
}
+8 -18
View File
@@ -1,27 +1,17 @@
//! Integration with allocators
// jemalloc
#[cfg(all(not(target_env = "msvc"), feature = "jemalloc", not(feature = "hardened_malloc")))]
#[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))]
pub mod je;
#[cfg(all(not(target_env = "msvc"), feature = "jemalloc", not(feature = "hardened_malloc")))]
#[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))]
pub use je::{memory_stats, memory_usage};
// hardened_malloc
//#[cfg(all(not(target_env = "msvc"), feature = "hardened_malloc", target_os =
//#[cfg(all(not(target_env "linux", not(feature = "jemalloc")))]
//pub mod hardened;
//#[cfg(all(not(target_env = "msvc"), feature = "hardened_malloc", target_os =
//#[cfg(all(not(target_env "linux", not(feature = "jemalloc")))]
//pub use hardened::{memory_stats, memory_usage};
#[cfg(all(not(target_env = "msvc"), feature = "hardened_malloc", not(feature = "jemalloc")))]
pub mod hardened;
#[cfg(all(not(target_env = "msvc"), feature = "hardened_malloc", not(feature = "jemalloc")))]
pub use hardened::{memory_stats, memory_usage};
// default, enabled when none or multiple of the above are enabled
#[cfg(any(
not(any(feature = "jemalloc", feature = "hardened_malloc")),
all(feature = "jemalloc", feature = "hardened_malloc"),
))]
#[cfg(any(target_env = "msvc", all(not(feature = "hardened_malloc"), not(feature = "jemalloc"))))]
pub mod default;
#[cfg(any(
not(any(feature = "jemalloc", feature = "hardened_malloc")),
all(feature = "jemalloc", feature = "hardened_malloc"),
))]
#[cfg(any(target_env = "msvc", all(not(feature = "hardened_malloc"), not(feature = "jemalloc"))))]
pub use default::{memory_stats, memory_usage};
+13 -5
View File
@@ -6,6 +6,17 @@ use tracing::{debug, error, info, warn};
use crate::{error::Error, Config};
pub fn check(config: &Config) -> Result<(), Error> {
#[cfg(feature = "rocksdb")]
warn!(
"Note the rocksdb feature was deleted from conduwuit, sqlite was deleted and RocksDB is the only supported \
backend now. Please update your build script to remove this feature."
);
#[cfg(feature = "sha256_media")]
warn!(
"Note the sha256_media feature was deleted from conduwuit, it is now fully integrated in a \
forwards-compatible way. Please update your build script to remove this feature."
);
config.warn_deprecated();
config.warn_unknown_key();
@@ -14,10 +25,7 @@ pub fn check(config: &Config) -> Result<(), Error> {
}
if cfg!(feature = "hardened_malloc") && cfg!(feature = "jemalloc") {
warn!(
"hardened_malloc and jemalloc were built together, this causes neither to be used. Conduwuit will still \
function, but consider rebuilding and pick one as this is now no-op."
);
warn!("hardened_malloc and jemalloc are both enabled, this causes jemalloc to be used.");
}
if config.unix_socket_path.is_some() && !cfg!(unix) {
@@ -66,7 +74,7 @@ pub fn check(config: &Config) -> Result<(), Error> {
});
// rocksdb does not allow max_log_files to be 0
if config.rocksdb_max_log_files == 0 && cfg!(feature = "rocksdb") {
if config.rocksdb_max_log_files == 0 {
return Err(Error::bad_config(
"When using RocksDB, rocksdb_max_log_files cannot be 0. Please set a value at least 1.",
));
+61 -70
View File
@@ -201,6 +201,8 @@ pub struct Config {
pub query_trusted_key_servers_first: bool,
#[serde(default = "default_log")]
pub log: String,
#[serde(default = "default_openid_token_ttl")]
pub openid_token_ttl: u64,
#[serde(default)]
pub turn_username: String,
#[serde(default)]
@@ -300,8 +302,13 @@ pub struct Config {
#[serde(default)]
pub allow_guests_auto_join_rooms: bool,
#[serde(default = "true_fn")]
pub media_startup_check: bool,
#[serde(default = "true_fn")]
pub media_compat_file_link: bool,
#[serde(default = "Vec::new")]
pub prevent_media_downloads_from: Vec<OwnedServerName>,
#[serde(default = "Vec::new")]
pub forbidden_remote_server_names: Vec<OwnedServerName>,
#[serde(default = "Vec::new")]
@@ -350,6 +357,9 @@ pub struct Config {
#[serde(default = "default_sentry_traces_sample_rate")]
pub sentry_traces_sample_rate: f32,
#[serde(default)]
pub tokio_console: bool,
#[serde(flatten)]
#[allow(clippy::zero_sized_map_values)] // this is a catchall, the map shouldn't be zero at runtime
catchall: BTreeMap<String, IgnoredAny>,
@@ -513,10 +523,9 @@ impl fmt::Display for Config {
("Database path", &self.database_path.to_string_lossy()),
(
"Database backup path",
match &self.database_backup_path {
Some(path) => path.to_str().unwrap(),
None => "",
},
self.database_backup_path
.as_ref()
.map_or("", |path| path.to_str().unwrap_or("")),
),
("Database backups to keep", &self.database_backups_to_keep.to_string()),
("Database cache capacity (MB)", &self.db_cache_capacity_mb.to_string()),
@@ -568,9 +577,10 @@ impl fmt::Display for Config {
("Allow registration", &self.allow_registration.to_string()),
(
"Registration token",
match self.registration_token {
Some(_) => "set",
None => "not set (open registration!)",
if self.registration_token.is_some() {
"set"
} else {
"not set (open registration!)"
},
),
(
@@ -651,17 +661,19 @@ impl fmt::Display for Config {
None => "not set",
},
),
("Trusted key servers", {
let mut lst = vec![];
for server in &self.trusted_servers {
lst.push(server.host());
}
&lst.join(", ")
}),
(
"Trusted key servers",
&self
.trusted_servers
.iter()
.map(|server| server.host())
.join(", "),
),
(
"Query Trusted Key Servers First",
&self.query_trusted_key_servers_first.to_string(),
),
("OpenID Token TTL", &self.openid_token_ttl.to_string()),
(
"TURN username",
if self.turn_username.is_empty() {
@@ -706,58 +718,43 @@ impl fmt::Display for Config {
("Gzip HTTP Compression", &self.gzip_compression.to_string()),
#[cfg(feature = "brotli_compression")]
("Brotli HTTP Compression", &self.brotli_compression.to_string()),
#[cfg(feature = "rocksdb")]
("RocksDB database LOG level", &self.rocksdb_log_level),
#[cfg(feature = "rocksdb")]
("RocksDB database LOG to stderr", &self.rocksdb_log_stderr.to_string()),
#[cfg(feature = "rocksdb")]
("RocksDB database LOG time-to-roll", &self.rocksdb_log_time_to_roll.to_string()),
#[cfg(feature = "rocksdb")]
("RocksDB Max LOG Files", &self.rocksdb_max_log_files.to_string()),
#[cfg(feature = "rocksdb")]
(
"RocksDB database max LOG file size",
&self.rocksdb_max_log_file_size.to_string(),
),
#[cfg(feature = "rocksdb")]
(
"RocksDB database optimize for spinning disks",
&self.rocksdb_optimize_for_spinning_disks.to_string(),
),
#[cfg(feature = "rocksdb")]
("RocksDB Direct-IO", &self.rocksdb_direct_io.to_string()),
#[cfg(feature = "rocksdb")]
("RocksDB Parallelism Threads", &self.rocksdb_parallelism_threads.to_string()),
#[cfg(feature = "rocksdb")]
("RocksDB Compression Algorithm", &self.rocksdb_compression_algo),
#[cfg(feature = "rocksdb")]
("RocksDB Compression Level", &self.rocksdb_compression_level.to_string()),
#[cfg(feature = "rocksdb")]
(
"RocksDB Bottommost Compression Level",
&self.rocksdb_bottommost_compression_level.to_string(),
),
#[cfg(feature = "rocksdb")]
(
"RocksDB Bottommost Level Compression",
&self.rocksdb_bottommost_compression.to_string(),
),
#[cfg(feature = "rocksdb")]
("RocksDB Recovery Mode", &self.rocksdb_recovery_mode.to_string()),
#[cfg(feature = "rocksdb")]
("RocksDB Repair Mode", &self.rocksdb_repair.to_string()),
#[cfg(feature = "rocksdb")]
("RocksDB Read-only Mode", &self.rocksdb_read_only.to_string()),
#[cfg(feature = "rocksdb")]
(
"RocksDB Compaction Idle Priority",
&self.rocksdb_compaction_prio_idle.to_string(),
),
#[cfg(feature = "rocksdb")]
(
"RocksDB Compaction Idle IOPriority",
&self.rocksdb_compaction_ioprio_idle.to_string(),
),
("Media integrity checks on startup", &self.media_startup_check.to_string()),
("Media compatibility filesystem links", &self.media_compat_file_link.to_string()),
("Prevent Media Downloads From", {
let mut lst = vec![];
for domain in &self.prevent_media_downloads_from {
@@ -824,52 +821,47 @@ impl fmt::Display for Config {
("Sentry.io tracing sample rate", &self.sentry_traces_sample_rate.to_string()),
(
"Well-known server name",
&if let Some(server) = &self.well_known.server {
server.to_string()
} else {
String::new()
},
self.well_known
.server
.as_ref()
.map_or("", |server| server.as_str()),
),
(
"Well-known client URL",
&if let Some(server) = &self.well_known.client {
server.to_string()
} else {
String::new()
},
self.well_known
.client
.as_ref()
.map_or("", |url| url.as_str()),
),
(
"Well-known support email",
&if let Some(support_email) = &self.well_known.support_email {
support_email.to_string()
} else {
String::new()
},
self.well_known
.support_email
.as_ref()
.map_or("", |str| str.as_ref()),
),
(
"Well-known support Matrix ID",
&if let Some(support_mxid) = &self.well_known.support_mxid {
support_mxid.to_string()
} else {
String::new()
},
self.well_known
.support_mxid
.as_ref()
.map_or("", |mxid| mxid.as_str()),
),
(
"Well-known support role",
&if let Some(support_role) = &self.well_known.support_role {
support_role.to_string()
} else {
String::new()
},
self.well_known
.support_role
.as_ref()
.map_or("", |role| role.as_str()),
),
(
"Well-known support page/URL",
&if let Some(support_page) = &self.well_known.support_page {
support_page.to_string()
} else {
String::new()
},
self.well_known
.support_page
.as_ref()
.map_or("", |url| url.as_str()),
),
("Enable the tokio-console", &self.tokio_console.to_string()),
];
let mut msg: String = "Active config values:\n\n".to_owned();
@@ -984,18 +976,19 @@ fn default_tracing_flame_output_path() -> String { "./tracing.folded".to_owned()
fn default_trusted_servers() -> Vec<OwnedServerName> { vec![OwnedServerName::try_from("matrix.org").unwrap()] }
/// do debug logging by default for debug builds
#[must_use]
pub fn default_log() -> String {
// do debug logging by default for debug builds
if cfg!(debug_assertions) {
"debug".to_owned()
} else {
"info".to_owned()
}
cfg!(debug_assertions)
.then_some("debug")
.unwrap_or("info")
.to_owned()
}
fn default_notification_push_path() -> String { "/_matrix/push/v1/notify".to_owned() }
fn default_openid_token_ttl() -> u64 { 60 * 60 }
fn default_turn_ttl() -> u64 { 60 * 60 * 24 }
fn default_presence_idle_timeout_s() -> u64 { 5 * 60 }
@@ -1072,9 +1065,7 @@ fn default_url_preview_max_spider_size() -> usize {
fn default_new_user_displayname_suffix() -> String { "🏳️‍⚧️".to_owned() }
fn default_sentry_endpoint() -> Option<Url> {
Url::parse("https://fe2eb4536aa04949e28eff3128d64757@o4506996327251968.ingest.us.sentry.io/4506996334657536")
.unwrap()
.into()
Url::parse("https://fe2eb4536aa04949e28eff3128d64757@o4506996327251968.ingest.us.sentry.io/4506996334657536").ok()
}
fn default_sentry_traces_sample_rate() -> f32 { 0.15 }
+5 -5
View File
@@ -14,9 +14,9 @@ pub use crate::utils::debug::*;
macro_rules! debug_event {
( $level:expr, $($x:tt)+ ) => {
if cfg!(debug_assertions) && cfg!(not(feature = "dev_release_log_level")) {
tracing::event!( $level, $($x)+ );
::tracing::event!( $level, $($x)+ );
} else {
tracing::debug!( $($x)+ );
::tracing::debug!( $($x)+ );
}
}
}
@@ -27,7 +27,7 @@ macro_rules! debug_event {
#[macro_export]
macro_rules! debug_error {
( $($x:tt)+ ) => {
$crate::debug_event!(tracing::Level::ERROR, $($x)+ );
$crate::debug_event!(::tracing::Level::ERROR, $($x)+ );
}
}
@@ -37,7 +37,7 @@ macro_rules! debug_error {
#[macro_export]
macro_rules! debug_warn {
( $($x:tt)+ ) => {
$crate::debug_event!(tracing::Level::WARN, $($x)+ );
$crate::debug_event!(::tracing::Level::WARN, $($x)+ );
}
}
@@ -47,7 +47,7 @@ macro_rules! debug_warn {
#[macro_export]
macro_rules! debug_info {
( $($x:tt)+ ) => {
$crate::debug_event!(tracing::Level::INFO, $($x)+ );
$crate::debug_event!(::tracing::Level::INFO, $($x)+ );
}
}
+56 -72
View File
@@ -7,7 +7,11 @@ use http_body_util::Full;
use ruma::{
api::{
client::{
error::{Error as RumaError, ErrorBody, ErrorKind},
error::ErrorKind::{
Forbidden, GuestAccessForbidden, LimitExceeded, MissingToken, NotFound, ThreepidAuthFailed,
ThreepidDenied, TooLarge, Unauthorized, Unknown, UnknownToken, Unrecognized, UserDeactivated,
WrongRoomKeysVersion,
},
uiaa::{UiaaInfo, UiaaResponse},
},
OutgoingResponse,
@@ -16,78 +20,62 @@ use ruma::{
};
use thiserror::Error;
use tracing::error;
use ErrorKind::{
Forbidden, GuestAccessForbidden, LimitExceeded, MissingToken, NotFound, ThreepidAuthFailed, ThreepidDenied,
TooLarge, Unauthorized, Unknown, UnknownToken, Unrecognized, UserDeactivated, WrongRoomKeysVersion,
};
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Error)]
pub enum Error {
#[cfg(feature = "sqlite")]
#[error("There was a problem with the connection to the sqlite database: {source}")]
Sqlite {
#[from]
source: rusqlite::Error,
},
#[cfg(feature = "rocksdb")]
#[error("There was a problem with the connection to the rocksdb database: {source}")]
RocksDb {
#[from]
source: rust_rocksdb::Error,
},
#[error("Could not generate an image: {source}")]
Image {
#[from]
source: image::error::ImageError,
},
#[error("Could not connect to server: {source}")]
Reqwest {
#[from]
source: reqwest::Error,
},
#[error("Could build regular expression: {source}")]
Regex {
#[from]
source: regex::Error,
},
#[error("Remote server {0} responded with: {1}")]
Federation(OwnedServerName, RumaError),
#[error("Could not do this io: {source}")]
Io {
#[from]
source: std::io::Error,
},
#[error("There was a problem with your configuration: {0}")]
BadConfig(String),
// std
#[error("{0}")]
BadServerResponse(&'static str),
Fmt(#[from] fmt::Error),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("{0}")]
/// Don't create this directly. Use Error::bad_database instead.
BadDatabase(&'static str),
#[error("uiaa")]
Uiaa(UiaaInfo),
#[error("{0}: {1}")]
BadRequest(ErrorKind, &'static str),
Utf8Error(#[from] std::str::Utf8Error),
#[error("{0}")]
Conflict(&'static str), // This is only needed for when a room alias already exists
FromUtf8Error(#[from] std::string::FromUtf8Error),
#[error("{0}")]
TryFromSliceError(#[from] std::array::TryFromSliceError),
// third-party
#[error("Regex error: {0}")]
Regex(#[from] regex::Error),
#[error("Tracing filter error: {0}")]
TracingFilter(#[from] tracing_subscriber::filter::ParseError),
#[error("Image error: {0}")]
Image(#[from] image::error::ImageError),
#[error("Request error: {0}")]
Reqwest(#[from] reqwest::Error),
#[error("{0}")]
Extension(#[from] axum::extract::rejection::ExtensionRejection),
#[error("{0}")]
Path(#[from] axum::extract::rejection::PathRejection),
#[error("from {0}: {1}")]
Redaction(OwnedServerName, ruma::canonical_json::RedactionError),
#[error("{0} in {1}")]
InconsistentRoomState(&'static str, ruma::OwnedRoomId),
#[error("{0}")]
TracingFilter(#[from] tracing_subscriber::filter::ParseError),
#[error("{0}")]
AdminCommand(&'static str),
#[error("{0}")]
Fmt(#[from] fmt::Error),
// ruma
#[error("{0}")]
Mxid(#[from] ruma::IdParseError),
#[error("{0}: {1}")]
BadRequest(ruma::api::client::error::ErrorKind, &'static str),
#[error("from {0}: {1}")]
Redaction(OwnedServerName, ruma::canonical_json::RedactionError),
#[error("Remote server {0} responded with: {1}")]
Federation(OwnedServerName, ruma::api::client::error::Error),
#[error("{0} in {1}")]
InconsistentRoomState(&'static str, ruma::OwnedRoomId),
// conduwuit
#[error("There was a problem with your configuration: {0}")]
BadConfig(String),
#[error("{0}")]
BadDatabase(&'static str),
#[error("{0}")]
Database(String),
#[error("{0}")]
BadServerResponse(&'static str),
#[error("{0}")]
Conflict(&'static str), // This is only needed for when a room alias already exists
#[error("uiaa")]
Uiaa(UiaaInfo),
// unique / untyped
#[error("{0}")]
Err(String),
}
@@ -104,7 +92,8 @@ impl Error {
}
/// Returns the Matrix error code / error kind
pub fn error_code(&self) -> ErrorKind {
#[inline]
pub fn error_code(&self) -> ruma::api::client::error::ErrorKind {
if let Self::Federation(_, error) = self {
return error.error_kind().unwrap_or_else(|| &Unknown).clone();
}
@@ -117,20 +106,13 @@ impl Error {
/// Sanitizes public-facing errors that can leak sensitive information.
pub fn sanitized_error(&self) -> String {
let db_error = String::from("Database or I/O error occurred.");
match self {
#[cfg(feature = "sqlite")]
Self::Sqlite {
Self::Database {
..
} => db_error,
#[cfg(feature = "rocksdb")]
Self::RocksDb {
..
} => db_error,
} => String::from("Database error occurred."),
Self::Io {
..
} => db_error,
} => String::from("I/O error occurred."),
_ => self.to_string(),
}
}
@@ -157,6 +139,8 @@ impl From<Error> for RumaResponse<UiaaResponse> {
impl Error {
pub fn to_response(&self) -> RumaResponse<UiaaResponse> {
use ruma::api::client::error::{Error as RumaError, ErrorBody};
if let Self::Uiaa(uiaainfo) = self {
return RumaResponse(UiaaResponse::AuthResponse(uiaainfo.clone()));
}
+2 -1
View File
@@ -1,9 +1,10 @@
use tracing::Level;
use tracing_core::{span::Current, Event};
use super::layer::Value;
use super::{layer::Value, Layer};
pub struct Data<'a> {
pub layer: &'a Layer,
pub event: &'a Event<'a>,
pub current: &'a Current,
pub values: Option<&'a mut [Value]>,
+1
View File
@@ -8,5 +8,6 @@ pub struct Guard {
}
impl Drop for Guard {
#[inline]
fn drop(&mut self) { self.capture.stop(); }
}
+8 -4
View File
@@ -17,6 +17,7 @@ struct Visitor {
}
impl Layer {
#[inline]
pub fn new(state: &Arc<State>) -> Self {
Self {
state: state.clone(),
@@ -25,6 +26,7 @@ impl Layer {
}
impl fmt::Debug for Layer {
#[inline]
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("capture::Layer").finish()
}
@@ -40,12 +42,12 @@ where
.read()
.expect("shared lock")
.iter()
.filter(|capture| filter(capture, event, &ctx))
.for_each(|capture| handle(capture, event, &ctx));
.filter(|capture| filter(self, capture, event, &ctx))
.for_each(|capture| handle(self, capture, event, &ctx));
}
}
fn handle<S>(capture: &Capture, event: &Event<'_>, ctx: &Context<'_, S>)
fn handle<S>(layer: &Layer, capture: &Capture, event: &Event<'_>, ctx: &Context<'_, S>)
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
@@ -56,18 +58,20 @@ where
let mut closure = capture.closure.lock().expect("exclusive lock");
closure(Data {
layer,
event,
current: &ctx.current_span(),
values: Some(&mut visitor.values),
});
}
fn filter<S>(capture: &Capture, event: &Event<'_>, ctx: &Context<'_, S>) -> bool
fn filter<S>(layer: &Layer, capture: &Capture, event: &Event<'_>, ctx: &Context<'_, S>) -> bool
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
capture.filter.as_ref().map_or(true, |filter| {
filter(Data {
layer,
event,
current: &ctx.current_span(),
values: None,
+16 -7
View File
@@ -2,17 +2,26 @@ pub mod capture;
pub mod color;
pub mod fmt;
mod reload;
mod server;
mod suppress;
pub use capture::Capture;
pub use reload::{LogLevelReloadHandles, ReloadHandle};
pub use server::Server;
pub use suppress::Suppress;
pub use tracing::Level;
pub use tracing_core::{Event, Metadata};
pub use tracing_subscriber::EnvFilter;
/// Logging subsystem. This is a singleton member of super::Server which holds
/// all logging and tracing related state rather than shoving it all in
/// super::Server directly.
pub struct Log {
/// General log level reload handles.
pub reload: LogLevelReloadHandles,
/// Tracing capture state for ephemeral/oneshot uses.
pub capture: std::sync::Arc<capture::State>,
}
// Wraps for logging macros. Use these macros rather than extern tracing:: or
// log:: crates in project code. ::log and ::tracing can still be used if
// necessary but discouraged. Remember debug_ log macros are also exported to
@@ -20,25 +29,25 @@ pub use tracing_subscriber::EnvFilter;
#[macro_export]
macro_rules! error {
( $($x:tt)+ ) => { tracing::error!( $($x)+ ); }
( $($x:tt)+ ) => { ::tracing::error!( $($x)+ ); }
}
#[macro_export]
macro_rules! warn {
( $($x:tt)+ ) => { tracing::warn!( $($x)+ ); }
( $($x:tt)+ ) => { ::tracing::warn!( $($x)+ ); }
}
#[macro_export]
macro_rules! info {
( $($x:tt)+ ) => { tracing::info!( $($x)+ ); }
( $($x:tt)+ ) => { ::tracing::info!( $($x)+ ); }
}
#[macro_export]
macro_rules! debug {
( $($x:tt)+ ) => { tracing::debug!( $($x)+ ); }
( $($x:tt)+ ) => { ::tracing::debug!( $($x)+ ); }
}
#[macro_export]
macro_rules! trace {
( $($x:tt)+ ) => { tracing::trace!( $($x)+ ); }
( $($x:tt)+ ) => { ::tracing::trace!( $($x)+ ); }
}
-14
View File
@@ -1,14 +0,0 @@
use std::sync::Arc;
use super::{capture, reload::LogLevelReloadHandles};
/// Logging subsystem. This is a singleton member of super::Server which holds
/// all logging and tracing related state rather than shoving it all in
/// super::Server directly.
pub struct Server {
/// General log level reload handles.
pub reload: LogLevelReloadHandles,
/// Tracing capture state for ephemeral/oneshot uses.
pub capture: Arc<capture::State>,
}
+6 -3
View File
@@ -4,15 +4,18 @@ pub mod debug;
pub mod error;
pub mod log;
pub mod mods;
pub mod pducount;
pub mod pdu;
pub mod server;
pub mod utils;
pub mod version;
pub use config::Config;
pub use error::{Error, Result, RumaResponse};
pub use pducount::PduCount;
pub use error::{Error, RumaResponse};
pub use pdu::{PduBuilder, PduCount, PduEvent};
pub use server::Server;
pub use version::version;
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[cfg(not(conduit_mods))]
pub mod mods {

Some files were not shown because too many files have changed in this diff Show More