Compare commits

..

726 Commits

Author SHA1 Message Date
strawberry b6e9dc3d98 comment out borked ci thing for now
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-09 10:17:28 -05:00
strawberry cfcd6eb1a6 bump ruwuma to stop erroring on empty push response body
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-07 18:00:58 -05:00
strawberry 88e7e50daf add missing source OCI image label metadata
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-07 11:49:00 -05:00
strawberry 8345ea2cd3 add --locked and --no-fail-fast to cargo test, add other feature test
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-06 19:02:14 -05:00
strawberry add2e0e9ee bump rust-rocksdb
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-06 18:27:36 -05:00
strawberry 43e6c27bb7 misc nix tweaks to maybe speedup ci
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-06 18:27:36 -05:00
strawberry c7c9f0e4a6 catch clippy lints for --no-default-features builds
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-06 18:27:36 -05:00
strawberry ef2d307c15 fix warnings and errors when building with no features
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-06 18:27:32 -05:00
strawberry f761d4d5c9 bump db version to 17, cleanup, rerun old migrations for users who downgraded
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-06 16:48:19 -05:00
strawberry 16b07ae3ec add default systemd support for a TTY to use console mode from
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-06 16:47:10 -05:00
Jason Volk 62d80b97e6 add systemd unit logging mode
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-06 03:16:56 +00:00
strawberry fda8b36809 add more systemd notify integration with stopping/reloading/ready states
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-05 07:32:00 +00:00
strawberry f6dfc9538f bump ruwuma to stop erroring on duplicate yaml values on appservice EDUs (we dont implement this atm anyways)
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-05 07:32:00 +00:00
strawberry f80d85e107 add SIGUSR1 systemctl reload config support to systemd units
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-02-05 07:32:00 +00:00
Jason Volk 9158edfb7c fix empty join timeline bug
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-05 07:32:00 +00:00
Jason Volk 04656a7886 fix spaces pagination bug
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-05 07:32:00 +00:00
Jason Volk 442bb9889c improvements on blurhashing feature
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-04 21:47:03 +00:00
Niko 62180897c0 Added blurhash.rs to fascilitate blurhashing.
Signed-off-by: Niko <cnotsomark@gmail.com>
2025-02-04 21:47:03 +00:00
Nineko 80277f6aa2 Adds .gitattributes to the projects to prevent LN and CLRF conflicts. (#681) 2025-02-04 16:46:00 -05:00
Jason Volk d32534164c fix soft-failed redaction regression (ff8bbd4cfa)
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-04 21:00:12 +00:00
Jason Volk b3271e0d65 split state_accessor
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-04 00:02:00 +00:00
Jason Volk 106bcd30b7 optimize incremental sync state diff
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-04 00:02:00 +00:00
Jason Volk da4b94d80d trap panics when running in gdb
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-04 00:02:00 +00:00
Jason Volk 32f990fc72 fix the panic counter in the tower layer
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-03 01:16:09 +00:00
Jason Volk 5e59ce37c4 snapshot sync results at next_batch upper-bound
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-02 16:30:55 +00:00
Jason Volk a774afe837 modernize remove_to_device_events
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-02 16:30:55 +00:00
Jason Volk ffe3b0faf2 make shutdown grace periods configurable
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-02 16:30:55 +00:00
Jason Volk bd6d4bc58f enforce timeout on request layers
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-02 16:30:55 +00:00
Jason Volk b4d22bd05e remove unnecessary cf arc refcnt workaround
log errors and panics propagating through the request task join

Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-02 10:08:30 +00:00
Jason Volk 7ce782ddf4 fix jemalloc cfgs lacking msvc conditions
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-02 10:08:30 +00:00
Jason Volk 4add39d0fe cache compressed state in a sorted structure for logarithmic queries with partial keys
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-02 10:08:30 +00:00
Jason Volk ea49b60273 add Option support to database deserializer
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-02 00:09:18 +00:00
Jason Volk 2fa9621f3a flatten state_full_shortids
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-31 22:46:26 +00:00
Jason Volk 09bc71caab fix missed concurrent fetch opportunities in sender (ffd0fd4242)
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-31 22:46:26 +00:00
Jason Volk 6983798487 implement lazy-loading for incremental sync
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-31 22:46:26 +00:00
Jason Volk a4ef04cd14 fix room join completion taking wrong sync branch
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-31 22:46:26 +00:00
Jason Volk 4e0cedbe51 simplify v3 sync presence collecting
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-31 22:46:26 +00:00
Jason Volk 4ff1155bf0 reroll encrypted_room branch in incremental sync state
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-31 22:46:26 +00:00
Jason Volk e161e5dd61 add pair_of! macro
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-31 22:45:37 +00:00
morguldir f698254c41 make registration tokens reloadable, and allow configuring multiple
Signed-off-by: morguldir <morguldir@protonmail.com>
2025-01-31 03:09:02 +01:00
Jason Volk 69837671bb simplify request handler task base
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-30 18:58:32 +00:00
Jason Volk ff8bbd4cfa untwist the redaction check stanza
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-30 05:26:30 +00:00
Jason Volk 1a8482b3b4 refactor incoming extremities retention; broad filter, single pass
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-30 05:26:30 +00:00
Jason Volk 31c2968bb2 move db files command w/ filter args; misc related cleanup
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 23:21:08 +00:00
Jason Volk 3c8376d897 parallelize state-res pre-gathering
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 23:21:07 +00:00
Jason Volk 50acfe7832 flatten auth chain iterations
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 21:28:26 +00:00
Jason Volk eb7d893c86 fix malloc_conf feature-awareness
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 06:37:30 +00:00
Jason Volk 936161d89e reduce bottommost compression underrides
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 03:09:13 +00:00
Jason Volk 329925c661 additional info level span adjustments
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 03:09:13 +00:00
Jason Volk af399fd517 flatten state accessor iterations
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk ad0b0af955 combine state_accessor data into mod
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk 2c5af902a3 support executing configurable admin commands via SIGUSR2
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk 2f449ba47d support reloading config via SIGUSR1
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk a567e314e9 simplify shutdown signal handlers
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk ed3cd99781 abstract the config reload checks
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk 99fe88c21e use smallvec for the edu sending event buffer
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk ffd0fd4242 pipeline pdu fetch for federation sending destination
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk b2a565b0b4 propagate better error from server.check_running() 2025-01-29 01:18:08 +00:00
Jason Volk c516a8df3e fanout edu processing
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk 94d786ac12 process rooms and edus concurrently
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk 677316631a pipeline prologue of handle_incoming_pdu
simplify room_version/first_pdu_in_room argument passing

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk 2b730a30ad add broad_flat_map
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-29 01:18:08 +00:00
Jason Volk 98f9570547 add option to disable rocksdb checksums
reference runtime state for default option initialization

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-28 18:38:47 +00:00
Jason Volk 13335042b7 enable the paranoid-checks options in debug mode
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-28 18:36:00 +00:00
Jason Volk 6db8df5e23 skip redundant acl check when sender is origin
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-28 18:36:00 +00:00
Jason Volk d0b4a619af furnish batch interface with trait
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-28 18:36:00 +00:00
Jason Volk 4a2d0d35bc split federation request from sending service
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-28 18:36:00 +00:00
Jason Volk 3e0ff2dc84 simplify references to server_name
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-28 18:36:00 +00:00
June Clementine Strawberry 71a3855af6 fix couple more docker manifest typos
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-26 21:30:15 -05:00
Jade Ellis db7d23e780 fix creating manifest on wrong repo 2025-01-26 20:38:26 -05:00
Jade Ellis 1c585ab1b6 create manifests for unique docker tags 2025-01-26 20:38:26 -05:00
Jade Ellis 24e6086f12 load correct image file 2025-01-26 20:38:26 -05:00
Jade Ellis ee63f720c9 revert incorrect tags 2025-01-26 20:38:26 -05:00
June Clementine Strawberry 4b3c54bbfa check if DOCKER_USERNAME is empty as well in dockerhub desc publish
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-26 13:11:47 -05:00
Jason Volk 68856645ee refactor lazy-loading
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-26 17:48:53 +00:00
Jason Volk 9ad4f20da4 propagate underflow as error result, not index bounds panic
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-26 17:48:53 +00:00
Jason Volk 186c459584 use scalar for file shape; increase shape for small-type columns
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-26 17:48:53 +00:00
Jason Volk 29a19ba437 add write_to_cache to descriptor
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-26 17:48:53 +00:00
June Clementine Strawberry 3b0195e6b3 misc various github actions ci fixes
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-26 01:10:25 -05:00
June Clementine Strawberry 4b331fe50e update README.md, crate metadata, and OCI image metadata
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-26 01:08:39 -05:00
June Clementine Strawberry c323894497 use test in postrm deb script before deleting
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-25 21:27:21 -05:00
June Clementine Strawberry 5b5ccba64e make conduwuit lowercase in the user-agent again
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-25 21:20:55 -05:00
bumpsoo 9dcf289c7a (doc): Update docker-compose.yml and conduwuit-example.toml
The server cannot start without a registration token when registration is configured

Signed-off-by: bumpsoo <bumpsoo063@protonmail.ch>
2025-01-25 20:08:46 -05:00
Jade Ellis d86061084c Publish haswell images to image registries (#674)
* push haswell images to docker repos

* Add OCI labels to image

* fixup! Add OCI labels to image

* fixup! push haswell images to docker repos

* fixup! Add OCI labels to image

* fixup! Add OCI labels to image

* fixup! Add OCI labels to image
2025-01-25 20:05:41 -05:00
Jade Ellis 1d26eec82d publish README to docker hub 2025-01-25 19:34:10 -05:00
June Clementine Strawberry 9514064c1c use --locked for macOS builds
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-25 13:40:31 -05:00
June Clementine Strawberry 2abf15b9e9 revert back to v9.9.3 due to upstream build issue with macos
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-25 13:35:22 -05:00
June Clementine Strawberry cd5d4f48be add mau.dev mirror of conduwuit
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-25 03:08:35 -05:00
morguldir eed3291625 ci: set variable after ssh has been configured, mainly for draft pull requests 2025-01-25 02:01:55 -05:00
morguldir 6a7fe3ab7c limit wal archive size to 1gb
Signed-off-by: morguldir <morguldir@protonmail.com>
2025-01-25 02:01:36 -05:00
June Clementine Strawberry 72daf7ea68 bump rocksdb to v9.10.0, reverts upstream rocksdb regression causing deadlocks on corrupt WAL files
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-25 02:01:20 -05:00
Jason Volk 94f2384fb0 fix missing iteration-optimized read options on several stream types
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk d59f68a51a add sensitive-field directives to config display
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk b1b6dc0479 reloadable configuration
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk 184a3b0f0c reduce some tracing span levels; bump ruma
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk b5c167de12 call decay prior to purge for trim-memory
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk 5be07ebc0f eliminate references to services.globals.config
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk 7c6b8b132a add config reloading indirector
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk 1351d07735 improve path argument to Config::load and constructions
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk 6e7c73336c move room version config check out of services.globals
make available_room_versions() non-member associated

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk 52adae7553 add sequence method to db engine; improve engine interface/tracing
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk a5520e8b1b fix SRV override loss on cache expiration
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-23 01:48:53 +00:00
Jason Volk 265802d546 additional prof/stats jemalloc related interface tweaks
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-23 01:48:53 +00:00
Jason Volk da9f1ae5d7 expire resolver cache entries
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 08:51:56 +00:00
Jason Volk 607e338ac2 cache result of resolution at completion of resolution
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 07:56:24 +00:00
Jason Volk f75d9fa79e deduplicate name resolutions
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 06:57:18 +00:00
Jason Volk 7c0c029a4a add try_lock to MutexMap; allow TryFrom constructions
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 06:40:07 +00:00
Jason Volk 49023aa295 use database for resolver caches
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 02:16:51 +00:00
Jason Volk 0c96891008 add CBOR support to database schema
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 00:52:48 +00:00
Jason Volk 1f31e74024 add del to raw suite
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 03:50:51 +00:00
Jason Volk 9ab381e4eb generate fmt::Display for Config
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-18 07:12:20 +00:00
Jason Volk dda27ffcb1 add some compaction related interfaces
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-18 12:05:07 +00:00
Jason Volk 8ab825b12c add stream parallelism extension combinators
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-21 20:43:38 +00:00
Jason Volk 19f6d9d0e1 add index-compression and auto-readahead to descriptor
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 12:12:44 +00:00
Jason Volk 277b4951e8 add compression-shaping; tweak default compression levels
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 11:50:17 +00:00
Jason Volk 610129d162 outdent auth_chain Service impl
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 09:05:49 +00:00
Jason Volk 4c0ae8c2f7 parallelize get_auth_chain outer
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 09:02:50 +00:00
Jason Volk ea25dc04b2 parallelize current and incoming fork-state fetch
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 07:38:32 +00:00
Jason Volk 388730d6dd add TryWideband trait to similar to TryBroadband
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 07:38:19 +00:00
Jason Volk ac944496c1 optimize statekey-from-short loopsite
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-14 19:17:45 +00:00
Jason Volk 3dae02b886 add preferred jemalloc config
add muzzy/dirty configuration mallctl interface

add program argument for --gc-muzzy=false

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-18 01:30:41 +00:00
Jason Volk 3eed408b29 additional util macros and reorg
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:48:47 +00:00
Jason Volk 4fbbfe5d30 add alt argument format for detecting cargo build phase
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:48:47 +00:00
Jason Volk df3eb95d4f additional affinity utils
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:48:47 +00:00
Jason Volk 7045481fae add from_errno construction to Error
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:48:47 +00:00
Jason Volk c6ae6adc80 pre-allocate some amount of media read buffer
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:48:47 +00:00
Jason Volk afdf5a07b5 abstract hidden line related in config generator macro 2025-01-20 04:48:47 +00:00
Jason Volk f9e76d6239 improve debug memory-stats options
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:48:47 +00:00
Jason Volk 8141ca3444 refactor admin outputs to asyncwrite
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:48:47 +00:00
Jason Volk abf33013e3 check-in additional database test related
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:48:47 +00:00
Jason Volk 96e85adc32 use cache builder for row and table cache options
add cache check using multi-get path

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:48:47 +00:00
Jason Volk fc1170e12a additional tracing span tweaks
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:17:04 +00:00
Jason Volk 819e35f81f remove mutex lock/unlock during sync iteration.
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:17:04 +00:00
Jason Volk bab40a3747 enable hashing on large-block indexes
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:17:04 +00:00
Jason Volk aad42bdaa0 reduce block size on small tables
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:17:04 +00:00
Jason Volk 3759d1be6c tweak per-column write_buffer down from default
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:17:04 +00:00
Jason Volk 77d8e26efe integrate trim-on-park memory reclamation to runtime
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:17:04 +00:00
Jason Volk 7a8ca8842a add jemallctl base; add trim to interface w/ console cmd
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:17:02 +00:00
Jason Volk 80832cb0bb add checked math wrapper
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:16:17 +00:00
Jason Volk 98d8e5c63c add standard error trait and thread access error conversions
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-20 04:16:17 +00:00
Jason Volk 5167e1f06d add option to disable listeners
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-18 01:43:58 +00:00
Jason Volk e56d3c6cb3 add multi_get_statekey_from_short
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-18 01:43:58 +00:00
Jason Volk afcd0bfeef add deref_at macro util
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-18 01:43:58 +00:00
strawberry 5b8464252c cleanup+fix login get_token code, use db ser/deser instead
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-17 17:40:53 -05:00
Jade Ellis 2cc6ad8df3 implement /login/get_token (MSC3882) 2025-01-17 17:40:53 -05:00
Jade Ellis afe9e5536b remove undocumented jwt token login 2025-01-17 17:40:53 -05:00
Jason Volk 9ebb39ca4f add missing cfg_attr on deserialisation db test
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-15 14:34:50 -05:00
June Clementine Strawberry f59e3d8850 bump nix lockfile, cargo.lock, rust to 1.84, and fix tracing fork
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-14 13:05:25 -05:00
morguldir 6cb3275be0 Add initial MSC4186 (Simplified Sliding Sync) implementation
Signed-off-by: morguldir <morguldir@protonmail.com>
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-14 15:09:51 +01:00
morguldir be16f84410 syncv3: use a function for repeated pattern of fetching sticky params 2025-01-13 22:31:21 -05:00
strawberry 9dd058de60 update complement results
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-13 14:15:16 -05:00
strawberry 5a1c41e66b knocking implementation
Signed-off-by: strawberry <strawberry@puppygock.gay>

add sync bit of knocking

Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-13 14:15:16 -05:00
strawberry fabd3cf567 ci: set binary as executable before uploading to webserver
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-13 14:15:16 -05:00
strawberry 5e21b43f25 run direnv exec in engage default steps
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-13 14:15:16 -05:00
strawberry 9bda5a43e5 fix /kick endpoint unbanning banned users
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-13 14:15:16 -05:00
strawberry 8c18481d1d optimise resetting all user presences
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-13 14:09:53 -05:00
Holger Huo fde1b94e26 fix: logic mistake 2025-01-11 21:43:58 -05:00
Holger Huo b71201cf19 add: clear online status on server boot 2025-01-11 21:43:57 -05:00
Holger Huo 8451ea3bc3 update: refresh timeout greater than idle timeout 2025-01-11 21:43:57 -05:00
Holger Huo 6f15c9b3f4 fix: presence timer not working 2025-01-11 21:43:57 -05:00
strawberry 0074f903d8 delete lix binary cache because it has terrible reliability
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-11 21:43:57 -05:00
strawberry 1852eeebf2 disable more unnecessary features in various build outputs
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-11 20:48:36 -05:00
strawberry 5b6279b1c5 ci: require docker publishing to pass tests
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-11 20:48:36 -05:00
strawberry 4c2999ccd1 gate libloading to conduwuit_mods feature and cfg only
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-11 20:48:36 -05:00
strawberry 53d03bbb1f gate sd_notify to linux target_os only
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-11 19:37:44 -05:00
Jason Volk 66231676f1 gracefully ignore unknown columns; add dropped flag in descriptor
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-10 22:29:05 +00:00
Jason Volk 16fa2eca87 add conf item for write buffer size
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-10 07:03:34 +00:00
Jason Volk 6a0f9add0c refactor database engine/options; add column descriptors
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-10 07:03:34 +00:00
Jason Volk 02f19cf951 tweak tracing spans; inlines
db deserializer tracing instrument cover

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-10 07:03:34 +00:00
Jason Volk 685b127f99 simplify iterator state constructor arguments
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-10 07:03:34 +00:00
Jason Volk cc1889d135 Add default-enabled feature-gates for url_preview and media_thumbnail
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-10 07:03:34 +00:00
Jason Volk 0238f27605 prevent example-config generating in test builds
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-10 07:03:34 +00:00
Jason Volk 5dae086197 exclude config item from doctest
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-10 06:53:15 +00:00
Jason Volk 44e6b1af3c fixes for tests to be run in release-mode
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-09 19:56:42 +00:00
Jason Volk 94c8683836 improve db pool topology configuration
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-09 18:14:23 +00:00
Jason Volk d36167ab64 partially revert 9a9c071e82; use std threads for db pool.
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-09 18:14:23 +00:00
Jason Volk 925061b92d flatten timeline pdus iterations; increase concurrency
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-09 18:14:23 +00:00
Jason Volk 27328cbc01 additional futures extension utils
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-09 18:14:23 +00:00
Jason Volk a3f9432da8 eliminate the state-res mutex hazard
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-09 18:14:23 +00:00
Jason Volk 82168b972a fix heroes calculation regression
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-09 18:14:23 +00:00
Neil Svedberg 7526ba9d6f Add header to console
When the console is launched, it now prints this message:

    conduwuit VERSION admin console
    "help" for help, ^D to exit the console, ^\ to stop the server
2025-01-09 10:18:49 -05:00
Jade Ellis 8c74e35e76 automatically retry returning data in syncv3 (#652)
* automatically retry returning data in syncv3

* reference service

* clippy fixes
2025-01-03 22:15:48 -05:00
June Clementine Strawberry e5049cae4a update complement test results
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-02 22:02:11 -05:00
Jason Volk f1af7ec08c fix unused import in release mode
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-03 02:36:24 +00:00
June Clementine Strawberry 3b8a90ad13 delete more stuff to free up runner space
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-02 20:56:27 -05:00
strawberry 7a349fdc58 use latest sccache, bump nix flake lock, cache everything in rust-cache
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-02 19:13:27 -05:00
strawberry 6c8a1b5e9b bump ruwuma
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-02 18:48:04 -05:00
strawberry a5d70f7356 add some m.room.member checks on putting direct state events
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-02 18:16:00 -05:00
Jason Volk 50cadbee96 add faster shutdown point in unix socket listener
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-02 08:20:02 +00:00
Jason Volk b1182fe8a4 improve some router tracing spans
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-02 08:20:02 +00:00
Jason Volk 77d7e8a3ad add json array to serde_json::Value db deserialization without Raw 2025-01-02 06:52:32 +00:00
strawberry 72797532b6 fix MSC4133 fields not being returned as original types
Signed-off-by: strawberry <strawberry@puppygock.gay>
2025-01-01 23:28:01 -05:00
Jason Volk b4ef646485 translate 5xx to 404 on remote media request
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk b8f8f68634 improve memory-usage output w/ more byte-sizes
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 33635e11d1 bump ruma
tweak tracing instrument

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 1a71798859 add Expected trait to utils; use (already transitive) num-traits.
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 7e4453620e move exponential backoff util to different submod
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 2259e2c82f batch queries to maximize throughput
query-side streams for first level of callsites

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 1792711d09 support core affinity mask
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 0b2fca5ad9 add complement diff from e2f6753a3280 2025-01-01 23:28:01 -05:00
June Clementine Strawberry 0e110bb48b fix flipped room ver check on send_join
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-01-01 23:28:01 -05:00
Jason Volk 3ffe2cd56e reduce backoff warning from infolog
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk c5b94be5b8 remove dev_release_log_level cfg
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 2bbb28bb88 get device info with libc using major/minor
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 203cf57fdf add console log event format hook
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 9c6b5b4407 add faster interruption to resolver (#649)
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk a1fc4d49ac reduce non-debug startup warnings
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk b56e480b3c integrate some std io error kinds with our status code abstraction
associate rocksdb error kinds with std io error kinds

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 7c8eeaf4ea simplify multi_get_or_create/related stream implementations
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 9eb99f8070 abstract async shutdown waiting loop
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 0a9b6c136f refactor for ruma identifiers optimizations
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk d91570d0e6 add Error variant for FeatureDisabled
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 3a2c5be4f4 reduce exponential backoff for prev fetch
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk e21403a4d4 use VecDeque for todo queues
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 74eb30c106 add LIFO scheduling for database frontend pool workers
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 6458f4b195 refactor various Arc<EventId> to OwnedEventId
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 5a335933b8 pass stream width to ruma state res
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 3b95af9a18 move stream width related into unit
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk a407909d09 reduce unnecessary info-level spans to debug
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 7a6d657558 configurable dynamic stream concurrency scalar
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk b195107053 optimize for multi-queue storage topologies with affinity
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk e5a1309583 additional interruption points to hasten shutdown
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 03f2ac9caf simplify usage of mpmc channels which don't require receiver lock
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 5fdb8895b1 add utils to detect device io characteristics
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 749f29aaab add and/and_then to BoolExt
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk a3d87be22f enable atomic_flush for database columns
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk aefc4b4e69 add more program options for tokio
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 503210c3bf toggle worker_affinity feature from program argument
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 674acc8657 add program options for tokio histogram settings
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk af3d6a2e37 shard sender into multiple task workers by destination hash
rename Destination::Normal variant

tracing instruments

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 98e6c81e49 offload remaining db iterator initial seeks on cache miss
consume task budget on cache hit

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 14341bb906 simplify and improve db iter State init interface
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Neil Svedberg 5bce0a3a46 Improve documentation for configuration
Although the configuration file was mostly wrapped to a line-width of
80, some lines were wrapped slightly shorter. I fixed this.

In general, all sentences were changed to start with a capital letter
and end with a period or other punctuation mark.

Many of the documentation commets read as, "config option to do XYZ". I
shortened these to simply "do XYZ".
2025-01-01 16:31:30 -05:00
Neek c53e9e07f2 update cohost link
added an archive.org link to the cohost post as it will fully shut down at the end of the year
2024-12-27 13:57:18 -05:00
nexy7574 7f645ff0e9 Make some doc changes to admin media delete-past-remote-media
Adjust before/after doc to clarify internationally

Courtesy of @Aranjedeath

Run `cargo fmt`, properly

Fix stupid doc command issue

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-20 13:56:40 -05:00
Jade Ellis 5b5735f653 update ruwuma 2024-12-19 21:03:12 -05:00
Jade Ellis 025950139e do not try to push to GHCR on pull requests from forks 2024-12-19 21:02:34 -05:00
Jade Ellis 0602e38ada remove logging 2024-12-19 21:02:34 -05:00
Jade Ellis 8f73caae0b fix github actions runs on forks
This commit contains two separate fixes:

1) use lowercased github username/repository for the docker
repository name.
This is because image registries only accept
lowercase in image repository names, but github stores the
repository and username in a case-sensitive manner. This broke
image uploads for me, as my username has uppercase chars.

2) change run conditions for some steps.
It will no longer attempt to set up SSH web publishing if the SSH
private key is not set.
It will also run the image registry upload steps if registry
usernames are missing, instead skipping individual uploads where
the token for that registry is missing.

Finally, it simplifies the sccache run conditions to use the
`SCCACHE_GHA_ENABLED` env variable, rather than duplicating that
logic.

Signed-off-by: Jade Ellis <jade@ellis.link>
2024-12-19 21:02:34 -05:00
admin@dimensionproject.net 802395bdb7 add password argument to reset-password admin cmd
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-18 20:46:01 -05:00
Jason Volk 60a952508e use macro for error constructions
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-18 14:16:29 -05:00
Jason Volk 4d46df2af5 abort tasks for non-async pool shudown
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-18 14:16:23 -05:00
strawberry 7b8320e0eb bump rocksdb to v9.9.3
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-18 13:41:30 -05:00
Jason Volk 6c42ac2726 add num_workers() convenience to core metrics
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-18 13:32:13 -05:00
Jason Volk 71673b2a88 add worker_affinity feature
split runtime init from main.rs

Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-18 13:31:58 -05:00
Jason Volk 5f7636f177 set dbpool thread name (gated by tokio_unstable)
Signed-off-by: Jason Volk <jason@zemos.net>
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-18 13:31:41 -05:00
Jason Volk f78104a959 relax Send on input iterator
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-18 13:29:51 -05:00
Jason Volk ad8cbcaac1 check cache prior to offloading iterator seek
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-18 13:29:43 -05:00
strawberry f54a62dda0 Revert "Send read reciept and typing indicator EDUs to appservices with receive_ephemeral"
This reverts commit 3675c941f8.
2024-12-18 11:26:18 -05:00
strawberry 9040ad054e Revert "misc typing cleanup"
This reverts commit 4dd809fdc4.
2024-12-18 11:26:04 -05:00
strawberry 4dd809fdc4 misc typing cleanup
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-17 23:13:35 -05:00
Jade Ellis 3675c941f8 Send read reciept and typing indicator EDUs to appservices with receive_ephemeral 2024-12-17 22:49:45 -05:00
Jade Ellis 5b6ff3869c Fix typo in test from rename 2024-12-17 19:29:46 +00:00
AsenHu 9ec35cf684 skip uploading JSON files in release workflow 2024-12-17 03:01:40 +00:00
AsenHu 63c4975483 fix bug 2024-12-17 02:08:52 +00:00
strawberry 5813419f4b free up ci runner space on both jobs
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 22:49:34 -05:00
strawberry 8dcdb4b09a update some more docs
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 22:48:22 -05:00
strawberry 7ad710d96a bump complement
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 18:00:49 -05:00
strawberry c8c9d73b20 enable edns0 on hickory resolver config
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 17:24:45 -05:00
strawberry 004671b437 dont copy join_authorized_via_users_server on leaving rooms
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 15:58:53 -05:00
strawberry aeae67a7ee bump ruwuma to stop sending empty content rulesets
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 15:20:28 -05:00
strawberry 74c5bfd311 dont allow m.room.server_acl to be redacted
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 14:31:11 -05:00
strawberry 2ba0400758 return proper error for attempting to update m.room.create
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 14:23:13 -05:00
strawberry 468071336b ping online presence on read updates like synapse
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 14:13:51 -05:00
strawberry 9c6908b8c1 bump ruwuma, implement MSC4076, add more pusher HTTP URL validation
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 14:05:28 -05:00
strawberry c8349988aa ping online presence on typing updates like synapse
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 02:53:32 -05:00
strawberry 6c96acc482 use fast binary_search for some const slices
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 01:41:50 -05:00
strawberry 52693db477 hide messages from users servers on the forbidden_remote_server_names list
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 01:02:52 -05:00
strawberry 77e0b76408 apply new rustfmt.toml changes, fix some clippy lints
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 01:00:41 -05:00
strawberry 0317cc8cc5 rename conduit to conduwuit finally
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-14 22:24:45 -05:00
strawberry c6bf8f5ea1 improve gh actions security using zizmor
https://github.com/woodruffw/zizmor
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-14 21:00:33 -05:00
strawberry e4489a5d20 bump rust-rocksdb fork
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-13 21:59:37 -05:00
strawberry a9f6bb6169 remove jemalloc_prof and jemalloc_stats from all-features builds (exc. debug)
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-13 13:35:36 -05:00
strawberry 1b9c331049 use database::Json() to serialise MSC4133 profile value before insert
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-13 11:13:21 -05:00
strawberry 17273b1cea upload CI binaries to webserver for easy direct download
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-13 11:09:29 -05:00
Asen c5aca8036d add auto upload assets, upload binary to webserver
Co-authored-by: strawberry <strawberry@puppygock.gay>
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-13 01:57:49 -05:00
strawberry b73d558cba start producing haswell target optimised x86 binaries for rocksdb fast CRC32 support
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-13 01:57:45 -05:00
strawberry 76a5a67b6f fix a couple rust 2024 lints introduced in rust 1.82.0
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-12 10:22:30 -05:00
strawberry e0446181c5 remove unnecessary args in pack_receipts
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 22:07:53 -05:00
strawberry a26b1c5722 send private read receipt on sliding stink (sync)
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 22:02:48 -05:00
strawberry c9bb943a34 mark device list updates when a device is deleted/removed
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 21:25:40 -05:00
strawberry 353dc17af4 construct private read receipt properly
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 21:25:07 -05:00
strawberry 66a82447da log hostname in DNS error tracing spans
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 21:24:53 -05:00
strawberry 3e64a5c907 delete pointless bad_query_ratelimiter harming e2ee performance
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 19:46:34 -05:00
strawberry 5d51adc29d update complement test results
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 19:17:23 -05:00
strawberry 0740d7259a document modifying systemd unit if changing database path
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 18:22:51 -05:00
strawberry af08d3f7bd document 'DNS No connections available' troubleshooting
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 18:12:27 -05:00
strawberry 9ca964a97e update stored default push rules when removing legacy mentions
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 17:36:51 -05:00
strawberry 39abd9a827 (temp) drop sccache version down in CI to 0.8.2
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 16:38:29 -05:00
strawberry ac0545f773 always set limited true on left timeline events in sync (for now)
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 16:38:29 -05:00
strawberry 80f9536d21 rename config.rs to account_data.rs, refactor, add some missing checks
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 16:38:29 -05:00
strawberry ef8392cbbe allow empty POST request bodies (synapse behaviour) to improve compatibility
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 16:38:25 -05:00
strawberry 1e3bb02ced bump cargo.lock, bump some deps
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 14:26:15 -05:00
strawberry badb83484f fix private read receipt support
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 14:25:32 -05:00
Jason Volk 34f9e3260f additional sync v3 refactoring/optimizations and tracing instruments
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-10 06:20:30 +00:00
Jason Volk aba88ccead misc tracing span tweaks
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-10 06:20:30 +00:00
Jason Volk 5fc8e90e02 fix runtime metrics command
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-10 05:40:45 +00:00
Jason Volk cd67ca6c57 fix .gitignore to allow /target to be a symlink
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-10 05:40:45 +00:00
strawberry 9cb71e212a nix: bump flake.lock finally after 3 months
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 17:03:54 -05:00
strawberry 0ff37b829c update default systemd units to use network-online.target fully
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 13:33:24 -05:00
strawberry b6ac3649ee use fork of complement
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 13:04:13 -05:00
strawberry e1bd6a7c2d nix: try bumping to latest complement
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:52:06 -05:00
strawberry faf48405aa bump rocksdb to v9.8.4, enable track_and_verify_wals_in_manifest by default
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:52:06 -05:00
strawberry ab4a283870 update complement config
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:28:14 -05:00
strawberry 9d59f777d2 refactor fed membership endpoints, add missing checks, some cleanup, reduce line width
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:28:14 -05:00
strawberry 61670370ed add rocksdb paranoid_file_checks config option, add some more config checks
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:28:14 -05:00
strawberry 1606441d09 disable admin_room_notices for complement, update welcome text
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:28:14 -05:00
strawberry cf71aeef0b fix+improve membership endpoint UX, dont reuse old membership reasons, small parallelisation
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:28:14 -05:00
strawberry a1b0369033 reduce line width on banned_room_check
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:28:14 -05:00
strawberry c070edc189 fix profile updates reusing old membership content + small parallelise + remove unnecessary Result
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:28:14 -05:00
strawberry 35e9d9b02e fix duplicate timezone keys being sent on profile lookup requests
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-09 12:28:14 -05:00
Jason Volk a752fb9943 rename mod with tracing inits due to macro issues
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 20:33:25 +00:00
Jason Volk f70fdca828 remove jemalloc_stats from main default features
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 20:33:25 +00:00
Jason Volk 82133ee2ea bump rust-rocksdb
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:27 +00:00
Jason Volk ff56ee7413 add back the consume_budget on cache hits
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:27 +00:00
Jason Volk 6aa35260e6 misc database options tweaks
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:27 +00:00
Jason Volk 139a1ac504 configure the tokio runtime tunables
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:27 +00:00
Jason Volk 65a370836c derive specific ReadOptions for iterators
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:27 +00:00
Jason Volk aa6d0fcaa7 add unwrap_or_default() to future TryExt extension
start an OptionFuture extension

Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:27 +00:00
Jason Volk d921b82376 add options for console tracing EnvFilter details
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:26 +00:00
Jason Volk da984d49cf remove unnecessary tracing of pdu conversions
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:26 +00:00
Jason Volk b7a41f283f optimize sync v3 asynchronicity
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:26 +00:00
Jason Volk b77a1eb079 move cork to remove_to_device_events fn
add cork around write-heavy database routine called in loop; cleanup

Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:23 +00:00
Jason Volk 23cf2b2236 add is_err() to TryFuture extension
add fold_default to Future tools extension

Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:23 +00:00
Jason Volk de3b137df8 eliminate future wrapping stream for all_pdus()
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:23 +00:00
Jason Volk 8e8c6bfe07 abstract supported room versions apis
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:23 +00:00
Jason Volk f0a1aaf7bc extend x-platform support for binding URL previews to interfaces via address
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-08 07:12:23 +00:00
Jade Ellis 52cee65748 add support for binding to a specific interface for url previews
This is helpful to, for example, bind to an interface that can
only access the public internet. The resulting setup is less
maintenance-heavy / error-prone than manually maintaining a deny/
allowlist to protect internal resources.

Signed-off-by: Jade Ellis <jade@ellis.link>
2024-12-07 23:27:56 +00:00
strawberry fe1ce521aa add ignored user checks on /context and /event, misc cleanup
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-04 18:33:12 -05:00
strawberry ad0c5ceda4 add origin to tracing instrument logs on /send
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-04 17:13:39 -05:00
Jason Volk 68afdb22c7 force Cargo.lock version to 3
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 21:55:50 +00:00
Jason Volk 1d02851028 implement several broadband loops
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 21:50:20 +00:00
Jason Volk 59d5e3ebf1 additional stream extensions for any/all
additional stream extension TryBroadbandExt

Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 21:49:19 +00:00
Jason Volk c2d97aaa5e increase default db pool worker count for large systems
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 21:49:19 +00:00
Jason Volk 513236b3ce bump ruma for async state-res optimizations
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 00:51:57 +00:00
strawberry 9db0325b42 bump rust to 1.83.0
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-04 00:51:57 +00:00
morguldir e0494c1538 add /bin/conduit to OCI image contents
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-04 00:51:57 +00:00
Jason Volk 784ccd6bad return stream from multi_get_eventid_from_short
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 00:51:57 +00:00
Jason Volk 48703173bc split get_batch from get.rs; add aqry_batch
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 00:51:57 +00:00
Jason Volk c01b049910 move cidr_range_denylist from globals to client service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 00:51:57 +00:00
Jason Volk 9d9f403ad5 prevent adding presence timer for server's own user
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 00:51:57 +00:00
Jason Volk 3109c0daba perform async shutdown for database pool after services stop
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 00:51:57 +00:00
Jason Volk ef9b1c6303 simplify sender shutdown; prevent launching any retries
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 00:51:57 +00:00
Jason Volk b7df0a14c6 parallelize events_before and events_after in api/client/context
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 00:51:57 +00:00
Jason Volk b5006a4c41 offload initial iterator seeks to threadpool
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-03 13:25:33 +00:00
Jason Volk 320b0680bd pipeline various loops
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-03 13:25:33 +00:00
Jason Volk ed8c21ac9a modernize async srv lookup
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-03 13:25:33 +00:00
Jason Volk 9a9c071e82 use tokio for threadpool mgmt
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-03 07:39:02 +00:00
Jason Volk 89a158ab0b add delay before starting updates check
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-03 07:39:02 +00:00
Jason Volk 7d6710c033 add broadband stream extensions
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-03 07:39:02 +00:00
Jason Volk 61d9ac66fa add ref_at util macro
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-03 07:39:02 +00:00
Jason Volk 3b30bd3580 add try_filter_map to TryReadyExt
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-03 07:39:02 +00:00
Jason Volk 3fbd74310f impl transposed form of MapExpect
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-01 10:51:04 +00:00
Jason Volk 9263439af8 fix is_matching macro argument designator
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-01 10:51:04 +00:00
Jason Volk 4a3cc9fffa de-arc state_full_ids
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-30 08:38:12 +00:00
Jason Volk b5266ad9f5 parallelize sender edu selection
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-29 08:47:03 +00:00
Jason Volk 6175e72f1c simplify get_pdu() interface; eliminate unconditional Arc
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-29 08:47:02 +00:00
Jason Volk 58be22e695 fix new lints; clippy::unnecessary-map-or
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-29 06:58:45 +00:00
Jason Volk 2a9bb1ce11 add configurables for frontend pool options
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-28 07:20:43 +00:00
Jason Volk 3ad6aa59f9 use smallvec for db query buffering
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-28 06:03:33 +00:00
strawberry 76c75cc05a bump tracing fork
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-27 20:58:04 -05:00
Jason Volk c7ae951676 add frontend threadpool to database
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-27 10:53:44 +00:00
Jason Volk 94d7b21cf0 use stricter timeout for fetching state
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-27 06:30:20 +00:00
Jason Volk 2aeee4f509 parallel query for outlier/non-outlier pdu data
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-27 06:30:20 +00:00
Jason Volk dd8c646b63 optimize state compressor I/O w/ batch operation
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-27 06:30:20 +00:00
Jason Volk 527494a34b fix oversized tracing span arguments; lints
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-27 06:30:20 +00:00
Jason Volk e83fa12451 tweak dev profile
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-27 02:57:13 +00:00
Jason Volk 4f97ff98d6 enter the tokio runtime for the scope of main init
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-27 02:57:13 +00:00
Jason Volk f69c596f56 generalize return value wrapping to not require Arc
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-26 03:45:21 +00:00
Jason Volk 238523f177 cleanup: reuse api rather than querying db
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-26 03:45:21 +00:00
strawberry c5c74febb5 bump rust-rocksdb to 4bce1bb97d8be6f0d47245c99d465ca9cef33aad
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-25 16:32:09 -05:00
morguldir 63d1fcf213 add queued transactions rocksdb cf cache
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-25 16:08:30 -05:00
strawberry b20bd65d38 fix matrix-appservice-irc workaround
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-25 15:55:31 -05:00
Jason Volk 62d560e2fb improve tracing instruments on database::map
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-25 07:00:55 +00:00
Jason Volk 6c66391988 fix unnecessary serialization of sender query keys
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-25 06:50:15 +00:00
strawberry 6ccfc9ed98 slightly refactor appservice registration command
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-24 23:14:19 -05:00
strawberry e9fee04eef fix needlessly strict appservice user existence check
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-24 23:14:19 -05:00
strawberry 8611cc0ee9 fix ignored_filter check, exclude dummy events over sync
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-24 23:14:19 -05:00
Jason Volk 2592f83b69 add migration fix for duplicate readreceipt entries
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-25 02:54:29 +00:00
Jason Volk c903a71807 refactor and optimize receipt service data
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-25 02:54:29 +00:00
Jason Volk 343ec59a8b use arrayvec for integer deserialization buffer
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-25 02:54:29 +00:00
Jason Volk 6f1d50dda3 panic on otherwise ignored errors in debug mode
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-25 02:54:29 +00:00
strawberry 29c715a45f ci: remove some old/unnecessary paths-ignore
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-24 19:30:54 -05:00
strawberry 2675033aac send plain txt admin room error responses
fixes bracketed arguments not showing up on missing args

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-24 19:19:08 -05:00
strawberry b87362cbf1 ci: add test for validating generated example config is current
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-24 19:17:07 -05:00
Jason Volk 1c751168c6 check-in missed example config changes
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 23:50:05 +00:00
Jason Volk a582d0559a bump url and cargo lock
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 22:16:16 +00:00
Jason Volk 4e74a1811b ci: set cancel-in-progress to true
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 22:16:16 +00:00
Jason Volk 97ad9afc86 default to main event for batch tokens
fix prev_batch token for legacy sync timeline

Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 21:47:25 +00:00
Jason Volk c519a40cb8 use multiget for shortid conversions
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 21:30:32 +00:00
Jason Volk 3789d60b6a refactor to iterator inputs for auth_chain/short batch functions
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 21:30:32 +00:00
Jason Volk 5da42fb859 refactor account_data.changes_since to stream
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 21:30:31 +00:00
Jason Volk fd4c447a2d move attribute argument extractor to utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 07:11:26 +00:00
Jason Volk f30b08f015 fix optional config section related
split api/client well_known

simplify well_known config access

Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 07:11:26 +00:00
Jason Volk 5f1cab6850 passthru worker thread count from env
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-24 05:18:36 +00:00
strawberry 175e1c6453 correct admin cmd getting version and bin name
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-23 22:36:22 -05:00
strawberry af772b0240 various misc documentation improvements
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-23 22:35:54 -05:00
strawberry 3fe98f35f2 remove queued push keys on pusher deletion, use more refs
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-23 13:45:27 -05:00
strawberry 9d23a2b6f5 add missing length checks on pushkey/appid, improve error msgs for pusher
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-23 12:53:26 -05:00
strawberry f15370027e improve DNS error messages
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-23 12:05:52 -05:00
Jason Volk b94eeb9580 fix deletions on readreceipt update
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-22 09:38:34 +00:00
Jason Volk 3968d03868 move and improve common-rooms related
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-22 09:38:34 +00:00
Jason Volk aea82183b2 add set intersection util for two sorted streams
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-22 09:38:34 +00:00
Jason Volk bae0667066 limit sync response events to within the since/next_batch window
fixes #606

Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-22 09:02:01 +00:00
strawberry 5256cad396 ignore bare_urls lint for well_known client config option
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-21 23:49:46 -05:00
strawberry 9100af9974 add eventid_pdu database cf cache
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-21 23:45:16 -05:00
strawberry b6d53e97a6 bump ruwuma and a few http deps
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-21 23:44:50 -05:00
strawberry 336de49e6a tiny optimisation in append_pdu push notif
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-21 23:44:50 -05:00
emily ee3c58f78f docs: add workaround to use unix sockets with the nixos module 2024-11-20 11:14:05 -05:00
nisbet-hubbard 876c6e933c A minimal caveat 2024-11-20 09:41:11 -05:00
Jason Volk 2f2cebe84d implement local room preview
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-19 09:12:50 +00:00
Jason Volk e257512aa7 relax state visibility for invited modes
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-19 08:37:25 +00:00
Jason Volk 411c60009d enrich state iteration interface
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-19 08:37:25 +00:00
Jason Volk 7680d1bd5e replace yields point with consume_budget
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-19 08:37:25 +00:00
Jason Volk 8fedc358e0 typename additional shortids
cleanup/split state_compressor load

Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-19 08:37:25 +00:00
Jason Volk 90106c4c33 streamline batch insertions
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-19 08:37:25 +00:00
Jason Volk a05dc03100 use debug_warn for backfill event evals
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-19 08:37:25 +00:00
Jason Volk 26bcc7e312 fix default stateinfo cache size
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-17 00:15:13 +00:00
strawberry 85a6d8fc6b ci: fix github pages publish check
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-16 01:57:31 -05:00
Tamara Schmitz 2b2793fac6 docs: add note about the nixos service defaulting to sqlite
Co-authored-by: June 🍓🦴 <june@girlboss.ceo>
2024-11-16 00:18:58 -05:00
strawberry 8f14048528 ci: free up a bit of runner space safely (again)
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 23:48:55 -05:00
strawberry 7f96b2f92a nix: remove libllvm, libgcc, and llvm from OCI images as well
aarch64 OCI images love llvm??

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 23:18:12 -05:00
strawberry b92b4e043c drop hyper-util back down to 0.1.8 due to DNS issues
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 22:16:11 -05:00
strawberry 6319384072 implement GET /_matrix/client/v3/pushrules/global/
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 21:41:38 -05:00
strawberry ead9d66797 send the actual unsupported room version in join errors
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 21:28:08 -05:00
strawberry cd2c473bfe add missing fix_referencedevents_missing_sep key on fresh db creations
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 21:00:26 -05:00
Jason Volk 887ae84f1e optimize sha256 interface gather/vector inputs
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-16 00:33:40 +00:00
Jason Volk 14e3b242df add database get_batch stream wrapper
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-16 00:33:40 +00:00
Jason Volk 9f7a4a012b improve tracing/logging for state_compressor
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-16 00:33:40 +00:00
Jason Volk 5f625216aa slight optimizations for statediff
calculate with_capacity for set/get_statediff() etc

Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-16 00:33:40 +00:00
Jason Volk 20836cc3db flush=false for database-backup in read-only/secondary modes; improve error
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-16 00:33:40 +00:00
Jason Volk 59834a4b05 add is_read_only()/is_secondary() to Engine
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-16 00:33:40 +00:00
strawberry 4b652f5236 ok cargo doc
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 17:50:39 -05:00
strawberry be5a04f47c ci: install liburing-dev
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 17:09:36 -05:00
strawberry 9c95a74d56 fix getting canonical alias server for backfill
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 16:48:16 -05:00
strawberry 6b1b464abc add missing knock_restricted room type to /publicRooms
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 16:48:16 -05:00
strawberry f897b4daee ci: remove all free runner space steps due to flakiness
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 16:48:16 -05:00
strawberry 666989f74c delete trivy as lately its been terribly unreliable
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 16:48:16 -05:00
strawberry 9783bc78ba remove sentry_telemetry from default features
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 16:48:16 -05:00
strawberry c23786d37f dont try to backfill empty, private rooms
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 16:48:16 -05:00
strawberry a9c280bd4c document NAT hairpinning/loopback if needed
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 16:48:16 -05:00
strawberry c1f553cf4f bump rocksdb to v9.7.4, and ruwuma
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 16:48:11 -05:00
strawberry b4d809c681 add more checks for gh pages deployment workflow
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:49:54 -05:00
strawberry 3f69f2ee73 replace deprecated sha-1 crate, try to reduce some unnecessary crates/features
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:44:29 -05:00
strawberry dac1a01216 update generated example config
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:43:58 -05:00
strawberry 44a7ac0703 add debug_assert is_sorted for inline content types
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:41:17 -05:00
strawberry 011d44b749 add missing declared support for MSC3952
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:41:17 -05:00
strawberry 72fb8371f9 link to migrating from conduit on the README
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:41:17 -05:00
strawberry 4f0bdb5194 general misc bug fixes and slight improvements
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:41:17 -05:00
strawberry fd2a002480 dont build sentry or perf_measurements features for complement
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:41:17 -05:00
strawberry 4296d7174f add receive_ephemeral check for appservice EDU sending (if it even works)
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:41:17 -05:00
strawberry 4fe47903c2 misc docs changes/improvements from example config
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:41:17 -05:00
strawberry 08365bf5f4 update config documentation, commit generated example config
also removes the no-op/useless "database_backend" config option

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-15 09:41:17 -05:00
Jason Volk 4ec5d1e28e replace additional use tracing::
add log:: to disallowed-macros

Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-14 04:50:07 +00:00
Jason Volk e228dec4f2 add byte counting for compressed state caches
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-13 23:14:05 +00:00
Jason Volk 6ffdc1b2a6 bump serde, image, loole, termimad etc
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-13 22:59:28 +00:00
Jason Volk 004be3bf00 prepare utf-8 check bypass for database deserializer
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-13 22:59:28 +00:00
Jason Volk 77fab2c323 use ruma visibility enum in directory interface
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-13 02:38:03 +00:00
Jason Volk 68582dd868 add parallel query for current membership state
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-13 02:38:03 +00:00
Jason Volk feefa43e65 add pretty/si-unit byte size parsing/printing utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-13 02:38:03 +00:00
strawberry c59f474aff fixes for gh workflow
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-13 02:38:03 +00:00
Jason Volk 86694f2d1d move non-generic code out of generic; reduce codegen
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-13 02:38:03 +00:00
Jason Volk 999d731a65 move err macro visitor out-of-line; reduce codegen
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-11 22:45:44 +00:00
Jason Volk 3962333043 partially revert e507c31306
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-11 21:35:30 +00:00
Jason Volk 61174dd0d3 check if lazyset already contains user prior to querying
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-11 21:30:48 +00:00
Jason Volk e2afaa9f03 add config item for with_span_events
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-11 20:50:05 +00:00
Jason Volk 9790a6edc9 add unwrap_or_err to result
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-11 20:50:05 +00:00
Jason Volk 08a4e931a0 supplement a from_str for FmtSpan
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-11 20:50:05 +00:00
OverPhoenix 24a5ecb6b4 fix incorrect user id for non-admin invites checking 2024-11-10 22:24:35 +00:00
Jason Volk 1efc52c440 increase logging during server keys acquire
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-10 11:17:42 +00:00
Jason Volk f290d1a9c8 prevent retry for missing keys later in join process
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-10 08:47:15 +00:00
strawberry 7e087bb93c Fixes for CI
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-10 04:33:30 +00:00
Jason Volk 5e74391c6c fix config generator macro matchers
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-10 04:33:30 +00:00
Jason Volk cc86feded3 bump ruma
fixes for key type changes

Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-10 04:33:30 +00:00
Jason Volk 14fce38403 cork around send_join response processing
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-10 04:33:30 +00:00
Jason Volk 10be301646 split large notary requests into batches
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-10 04:33:29 +00:00
Jason Volk 1ce3db727f split event_handler service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-08 09:21:42 +00:00
Jason Volk 6eba36d788 split make_body template
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-08 09:21:42 +00:00
Jason Volk f59e8af734 slight cleanup/simplifications to backfil
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-08 09:21:30 +00:00
Jason Volk 1f2e939fd5 optional arguments for timeline pdus iterations
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-08 08:22:54 +00:00
Jason Volk 13ef6dcbcf add standalone getters for shortid service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-08 06:09:04 +00:00
Jason Volk 27966221f1 add ready_try_fold to utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-08 06:09:04 +00:00
Jason Volk 79c6b51860 renames for core pdu
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-08 06:09:04 +00:00
Jason Volk e507c31306 make pdu batch tokens zeroith-indexed
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-08 06:06:18 +00:00
Jason Volk f36757027e split api/client/room
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-06 21:46:20 +00:00
Jason Volk 7450c654ae add get_pdu_owned sans Arc; improve client/room/event handler
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-06 21:46:20 +00:00
Jason Volk 3ed2c17f98 move sync watcher from globals service to sync service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-06 21:46:20 +00:00
Jason Volk 26c890d5ac skip redundant receipts on syncs
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-06 21:46:20 +00:00
Jason Volk 137e3008ea merge rooms threads data and service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-06 21:46:20 +00:00
Jason Volk 9da523c004 refactor for stronger RawPduId type
implement standard traits for PduCount

enable serde for arrayvec

typedef various shortid's

pducount simplifications

split parts of pdu_metadata service to core/pdu and api/relations

remove some yields; improve var names/syntax

tweak types for limit timeline limit arguments

Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-06 21:46:20 +00:00
Kirill Hmelnitski 2e4d9cb37c fix thread pagination
refactor logic

increase fetch limit for first relates

apply other format

Co-authored-by: Jason Volk <jason@zemos.net>
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-04 19:25:31 +00:00
Jason Volk 78aeb620bc add broad timeout on acquire_origins keys operation
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-04 19:25:31 +00:00
Jason Volk 4a94a4c945 rename pdu/id to pdu/event_id
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-04 19:25:31 +00:00
Jason Volk 768e81741c use FnMut for ready_try_for_each extension
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 14:51:07 +00:00
Jason Volk 8d251003a2 reduce Error-related codegen; add PoisonError
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 14:51:07 +00:00
Jason Volk 52f09fdb51 add database migration for missing referencedevents separator
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 14:50:28 +00:00
Jason Volk f191b4bad4 add map_expect for stream
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 14:50:28 +00:00
Jason Volk 8742437036 wrap unimplemented ser/de branches with internal macro
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk ba1c134689 move migrations out of globals service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk 1f1e2d547c optimize override ips; utilize all ips from cache
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk f746be82c1 typename some loose u64 ShortId's
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk 0bc6fdd589 Refactor ShortStateInfo et al to properly named structures
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk 6b0eb7608d add Filter extension to Result
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk e49aee61c1 consolidate and parallelize api/server access check prologues
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk 7fcc6d11a4 de-wrap state_accessor.server_can_see_event
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk 0eb67cfea0 additional bool extensions for Result/Option conversion
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk 9775694423 inline database stream interface functions lt 64B
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 07:32:09 +00:00
Jason Volk a7cb1c5951 slightly optimize request signing/verifying
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 07:32:09 +00:00
Jason Volk ed76797b55 add raw_ overloads for prefix/from counting
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 07:32:09 +00:00
Jason Volk ad117641b8 add tuple-apply macro with length argument for now
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 07:32:09 +00:00
Jason Volk 1fbfc983e9 optimize FedDest::Named port
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 07:32:09 +00:00
strawberry 0387871063 add workaround for matrix-appservice-irc using historical localparts
see https://github.com/matrix-org/matrix-appservice-irc/issues/1780

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-02 21:20:36 -04:00
strawberry 6f37a251fb allow taking room aliases for auto_join_rooms config option
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-02 20:55:40 -04:00
strawberry 9466aeb088 remove some unnecessary debug prints on notices
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-02 18:52:25 -04:00
strawberry ee6af6c90e drop report delay response range to 2-5 secs
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-02 18:46:20 -04:00
strawberry 6cbaef2d12 always set RUST_BACKTRACE=full in OCI images
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-02 13:17:31 -04:00
strawberry 240c78e810 strong-type URL for URL previews to Url type
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-02 13:17:22 -04:00
strawberry 8ed9d49b73 skip new flakey complement test
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-31 14:41:35 -04:00
Jason Volk 354dc9e703 add map accessor to Database; move cork interface
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-28 20:52:52 -04:00
strawberry 567a4cb441 implement admin command to force join all local users to room
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-28 20:52:52 -04:00
strawberry c71db93e22 implement admin command to force join list of local users
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-28 20:52:52 -04:00
strawberry 0a281241ef bump few dependencies, bump ruwuma
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-28 20:52:52 -04:00
strawberry 85890ed425 remove some unnecessary HTML from admin commands
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-28 20:52:52 -04:00
strawberry 065396f8f5 better document allow_inbound_profile_lookup_federation_requests
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-28 20:52:52 -04:00
strawberry d92f2c121f document nginx needing request_uri
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-28 20:52:52 -04:00
Jason Volk 52e356d780 generate ActualDest https string on the fly
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-28 20:52:52 -04:00
Jason Volk 7a09ac81e0 split send from messages; refactor client/messages; add filters to client/context
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-28 20:52:52 -04:00
Jason Volk 6c9ecb031a re-export ruma Event trait through core pdu
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 21:38:49 +00:00
Jason Volk e7e606300f slightly simplify reqwest/hickory hooks
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 19:17:41 +00:00
Jason Volk 9787dfe77c fix clippy::ref_option
fix needless borrow

fix clippy::nonminimal_bool
2024-10-27 02:11:07 +00:00
Jason Volk 5e6dbaa27f apply room event filter to messages endpoint (#596)
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 02:11:07 +00:00
Jason Volk d281b8d3ae implement filters for search (#596)
closes #596

Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 02:11:07 +00:00
Jason Volk 21a67513f2 refactor search system
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 02:11:07 +00:00
Jason Volk f245389c02 add typedef for pdu_ids
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:11:50 +00:00
Jason Volk 1e7207c230 start an ArrayVec extension trait
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:11:50 +00:00
Jason Volk 0426f92ac0 unify database record separator constants
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:11:50 +00:00
Jason Volk 6808671751 merge search service w/ data
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:11:50 +00:00
Jason Volk b7369074d4 add RoomEventFilter matcher for PduEvent
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:11:50 +00:00
Jason Volk cf59f738b9 move macros incorrectly moved out of utils to top level
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:11:50 +00:00
Jason Volk 8742266ff0 split up core/pdu
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:11:50 +00:00
Jason Volk ee92a33a4d add some accessors to Ar for common patterns
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:11:50 +00:00
Jason Volk 60cc07134f log error for auth_chain corruption immediately
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:09:05 +00:00
Jason Volk e175b7d28d slightly cleanup prev_event eval loop
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:09:05 +00:00
Jason Volk 0e616f1d12 add event macro log wrapper suite
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:09:05 +00:00
Jason Volk 9438dc89e6 merge and resplit/cleanup appservice service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:09:05 +00:00
Jason Volk efb28c1a99 add a Map::contains suite to db
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:09:05 +00:00
Jason Volk 49343281d4 additional bool extensions
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 00:09:05 +00:00
strawberry b921983a79 send room alias on pusher notification
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-26 18:50:29 -04:00
strawberry 60d84195c5 implement MSC4210, bump ruwuma
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-26 18:50:29 -04:00
strawberry d6991611f0 add require_auth_for_profile_requests config option, check endpoint metadata instead of request string
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-26 18:50:29 -04:00
strawberry 0efe24a028 remove spaces from CSP header to save a few bytes
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-26 18:50:29 -04:00
strawberry 2ce91f33af log method on tracing req spans, fix path sometimes being truncated
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-26 18:50:29 -04:00
strawberry 652b04b9b6 update conduwuit freebsd docs
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-26 18:50:29 -04:00
strawberry f29879288d document conduwuit k8s helm chart
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-26 18:50:29 -04:00
strawberry 89cc865868 bump conduwuit to 0.5.0
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-26 18:50:29 -04:00
Jason Volk aa768b5dec distill active and old keys for federation key/server response
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk c769fcc347 move core result into core utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 5cb0a5f676 add config generator controls via attribute metadatas
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 367d153380 add default-directives to config document comments
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 3396542168 complete the example-config generator macro
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk b08c1241a8 add some interruption points in recursive event handling to prevent shutdown hangs
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk dd6621a720 reduce unnecessary clone in pdu handler
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk b8260e0104 optimize for pdu_exists; remove a yield thing
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk ca57dc7928 optimize config denylists
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk d35376a90c aggregate receipts into single edu; dedup presence; refactor selection limits etc
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk a74461fc9a split keys_changed for stronger-type overloads
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 0e0438e1f9 further optimize presence_since iteration
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk c06f560913 add some additional database::de test cases
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 167807e0a6 de-wrapper max_fetch_prev_event; increase default config
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 0e55fa2de2 add ready_try_for_each to TryReadyExt extension utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk b505f0d0d7 add (back) query_trusted_key_servers_first w/ additional configuration detail
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk ac75ebee8a event_handler/timeline service cleanups
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 93130fbb85 add is_ok to futures TryExtExt utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 1fdcab0319 additional sync cleanup
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 828cb96ba9 split client/sync
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 55b8908894 merge rooms state_compressor service and data
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 84191656fb slightly cleanup appservice_in_room
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 0b085ea84f merge remaining rooms state_cache data and service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 4576313a7c merge rooms user service and data
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk ed5b5d7877 merge rooms state service and data
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk d0ee4b6d25 add resolve_with_servers() to alias service; simplify api
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk b4ec1e9d3c add federation client for select high-timeout requests
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk c0939c3e9a Refactor server_keys service/interface and related callsites
Signed-off-by: Jason Volk <jason@zemos.net>
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-26 18:50:29 -04:00
Jason Volk d82ea331cf add random shuffle util
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 1a09eb0f02 use string::EMPTY; minor formatting and misc cleanups
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 89b5c4ee1c add timepoint_from_now to complement timepoint_ago in utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 2ed0c267eb Refactor for structured insertions
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 8258d16a94 re-scheme naming of stream iterator overloads
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 19880ce12b add IgnoreAll directive to deserializer
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk d3d11356ee add serialized insert interface
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 2f24d7117a further develop serializer for insertions
add JSON delegator to db serializer

consolidate writes through memfun; simplifications

Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk fc4d109f35 add document comments to config items
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk f67cfcd535 cleanup Config::load()
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 2a59a56eaa initial example-config generator
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk c40d20cb95 add macro util to determine if cargo build or check/clippy.
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 43b0bb6a5e add non-allocating fixed-size random string generator
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk a5e85727b5 add tuple access functor-macro
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 16f82b02a0 add util to restore state on scope exit
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk c9c405facf relax Sized bound for debug::type_name
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk 8ea2dccc9a sort rustfmt
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:29 -04:00
Jason Volk e482c0646f Add constructions and Default for PduBuilder
simplify various RoomMemberEventContent constructions

Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk f503ed918c misc cleanup
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 57e0a5f65d additional database stream deserializations for serde_json::from_ elim
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk d526db681f refactor various patterns for serde_json::from_ elim
bump ruma

Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 55c85f6851 refactor to pdu.get_content() for serde_json::from_ elim
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk f7af6966b7 refactor to room_state_get_content() for serde_json::from_ elim
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 68315ac112 Add state_get_content(shortid) for serde_json::from elim
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk da34b43302 abstract account-data deserializations for serde_json::from_elim
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 48a767d52c abstract common patterns as core pdu memberfns
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 2b2055fe8a parallelize calculate_invite_state
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 685eadb171 add is_not_found as Error member function; tweak interface; add doc comments
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk dd9f53080a add unwrap_or to TryFutureExtExt
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 4485f36e34 add mactors for true/false
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk a2e5c3d5d3 add FlatOk trait to Result/Option suite
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 08a2fecc0e catch panics at base functions to integrate with other fatal errors.
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 89a3c80700 split admin-room branch from build_and_append_pdu (fixes large stack warning)
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 56dd0f5139 use loop condition to account for loole channel close
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
Jason Volk 814b9e28b6 fix unnecessary re-serializations
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-26 18:50:28 -04:00
strawberry 8eec78e9e0 mark the server user bot as online/offline on shutdown/startup
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:45 -04:00
morguldir 9eace1fbbb fix sliding sync room type filter regression
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:45 -04:00
Jason Volk ba683cf534 fix aliasid_alias key deserialization
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:38:45 -04:00
Jason Volk bd9a9cc5f8 fix trait-solver issue requiring recursion_limit increase
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:38:45 -04:00
Jason Volk 2d049dacc3 fix get_all_media_keys deserialization
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:38:45 -04:00
Jason Volk c6b7c24e99 consume all bytes for top-level Ignore; add comments/tweaks
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:38:45 -04:00
strawberry fa7c1200b5 miniscule spaces code optimisations
still terrible though

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:45 -04:00
strawberry bd56d83045 fix room directory regression
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:45 -04:00
strawberry ab9a65db5d add MSC4151 room reporting support
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:45 -04:00
strawberry 54a107c3c4 drop unnecessary error to debug_warn
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:45 -04:00
strawberry 98363852b1 fix: dont add remote users for push targets, use hashset instead of vec
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:45 -04:00
strawberry 4eb7ad79d1 update last_seen_ip and last_seen_ts on updating device metadata
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:45 -04:00
strawberry 115ea03edf remove unnecessary full type annos
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:18 -04:00
strawberry a9e3e8f77a dont send non-state events from ignored users over /context/{eventId}
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:18 -04:00
strawberry 6a81bf23de dont send events from ignored users over /messages
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:18 -04:00
strawberry 7a59add8f1 add support for reading a registration token from a file
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:18 -04:00
strawberry ee1580e480 fix list_rooms admin command filters
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:18 -04:00
strawberry b64a235165 use ok_or_else for a rare error
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:18 -04:00
strawberry 4413793f7e dont allow sending/receiving room invites with ignored users
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:18 -04:00
strawberry 2083c38c76 dont send non-state events from ignored users over sync
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:18 -04:00
strawberry 890ee84f71 dont send read receipts and typing indicators from ignored users
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:18 -04:00
strawberry fafe320899 send EDUs to appservices if in events
to_device is not supported yet

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:38:14 -04:00
strawberry 8311952629 bump ruma, cargo.lock, and deps
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:37:15 -04:00
Jason Volk 36677bb982 optimize auth_chain short_id to event_id translation step
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:36:30 -04:00
Jason Volk ab06701ed0 refactor multi-get to handle result type
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:36:30 -04:00
Jason Volk 26dcab272d various cleanup tweaks/fixes
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:36:30 -04:00
Jason Volk 96fcf7f94d add rocksdb secondary; fix read_only mode.
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:36:30 -04:00
Jason Volk 6b80361c31 additional stream tools
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:36:30 -04:00
Jason Volk a8d5cf9651 Add rocksdb logging integration with tracing.
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:36:30 -04:00
Jason Volk c569881b08 merge rooms/short Data w/ Service; optimize queries
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:36:28 -04:00
Jason Volk 0e8ae1e13e add ArrayVec-backed serialized query overload; doc comments
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:32:33 -04:00
Jason Volk 5192927a53 split remaining map suites
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:32:33 -04:00
strawberry 4496cf2d5b add missing await to first admin room creation
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-25 00:32:33 -04:00
Jason Volk 3f7ec4221d minor auth_chain optimizations/cleanup
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:32:33 -04:00
Jason Volk 4776fe66c4 handle serde_json for deserialized()
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:32:33 -04:00
Jason Volk 946ca364e0 Database Refactor
combine service/users data w/ mod unit

split sliding sync related out of service/users

instrument database entry points

remove increment crap from database interface

de-wrap all database get() calls

de-wrap all database insert() calls

de-wrap all database remove() calls

refactor database interface for async streaming

add query key serializer for database

implement Debug for result handle

add query deserializer for database

add deserialization trait for option handle

start a stream utils suite

de-wrap/asyncify/type-query count_one_time_keys()

de-wrap/asyncify users count

add admin query users command suite

de-wrap/asyncify users exists

de-wrap/partially asyncify user filter related

asyncify/de-wrap users device/keys related

asyncify/de-wrap user auth/misc related

asyncify/de-wrap users blurhash

asyncify/de-wrap account_data get; merge Data into Service

partial asyncify/de-wrap uiaa; merge Data into Service

partially asyncify/de-wrap transaction_ids get; merge Data into Service

partially asyncify/de-wrap key_backups; merge Data into Service

asyncify/de-wrap pusher service getters; merge Data into Service

asyncify/de-wrap rooms alias getters/some iterators

asyncify/de-wrap rooms directory getters/iterator

partially asyncify/de-wrap rooms lazy-loading

partially asyncify/de-wrap rooms metadata

asyncify/dewrap rooms outlier

asyncify/dewrap rooms pdu_metadata

dewrap/partially asyncify rooms read receipt

de-wrap rooms search service

de-wrap/partially asyncify rooms user service

partial de-wrap rooms state_compressor

de-wrap rooms state_cache

de-wrap room state et al

de-wrap rooms timeline service

additional users device/keys related

de-wrap/asyncify sender

asyncify services

refactor database to TryFuture/TryStream

refactor services for TryFuture/TryStream

asyncify api handlers

additional asyncification for admin module

abstract stream related; support reverse streams

additional stream conversions

asyncify state-res related

Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:32:30 -04:00
Jason Volk 6001014078 add UnwrapInfallible to Result
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk a5de27442a re-export crates used by error macros
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk f7ce4db0b0 add is_not_found functor to error; tweak status code matcher
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk a5822ebc27 add missing err! case
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk 63053640f1 add util functors for is_zero/is_equal; move clamp to math utils
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk bd75ff65c9 move common_elements util into unit
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk aa265f7ca4 add err log trait to Result
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk 3d4b0f10a5 add expected! macro to checked math expression suite
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk 2709995f84 add MapExpect to Result
add DebugInspect to Result

move Result typedef into unit

Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk 99ad404ea9 add str traits for split, between, unquote; consolidate tests
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
Jason Volk 2db017af37 simplify service trait bounds and lifetimes
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:15:01 -04:00
strawberry 16014e1594 remove ProcSubset=pid from systemd units for now
they appear to cause strange rust malloc issues on Debian systems

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 23:51:02 -04:00
strawberry 7e828440f9 allow conduit database version 16
Conduit bumped the database version to 16, but did not introduce any
breaking changes. Their database migrations are extremely fragile and risky,
and also do not really apply to us, so just to retain Conduit -> conduwuit
compatibility we'll check for both versions.

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 23:44:15 -04:00
strawberry f6918833d7 remove -unknown- from nix flake
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 23:04:14 -04:00
strawberry 4d7bbe9fb4 tiny micro-optimisations in some config stuff
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 22:37:40 -04:00
strawberry 75be68fa61 add config option to control sending admin notices of alerts
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 22:37:34 -04:00
strawberry 0760150822 cache all 3 x86_64 nix devshells in CI
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 22:08:23 -04:00
strawberry 37a2ba59d0 improve UX of admin media deletion commands, ignore errors by default, support deleting local media too
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 22:02:58 -04:00
strawberry 724711218a add note that ko-fi takes a fee
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 22:02:58 -04:00
strawberry 359fb25262 add missing feat_sha256_media to fresh database creations
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 22:02:51 -04:00
strawberry 9761e2f10c fix lockdown_public_room_directory bypass, add appservice exclusion
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 21:38:26 -04:00
strawberry 30e3e45f9f misc CI improvements, build macOS binaries, flake improvements/fixes
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 21:29:17 -04:00
strawberry e5efd55838 feature-gate direct TLS mode to make rustls/aws-lc-rs optional
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:54:21 -04:00
strawberry 87734a074f add m.call and m.call.member to list of permissions to set on public rooms
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:53:31 -04:00
strawberry a7c4a7933d disable log colours in the complement config
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:52:14 -04:00
strawberry 83becf013c add config option to disable ANSI log colours
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:51:54 -04:00
strawberry acb9eae707 add back server name to error sending PDU to remote server
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:51:50 -04:00
strawberry 2eee454a18 docs: nixos and unix socket fail, jemalloc and hardened.nix
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:50:52 -04:00
strawberry e0b2595905 support reading TURN secret from a file (turn_secret_file)
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:49:23 -04:00
strawberry 73afc1fd8f allow taking multiple --config arguments to "include"/merge more config files
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:49:17 -04:00
strawberry 6acdd0d947 improve some general documentation
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:49:13 -04:00
strawberry e38c37d9e7 allow users to respond to polls by default (org.matrix.msc3381.poll.response)
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:49:08 -04:00
strawberry 45254638b1 drop target-cpu optimised builds
this seems too broken.

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:48:59 -04:00
strawberry 2d54264fbe bump rust to 1.82.0, rocksdb v9.7.3, ruwuma, and a few nix pkgs
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-24 20:47:51 -04:00
Toby Murray 6c1c7b35a5 Separate command lines
I don't think this works if the commands are invoked on the same line with no thing joining them, so separate them on to separate lines.
2024-10-24 15:09:28 -04:00
nisbet-hubbard 8428e7cdf7 Update generic.md 2024-10-19 12:35:20 -04:00
strawberry e589464954 bump cargo.lock and deps
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-10-05 22:33:58 -04:00
Jason Volk 0413037246 fix lints
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-05 17:07:37 -07:00
Jacob Taylor b9a8f8e6c7 automatically scale conduwuit caches by CPU-core-count 2024-10-05 17:07:37 -07:00
strawberry 032b199129 add db query command to get all pushers for a user
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-15 19:56:29 -04:00
strawberry e9e5fe2176 implement MSC4165, removing own power levels on deactivation
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-15 14:20:01 -04:00
strawberry 17fd34eb12 dedupe some account deactivation steps, remove all profile fields on deactivation
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-15 12:08:07 -04:00
strawberry 895b178720 add admin command to force demote a local user from a room
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-15 11:36:47 -04:00
strawberry a65dd6dfb3 dont allow guests to publish to room directories
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-14 12:37:29 -04:00
strawberry e146c75279 dont include appservices in room guest access enforcement check
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-14 12:27:22 -04:00
strawberry d75aebc373 implement generic K-V support for MSC4133, GET/PUT/DELETE
no PATCH still yet

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-14 11:16:49 -04:00
morguldir 80b72637e2 ci: enable cachix after restoring the cache
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-09-13 05:09:10 +02:00
morguldir a41e63b40e Add back allow_check_for_updates
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-09-12 22:51:31 -04:00
strawberry cf9b72ce3f remove a few unnecessary muts
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-09 21:41:57 -04:00
strawberry 38552b36e9 make the first user admin if created from CLI / --execute
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-09 21:13:37 -04:00
strawberry 9de780b56c remove unnecessary displayname requirement on making user admin
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-09 21:10:56 -04:00
strawberry 55f71d3912 bump conduwuit to 0.4.7
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-08 19:56:53 -04:00
strawberry 61347bee06 advertise support for MSC4133 and MSC4175
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-08 19:53:33 -04:00
strawberry 38cd88e1e8 remove unnecessary cloning on account deactivation profile updates
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-08 19:33:21 -04:00
strawberry b44f7f5476 remove MSC4175 timezone on account deactivation
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-08 19:23:54 -04:00
strawberry e888810e67 update complement results for TestFederationThumbnail
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-08 16:22:02 -04:00
morguldir 02aee2f174 ci: retry attic push 3 times, and continue on errors
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-09-08 20:51:34 +02:00
morguldir 24c408f4c6 bump rocksdb to 9.6.1, add binutils to devshell 2024-09-08 19:21:23 +02:00
morguldir 1c1f300efe ci: avoid propagating bash errors immidiately
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-09-08 17:41:02 +02:00
morguldir 8dccc04b40 nix: explicitly include liburing in the devshell
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-09-08 17:40:02 +02:00
strawberry 96ab59b5b0 bump cargo.lock
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-08 10:28:21 -04:00
strawberry c47337f3db docs: ignore development.md and contributing.md from lychee
and update 2 other nix references

Signed-off-by: strawberry <strawberry@puppygock.gay>
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-09-08 10:24:38 -04:00
morguldir 3e0d404fb4 syncv3: use RoomTypeFilter struct instead of Option<RoomType>
Signed-off-by: morguldir <morguldir@protonmail.com>
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-07 18:09:21 +02:00
morguldir 593d3bb321 nix: update flake.lock, skip building tests for liburing
Signed-off-by: morguldir <morguldir@protonmail.com>
2024-09-08 05:03:30 +02:00
strawberry f14a253664 add local_only arg to list joined members in room admin cmd
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-07 12:46:59 -04:00
strawberry b3974c569d log device display name on normal user registrations too
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-07 10:10:46 -04:00
strawberry f163ebf3bb implement MSC4133 only with MSC4175 for GET/PUT/DELETE
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-07 09:27:35 -04:00
strawberry 5ae9a5ff31 bump nix lockfile, and ruma
• Updated input 'attic':
    'github:zhaofengli/attic/6d9aeaef0a067d664cb11bb7704f7ec373d47fb2' (2024-08-21)
  → 'github:zhaofengli/attic/bea72d75b6165dfb529ba0c39cc6c7e9c7f0d234' (2024-09-02)
• Added input 'attic/flake-parts':
    'github:hercules-ci/flake-parts/8471fe90ad337a8074e957b69ca4d0089218391d' (2024-08-01)
• Added input 'attic/flake-parts/nixpkgs-lib':
    follows 'attic/nixpkgs'
• Updated input 'attic/nixpkgs':
    'github:NixOS/nixpkgs/d4a7a4d0e066278bfb0d77bd2a7adde1c0ec9e3d' (2024-08-16)
  → 'github:NixOS/nixpkgs/b96f849e725333eb2b1c7f1cb84ff102062468ba' (2024-08-30)
• Updated input 'attic/nixpkgs-stable':
    'github:NixOS/nixpkgs/205fd4226592cc83fd4c0885a3e4c9c400efabb5' (2024-07-09)
  → 'github:NixOS/nixpkgs/797f7dc49e0bc7fab4b57c021cdf68f595e47841' (2024-08-22)
• Updated input 'complement':
    'github:matrix-org/complement/6e4426a9e63233f9821a4d2382bfed145244183f' (2024-07-30)
  → 'github:matrix-org/complement/39733c1b2f8314800776748cc7164f9a34650686' (2024-08-22)
• Updated input 'crane':
    'github:ipetkov/crane/7ce92819802bc583b7e82ebc08013a530f22209f' (2024-08-18)
  → 'github:ipetkov/crane/7e4586bad4e3f8f97a9271def747cf58c4b68f3c' (2024-09-04)
• Removed input 'crane/nixpkgs'
• Updated input 'fenix':
    'github:nix-community/fenix/e88b38a5a3834e039d413a88f8150a75ef6453ef' (2024-08-21)
  → 'github:nix-community/fenix/d9afdb4465ba2f20bb73b0ff5d2c2837cafc2e14' (2024-09-06)
• Updated input 'fenix/rust-analyzer-src':
    'github:rust-lang/rust-analyzer/3723e5910c14f0ffbd13de474b8a8fcc74db04ce' (2024-08-20)
  → 'github:rust-lang/rust-analyzer/124c7482167ff6eea4f7663c0be87ea568ccd8c6' (2024-09-05)
• Updated input 'liburing':
    'github:axboe/liburing/2d4e799017d64cd2f8304503eef9064931bb3fbd' (2024-08-21)
  → 'github:axboe/liburing/0fe5c09195c0918f89582dd6ff098a58a0bdf62a' (2024-09-06)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/36a9aeaaa17a2d4348498275f9fe530cd4f9e519' (2024-08-21)
  → 'github:NixOS/nixpkgs/ad416d066ca1222956472ab7d0555a6946746a80' (2024-09-04)

Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-07 09:27:29 -04:00
strawberry 6f643a4b06 bump rust to 1.81.0
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-06 21:08:21 -04:00
strawberry 80698c0b17 docs: add some more conduwuit development info
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-06 20:33:02 -04:00
strawberry 909eeac5b0 drop target CPU for aarch64 to cortex-a53 instead of cortex-a73
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-06 19:02:04 -04:00
strawberry f521f88daf docs: mildly update the NixOS page to ref https://github.com/NixOS/nixpkgs/pull/339260
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-09-06 19:00:38 -04:00
501 changed files with 50130 additions and 28730 deletions
+1
View File
@@ -21,3 +21,4 @@ indent_size = 2
[*.rs]
indent_style = tab
max_line_length = 98
+87
View File
@@ -0,0 +1,87 @@
# taken from https://github.com/gitattributes/gitattributes/blob/46a8961ad73f5bd4d8d193708840fbc9e851d702/Rust.gitattributes
# Auto detect text files and perform normalization
* text=auto
*.rs text diff=rust
*.toml text diff=toml
Cargo.lock text
# taken from https://github.com/gitattributes/gitattributes/blob/46a8961ad73f5bd4d8d193708840fbc9e851d702/Common.gitattributes
# Documents
*.bibtex text diff=bibtex
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
*.md text diff=markdown
*.mdx text diff=markdown
*.tex text diff=tex
*.adoc text
*.textile text
*.mustache text
*.csv text eol=crlf
*.tab text
*.tsv text
*.txt text
*.sql text
*.epub diff=astextplain
# Graphics
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.tif binary
*.tiff binary
*.ico binary
# SVG treated as text by default.
*.svg text
*.eps binary
# Scripts
*.bash text eol=lf
*.fish text eol=lf
*.ksh text eol=lf
*.sh text eol=lf
*.zsh text eol=lf
# These are explicitly windows files and should use crlf
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
# Serialisation
*.json text
*.toml text
*.xml text
*.yaml text
*.yml text
# Archives
*.7z binary
*.bz binary
*.bz2 binary
*.bzip2 binary
*.gz binary
*.lz binary
*.lzma binary
*.rar binary
*.tar binary
*.taz binary
*.tbz binary
*.tbz2 binary
*.tgz binary
*.tlz binary
*.txz binary
*.xz binary
*.Z binary
*.zip binary
*.zst binary
# Text files where line endings should be preserved
*.patch -text
-8
View File
@@ -1,8 +0,0 @@
<!-- Please describe your changes here -->
-----------------------------------------------------------------------------
- [ ] I ran `cargo fmt`, `cargo clippy`, and `cargo test`
- [ ] I agree to release my code and all other changes of this MR under the Apache-2.0 license
-264
View File
@@ -1,264 +0,0 @@
name: CI and Artifacts
on:
pull_request:
push:
# documentation workflow deals with this or is not relevant for this workflow
paths-ignore:
- '*.md'
- 'conduwuit-example.toml'
- 'book.toml'
- '.gitlab-ci.yml'
- '.gitignore'
- 'renovate.json'
- 'docs/**'
- 'debian/**'
- 'docker/**'
branches:
- main
tags:
- '*'
# Allows you to run this workflow manually from the Actions tab
#workflow_dispatch:
#concurrency:
# group: ${{ gitea.head_ref || gitea.ref_name }}
# cancel-in-progress: true
env:
# Required to make some things output color
TERM: ansi
# Publishing to my nix binary cache
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }}
# conduwuit.cachix.org
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
# Just in case incremental is still being set to true, speeds up CI
CARGO_INCREMENTAL: 0
# Custom nix binary cache if fork is being used
ATTIC_ENDPOINT: ${{ vars.ATTIC_ENDPOINT }}
ATTIC_PUBLIC_KEY: ${{ vars.ATTIC_PUBLIC_KEY }}
# Get error output from nix that we can actually use
NIX_CONFIG: show-trace = true
#permissions:
# packages: write
# contents: read
jobs:
tests:
name: Test
runs-on: ubuntu-latest
steps:
- name: Sync repository
uses: https://github.com/actions/checkout@v4
- name: Tag comparison check
if: startsWith(gitea.ref, 'refs/tags/v')
run: |
# Tag mismatch with latest repo tag check to prevent potential downgrades
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
if [ $LATEST_TAG != ${{ gitea.ref_name }} ]; then
echo '# WARNING: Attempting to run this workflow for a tag that is not the latest repo tag. Aborting.'
echo '# WARNING: Attempting to run this workflow for a tag that is not the latest repo tag. Aborting.' >> $GITHUB_STEP_SUMMARY
exit 1
fi
- name: Install Nix
uses: https://github.com/DeterminateSystems/nix-installer-action@main
with:
diagnostic-endpoint: ""
extra-conf: |
experimental-features = nix-command flakes
accept-flake-config = true
- name: Enable Cachix binary cache
run: |
nix profile install nixpkgs#cachix
cachix use crane
cachix use nix-community
- name: Configure Magic Nix Cache
uses: https://github.com/DeterminateSystems/magic-nix-cache-action@main
with:
diagnostic-endpoint: ""
upstream-cache: "https://attic.kennel.juneis.dog/conduwuit"
- name: Apply Nix binary cache configuration
run: |
sudo tee -a /etc/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
- 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
extra-substituters = ${{ env.ATTIC_ENDPOINT }}
extra-trusted-public-keys = ${{ env.ATTIC_PUBLIC_KEY }}
EOF
- name: Prepare build environment
run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --impure --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow
nix develop .#all-features --command true
- name: Cache CI dependencies
run: |
bin/nix-build-and-cache ci
- name: Run CI tests
run: |
direnv exec . engage > >(tee -a test_output.log)
- name: Sync Complement repository
uses: https://github.com/actions/checkout@v4
with:
repository: 'matrix-org/complement'
path: complement_src
- name: Run Complement tests
run: |
direnv exec . bin/complement 'complement_src' 'complement_test_logs.jsonl' 'complement_test_results.jsonl'
cp -v -f result complement_oci_image.tar.gz
- name: Upload Complement OCI image
uses: https://github.com/actions/upload-artifact@v4
with:
name: complement_oci_image.tar.gz
path: complement_oci_image.tar.gz
if-no-files-found: error
- name: Upload Complement logs
uses: https://github.com/actions/upload-artifact@v4
with:
name: complement_test_logs.jsonl
path: complement_test_logs.jsonl
if-no-files-found: error
- name: Upload Complement results
uses: https://github.com/actions/upload-artifact@v4
with:
name: complement_test_results.jsonl
path: complement_test_results.jsonl
if-no-files-found: error
- name: Diff Complement results with checked-in repo results
run: |
diff -u --color=always tests/test_results/complement/test_results.jsonl complement_test_results.jsonl > >(tee -a complement_test_output.log)
echo '# Complement diff results' >> $GITHUB_STEP_SUMMARY
echo '```diff' >> $GITHUB_STEP_SUMMARY
tail -n 100 complement_test_output.log | sed 's/\x1b\[[0-9;]*m//g' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
- name: Update Job Summary
if: success() || failure()
run: |
if [ ${{ job.status }} == 'success' ]; then
echo '# ✅ completed suwuccessfully' >> $GITHUB_STEP_SUMMARY
else
echo '```' >> $GITHUB_STEP_SUMMARY
tail -n 40 test_output.log | sed 's/\x1b\[[0-9;]*m//g' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
fi
build:
name: Build
runs-on: ubuntu-latest
needs: tests
strategy:
matrix:
include:
- target: aarch64-unknown-linux-musl
- target: x86_64-unknown-linux-musl
steps:
- name: Sync repository
uses: https://github.com/actions/checkout@v4
- name: Install Nix
uses: https://github.com/DeterminateSystems/nix-installer-action@main
with:
diagnostic-endpoint: ""
extra-conf: |
experimental-features = nix-command flakes
accept-flake-config = true
- name: Install and enable Cachix binary cache
run: |
nix profile install nixpkgs#cachix
cachix use crane
cachix use nix-community
- name: Configure Magic Nix Cache
uses: https://github.com/DeterminateSystems/magic-nix-cache-action@main
with:
diagnostic-endpoint: ""
upstream-cache: "https://attic.kennel.juneis.dog/conduwuit"
- name: Apply Nix binary cache configuration
run: |
sudo tee -a /etc/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
- 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
extra-substituters = ${{ env.ATTIC_ENDPOINT }}
extra-trusted-public-keys = ${{ env.ATTIC_PUBLIC_KEY }}
EOF
- name: Prepare build environment
run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --impure --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow
nix develop .#all-features --command true
- name: Build static ${{ matrix.target }}
run: |
CARGO_DEB_TARGET_TUPLE=$(echo ${{ matrix.target }} | grep -o -E '^([^-]*-){3}[^-]*')
SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
bin/nix-build-and-cache just .#static-${{ matrix.target }}
mkdir -v -p target/release/
mkdir -v -p target/$CARGO_DEB_TARGET_TUPLE/release/
cp -v -f result/bin/conduit target/release/conduwuit
cp -v -f result/bin/conduit target/$CARGO_DEB_TARGET_TUPLE/release/conduwuit
# -p conduit is the main crate name
direnv exec . cargo deb --verbose --no-build --no-strip -p conduit --target=$CARGO_DEB_TARGET_TUPLE --output target/release/${{ matrix.target }}.deb
mv -v target/release/conduwuit static-${{ matrix.target }}
mv -v target/release/${{ matrix.target }}.deb ${{ matrix.target }}.deb
- name: Upload static-${{ matrix.target }}
uses: https://github.com/actions/upload-artifact@v4
with:
name: static-${{ matrix.target }}
path: static-${{ matrix.target }}
if-no-files-found: error
- name: Upload deb ${{ matrix.target }}
uses: https://github.com/actions/upload-artifact@v4
with:
name: deb-${{ matrix.target }}
path: ${{ matrix.target }}.deb
if-no-files-found: error
compression-level: 0
- name: Build OCI image ${{ matrix.target }}
run: |
bin/nix-build-and-cache just .#oci-image-${{ matrix.target }}
cp -v -f result oci-image-${{ matrix.target }}.tar.gz
- name: Upload OCI image ${{ matrix.target }}
uses: https://github.com/actions/upload-artifact@v4
with:
name: oci-image-${{ matrix.target }}
path: oci-image-${{ matrix.target }}.tar.gz
if-no-files-found: error
compression-level: 0
+604 -242
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,41 @@
name: Update Docker Hub Description
on:
push:
branches:
- main
paths:
- README.md
- .github/workflows/docker-hub-description.yml
workflow_dispatch:
jobs:
dockerHubDescription:
runs-on: ubuntu-latest
if: ${{ (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' || (github.event.pull_request.draft != true)) && github.event.pull_request.user.login != 'renovate[bot]' && (vars.DOCKER_USERNAME != '') }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setting variables
uses: actions/github-script@v7
id: var
with:
script: |
const githubRepo = '${{ github.repository }}'.toLowerCase()
const repoId = githubRepo.split('/')[1]
core.setOutput('github_repository', githubRepo)
const dockerRepo = '${{ vars.DOCKER_USERNAME }}'.toLowerCase() + '/' + repoId
core.setOutput('docker_repo', dockerRepo)
- name: Docker Hub Description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ vars.DOCKER_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: ${{ steps.var.outputs.docker_repo }}
short-description: ${{ github.event.repository.description }}
enable-url-completion: true
+38 -51
View File
@@ -24,8 +24,11 @@ env:
# Get error output from nix that we can actually use, and use our binary caches for the earlier CI steps
NIX_CONFIG: |
show-trace = true
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit https://cache.lix.systems https://conduwuit.cachix.org
extra-substituters = extra-substituters = https://attic.kennel.juneis.dog/conduwuit https://attic.kennel.juneis.dog/conduit https://conduwuit.cachix.org https://aseipp-nix-cache.freetls.fastly.net
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
experimental-features = nix-command flakes
extra-experimental-features = nix-command flakes
accept-flake-config = true
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
@@ -33,10 +36,12 @@ concurrency:
group: "pages"
cancel-in-progress: false
permissions: {}
jobs:
docs:
name: Documentation and GitHub Pages
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
permissions:
pages: write
@@ -47,25 +52,30 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
- name: Free up a bit of runner space
run: |
set +o pipefail
sudo docker image prune --all --force || true
sudo apt purge -y 'php.*' '^mongodb-.*' '^mysql-.*' azure-cli google-cloud-cli google-chrome-stable firefox powershell microsoft-edge-stable || true
sudo apt clean
sudo rm -v -rf /usr/local/games /usr/local/sqlpackage /usr/local/share/powershell /usr/local/share/edge_driver /usr/local/share/gecko_driver /usr/local/share/chromium /usr/local/share/chromedriver-linux64 /usr/lib/google-cloud-sdk /usr/lib/jvm /usr/lib/mono /usr/lib/heroku
set -o pipefail
- name: Sync repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup GitHub Pages
if: github.event_name != 'pull_request'
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') && (github.event_name != 'pull_request')
uses: actions/configure-pages@v5
- uses: nixbuild/nix-quick-install-action@v28
- name: Enable Cachix binary cache
run: |
nix profile install nixpkgs#cachix
cachix use crane
cachix use nix-community
- uses: nixbuild/nix-quick-install-action@master
- name: Restore and cache Nix store
# we want a fresh-state when we do releases/tags to avoid potential cache poisoning attacks impacting
# releases and tags
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
uses: nix-community/cache-nix-action@v5.1.0
with:
# restore and save a cache using this key
@@ -86,19 +96,28 @@ jobs:
# always save the cache
save-always: true
- name: Enable Cachix binary cache
run: |
nix profile install nixpkgs#cachix
cachix use crane
cachix use nix-community
- name: Apply Nix binary cache configuration
run: |
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-substituters = https://attic.kennel.juneis.dog/conduwuit https://attic.kennel.juneis.dog/conduit https://conduwuit.cachix.org https://aseipp-nix-cache.freetls.fastly.net
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
experimental-features = nix-command flakes
extra-experimental-features = nix-command flakes
accept-flake-config = true
EOF
- name: Use alternative Nix binary caches if specified
if: ${{ (env.ATTIC_ENDPOINT != '') && (env.ATTIC_PUBLIC_KEY != '') }}
run: |
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 }}
extra-substituters = ${ATTIC_ENDPOINT}
extra-trusted-public-keys = ${ATTIC_PUBLIC_KEY}
EOF
- name: Prepare build environment
@@ -110,23 +129,7 @@ jobs:
- name: Cache CI dependencies
run: |
# attic nix binary cache server is very, very terribly flakey. nothing i can do to fix it other than retry multiple times here
ATTEMPTS=3
SUCCESS=false
while (( ATTEMPTS-- > 0 ))
do
bin/nix-build-and-cache ci
if [[ $? == 0 ]]; then
SUCCESS=true
break
else
sleep 3
fi
done
if [[ $SUCCESS == "false" ]]; then
exit 1
fi
bin/nix-build-and-cache ci
- name: Run lychee and markdownlint
run: |
@@ -135,23 +138,7 @@ jobs:
- name: Build documentation (book)
run: |
# attic nix binary cache server is very, very terribly flakey. nothing i can do to fix it other than retry multiple times here
ATTEMPTS=3
SUCCESS=false
while (( ATTEMPTS-- > 0 ))
do
bin/nix-build-and-cache just .#book
if [[ $? == 0 ]]; then
SUCCESS=true
break
else
sleep 3
fi
done
if [[ $SUCCESS == "false" ]]; then
exit 1
fi
bin/nix-build-and-cache just .#book
cp -r --dereference result public
@@ -165,12 +152,12 @@ jobs:
compression-level: 0
- name: Upload generated documentation (book) as GitHub Pages artifact
if: github.event_name != 'pull_request'
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') && (github.event_name != 'pull_request')
uses: actions/upload-pages-artifact@v3
with:
path: public
- name: Deploy to GitHub Pages
if: github.event_name != 'pull_request'
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') && (github.event_name != 'pull_request')
id: deployment
uses: actions/deploy-pages@v4
+118
View File
@@ -0,0 +1,118 @@
name: Upload Release Assets
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: 'Tag to release'
required: true
type: string
action_id:
description: 'Action ID of the CI run'
required: true
type: string
permissions: {}
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
env:
GH_EVENT_NAME: ${{ github.event_name }}
GH_EVENT_INPUTS_ACTION_ID: ${{ github.event.inputs.action_id }}
GH_EVENT_INPUTS_TAG: ${{ github.event.inputs.tag }}
GH_REPOSITORY: ${{ github.repository }}
GH_SHA: ${{ github.sha }}
GH_TAG: ${{ github.event.release.tag_name }}
steps:
- name: get latest ci id
id: get_ci_id
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${GH_EVENT_NAME}" == "workflow_dispatch" ]; then
id="${GH_EVENT_INPUTS_ACTION_ID}"
tag="${GH_EVENT_INPUTS_TAG}"
else
# get all runs of the ci workflow
json=$(gh api "repos/${GH_REPOSITORY}/actions/workflows/ci.yml/runs")
# find first run that is github sha and status is completed
id=$(echo "$json" | jq ".workflow_runs[] | select(.head_sha == \"${GH_SHA}\" and .status == \"completed\") | .id" | head -n 1)
if [ ! "$id" ]; then
echo "No completed runs found"
echo "ci_id=0" >> "$GITHUB_OUTPUT"
exit 0
fi
tag="${GH_TAG}"
fi
echo "ci_id=$id" >> "$GITHUB_OUTPUT"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: get latest ci artifacts
if: steps.get_ci_id.outputs.ci_id != 0
uses: actions/download-artifact@v4
env:
GH_TOKEN: ${{ github.token }}
with:
merge-multiple: true
run-id: ${{ steps.get_ci_id.outputs.ci_id }}
github-token: ${{ github.token }}
- run: |
ls
- name: upload release assets
if: steps.get_ci_id.outputs.ci_id != 0
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.get_ci_id.outputs.tag }}
run: |
for file in $(find . -type f); do
case "$file" in
*json*) echo "Skipping $file...";;
*) echo "Uploading $file..."; gh release upload $TAG "$file" --clobber --repo="${GH_REPOSITORY}" || echo "Something went wrong, skipping.";;
esac
done
- name: upload release assets to website
if: steps.get_ci_id.outputs.ci_id != 0
env:
TAG: ${{ steps.get_ci_id.outputs.tag }}
run: |
mkdir -p -v ~/.ssh
echo "${{ secrets.WEB_UPLOAD_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
echo "${{ secrets.WEB_UPLOAD_SSH_PRIVATE_KEY }}" >> ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
cat >>~/.ssh/config <<END
Host website
HostName ${{ secrets.WEB_UPLOAD_SSH_HOSTNAME }}
User ${{ secrets.WEB_UPLOAD_SSH_USERNAME }}
IdentityFile ~/.ssh/id_ed25519
StrictHostKeyChecking yes
AddKeysToAgent no
ForwardX11 no
BatchMode yes
END
echo "Creating tag directory on web server"
ssh -q website "rm -rf /var/www/girlboss.ceo/~strawberry/conduwuit/releases/$TAG/"
ssh -q website "mkdir -v /var/www/girlboss.ceo/~strawberry/conduwuit/releases/$TAG/"
for file in $(find . -type f); do
case "$file" in
*json*) echo "Skipping $file...";;
*) echo "Uploading $file to website"; scp $file website:/var/www/girlboss.ceo/~strawberry/conduwuit/releases/$TAG/$file;;
esac
done
-42
View File
@@ -1,42 +0,0 @@
name: Trivy code and vulnerability scanning
on:
pull_request:
push:
branches:
- main
tags:
- '*'
schedule:
- cron: '00 12 * * *'
permissions:
contents: read
jobs:
trivy-scan:
name: Trivy Scan
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
actions: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Trivy code and vulnerability scanner on repo
uses: aquasecurity/trivy-action@0.24.0
with:
scan-type: repo
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH,MEDIUM,LOW
- name: Run Trivy code and vulnerability scanner on filesystem
uses: aquasecurity/trivy-action@0.24.0
with:
scan-type: fs
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH,MEDIUM,LOW
+1 -1
View File
@@ -30,7 +30,7 @@ modules.xml
.nfs*
# Rust
/target/
/target
### vscode ###
.vscode/*
+24 -16
View File
@@ -10,6 +10,13 @@ variables:
FF_USE_FASTZIP: true
# Print progress reports for cache and artifact transfers
TRANSFER_METER_FREQUENCY: 5s
NIX_CONFIG: |
show-trace = true
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit https://conduwuit.cachix.org
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
experimental-features = nix-command flakes
extra-experimental-features = nix-command flakes
accept-flake-config = true
# Avoid duplicate pipelines
# See: https://docs.gitlab.com/ee/ci/yaml/workflow.html#switch-between-branch-pipelines-and-merge-request-pipelines
@@ -23,6 +30,9 @@ workflow:
before_script:
# Enable nix-command and flakes
- if command -v nix > /dev/null; then echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf; fi
- if command -v nix > /dev/null; then echo "extra-experimental-features = nix-command flakes" >> /etc/nix/nix.conf; fi
# Accept flake config from "untrusted" users
- if command -v nix > /dev/null; then echo "accept-flake-config = true" >> /etc/nix/nix.conf; fi
# Add conduwuit binary cache
- if command -v nix > /dev/null; then echo "extra-substituters = https://attic.kennel.juneis.dog/conduwuit" >> /etc/nix/nix.conf; fi
@@ -35,10 +45,6 @@ before_script:
- if command -v nix > /dev/null && [ -n "$ATTIC_ENDPOINT" ]; then echo "extra-substituters = $ATTIC_ENDPOINT" >> /etc/nix/nix.conf; fi
- if command -v nix > /dev/null && [ -n "$ATTIC_PUBLIC_KEY" ]; then echo "extra-trusted-public-keys = $ATTIC_PUBLIC_KEY" >> /etc/nix/nix.conf; fi
# Add Lix binary cache
- if command -v nix > /dev/null; then echo "extra-substituters = https://cache.lix.systems" >> /etc/nix/nix.conf; fi
- if command -v nix > /dev/null; then echo "extra-trusted-public-keys = cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o=" >> /etc/nix/nix.conf; fi
# Add crane binary cache
- if command -v nix > /dev/null; then echo "extra-substituters = https://crane.cachix.org" >> /etc/nix/nix.conf; fi
- if command -v nix > /dev/null; then echo "extra-trusted-public-keys = crane.cachix.org-1:8Scfpmn9w+hGdXH/Q9tTLiYAE/2dnJYRJP7kl80GuRk=" >> /etc/nix/nix.conf; fi
@@ -47,6 +53,8 @@ before_script:
- if command -v nix > /dev/null; then echo "extra-substituters = https://nix-community.cachix.org" >> /etc/nix/nix.conf; fi
- if command -v nix > /dev/null; then echo "extra-trusted-public-keys = nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" >> /etc/nix/nix.conf; fi
- if command -v nix > /dev/null; then echo "extra-substituters = https://aseipp-nix-cache.freetls.fastly.net" >> /etc/nix/nix.conf; fi
# Install direnv and nix-direnv
- if command -v nix > /dev/null; then nix-env -iA nixpkgs.direnv nixpkgs.nix-direnv; fi
@@ -58,7 +66,7 @@ before_script:
ci:
stage: ci
image: nixos/nix:2.24.4
image: nixos/nix:2.24.9
script:
# Cache CI dependencies
- ./bin/nix-build-and-cache ci
@@ -83,31 +91,31 @@ ci:
artifacts:
stage: artifacts
image: nixos/nix:2.24.4
image: nixos/nix:2.24.9
script:
- ./bin/nix-build-and-cache just .#static-x86_64-unknown-linux-musl
- cp result/bin/conduit x86_64-unknown-linux-musl
- ./bin/nix-build-and-cache just .#static-x86_64-linux-musl
- cp result/bin/conduit x86_64-linux-musl
- mkdir -p target/release
- cp result/bin/conduit target/release
- direnv exec . cargo deb --no-build --no-strip
- mv target/debian/*.deb x86_64-unknown-linux-musl.deb
- mv target/debian/*.deb x86_64-linux-musl.deb
# Since the OCI image package is based on the binary package, this has the
# fun side effect of uploading the normal binary too. Conduit users who are
# deploying with Nix can leverage this fact by adding our binary cache to
# their systems.
#
# Note that although we have an `oci-image-x86_64-unknown-linux-musl`
# Note that although we have an `oci-image-x86_64-linux-musl`
# output, we don't build it because it would be largely redundant to this
# one since it's all containerized anyway.
- ./bin/nix-build-and-cache just .#oci-image
- cp result oci-image-amd64.tar.gz
- ./bin/nix-build-and-cache just .#static-aarch64-unknown-linux-musl
- cp result/bin/conduit aarch64-unknown-linux-musl
- ./bin/nix-build-and-cache just .#static-aarch64-linux-musl
- cp result/bin/conduit aarch64-linux-musl
- ./bin/nix-build-and-cache just .#oci-image-aarch64-unknown-linux-musl
- ./bin/nix-build-and-cache just .#oci-image-aarch64-linux-musl
- cp result oci-image-arm64v8.tar.gz
- ./bin/nix-build-and-cache just .#book
@@ -115,9 +123,9 @@ artifacts:
- cp -r --dereference result public
artifacts:
paths:
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-musl
- x86_64-unknown-linux-musl.deb
- x86_64-linux-musl
- aarch64-linux-musl
- x86_64-linux-musl.deb
- oci-image-amd64.tar.gz
- oci-image-arm64v8.tar.gz
- public
+7 -3
View File
@@ -1,7 +1,7 @@
# Contributing guide
This page is for about contributing to conduwuit. The
[development](development.md) page may be of interest for you as well.
[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],
@@ -67,7 +67,7 @@ failing from your changes, please review the logs (they are uploaded as
artifacts) and determine if they're intended or not.
If you'd like to run Complement locally using Nix, see the
[testing](docs/development/testing.md) page.
[testing](development/testing.md) page.
[Sytest][sytest] support will come soon.
@@ -128,7 +128,11 @@ Direct all PRs/MRs to the `main` branch.
By sending a pull request or patch, you are agreeing that your changes are
allowed to be licenced under the Apache-2.0 licence and all of your conduct is
in line with the Contributor's Covenant.
in line with the Contributor's Covenant, and conduwuit's Code of Conduct.
Contribution by users who violate either of these code of conducts will not have
their contributions accepted. This includes users who have been banned from
conduwuit Matrix rooms for Code of Conduct violations.
[issues]: https://github.com/girlbossceo/conduwuit/issues
[conduwuit-matrix]: https://matrix.to/#/#conduwuit:puppygock.gay
Generated
+1364 -708
View File
File diff suppressed because it is too large Load Diff
+187 -105
View File
@@ -7,35 +7,47 @@ default-members = ["src/*"]
[workspace.package]
authors = [
"strawberry <strawberry@puppygock.gay>",
"timokoesters <timo@koesters.xyz>",
"June Clementine Strawberry <june@girlboss.ceo>",
"strawberry <strawberry@puppygock.gay>", # woof
"Jason Volk <jason@zemos.net>",
]
categories = ["network-programming"]
description = "a very cool fork of Conduit, a Matrix homeserver written in Rust"
description = "a very cool Matrix chat homeserver written in Rust"
edition = "2021"
homepage = "https://conduwuit.puppyirl.gay/"
keywords = ["chat", "matrix", "server", "uwu"]
keywords = ["chat", "matrix", "networking", "server", "uwu"]
license = "Apache-2.0"
# See also `rust-toolchain.toml`
readme = "README.md"
repository = "https://github.com/girlbossceo/conduwuit"
rust-version = "1.80.1"
version = "0.4.6"
rust-version = "1.84.0"
version = "0.5.0"
[workspace.metadata.crane]
name = "conduit"
name = "conduwuit"
[workspace.dependencies.arrayvec]
version = "0.7.4"
features = ["serde"]
[workspace.dependencies.smallvec]
version = "1.13.2"
features = [
"const_generics",
"const_new",
"serde",
"union",
"write",
]
[workspace.dependencies.const-str]
version = "0.5.7"
[workspace.dependencies.ctor]
version = "0.2.8"
version = "0.2.9"
[workspace.dependencies.cargo_toml]
version = "0.20"
version = "0.21"
default-features = false
features = ["features"]
@@ -45,20 +57,16 @@ default-features = false
features = ["parse"]
[workspace.dependencies.sanitize-filename]
version = "0.5.0"
[workspace.dependencies.jsonwebtoken]
version = "9.3.0"
version = "0.6.0"
[workspace.dependencies.base64]
version = "0.22.1"
default-features = false
# used for TURN server authentication
[workspace.dependencies.hmac]
version = "0.12.1"
[workspace.dependencies.sha-1]
version = "0.10.1"
default-features = false
# used for checking if an IP is in specific subnets / CIDR ranges easier
[workspace.dependencies.ipaddress]
@@ -69,19 +77,19 @@ version = "0.8.5"
# Used for the http request / response body type for Ruma endpoints used with reqwest
[workspace.dependencies.bytes]
version = "1.7.1"
version = "1.9.0"
[workspace.dependencies.http-body-util]
version = "0.1.1"
version = "0.1.2"
[workspace.dependencies.http]
version = "1.1.0"
version = "1.2.0"
[workspace.dependencies.regex]
version = "1.10.6"
version = "1.11.1"
[workspace.dependencies.axum]
version = "0.7.5"
version = "0.7.9"
default-features = false
features = [
"form",
@@ -94,45 +102,47 @@ features = [
]
[workspace.dependencies.axum-extra]
version = "0.9.3"
version = "0.9.6"
default-features = false
features = ["typed-header", "tracing"]
[workspace.dependencies.axum-server]
version = "0.7.1"
default-features = false
features = ["tls-rustls"]
# to listen on both HTTP and HTTPS if listening on TLS dierctly from conduwuit for complement or sytest
[workspace.dependencies.axum-server-dual-protocol]
version = "0.7"
[workspace.dependencies.axum-client-ip]
version = "0.6.0"
version = "0.6.1"
[workspace.dependencies.tower]
version = "0.5.0"
version = "0.5.1"
default-features = false
features = ["util"]
[workspace.dependencies.tower-http]
version = "0.5.2"
version = "0.6.2"
default-features = false
features = [
"add-extension",
"catch-panic",
"cors",
"sensitive-headers",
"set-header",
"timeout",
"trace",
"util",
"catch-panic",
]
[workspace.dependencies.rustls]
version = "0.23.12"
version = "0.23.19"
default-features = false
features = ["aws_lc_rs"]
[workspace.dependencies.reqwest]
version = "0.12.7"
version = "0.12.9"
default-features = false
features = [
"rustls-tls-native-roots",
@@ -142,12 +152,12 @@ features = [
]
[workspace.dependencies.serde]
version = "1.0.209"
version = "1.0.216"
default-features = false
features = ["rc"]
[workspace.dependencies.serde_json]
version = "1.0.124"
version = "1.0.133"
default-features = false
features = ["raw_value"]
@@ -169,9 +179,9 @@ version = "0.5.3"
features = ["alloc", "rand"]
default-features = false
# Used to generate thumbnails for images
# Used to generate thumbnails for images & blurhashes
[workspace.dependencies.image]
version = "0.25.1"
version = "0.25.5"
default-features = false
features = [
"jpeg",
@@ -180,43 +190,55 @@ features = [
"webp",
]
[workspace.dependencies.blurhash]
version = "0.2.3"
default-features = false
features = [
"fast-linear-to-srgb",
"image",
]
# logging
[workspace.dependencies.log]
version = "0.4.21"
version = "0.4.22"
default-features = false
[workspace.dependencies.tracing]
version = "0.1.40"
version = "0.1.41"
default-features = false
[workspace.dependencies.tracing-subscriber]
version = "0.3.18"
features = ["env-filter"]
version = "=0.3.18"
default-features = false
features = ["env-filter", "std", "tracing", "tracing-log", "ansi", "fmt"]
[workspace.dependencies.tracing-core]
version = "0.1.32"
version = "0.1.33"
default-features = false
# for URL previews
[workspace.dependencies.webpage]
version = "2.0.1"
default-features = false
# used for conduit's CLI and admin room command parsing
# used for conduwuit's CLI and admin room command parsing
[workspace.dependencies.clap]
version = "4.5.15"
version = "4.5.23"
default-features = false
features = [
"std",
"derive",
"help",
"usage",
"env",
"error-context",
"help",
"std",
"string",
"usage",
]
[workspace.dependencies.futures-util]
[workspace.dependencies.futures]
version = "0.3.30"
default-features = false
features = ["std", "async-await"]
[workspace.dependencies.tokio]
version = "1.40.0"
version = "1.42.0"
default-features = false
features = [
"fs",
@@ -227,17 +249,18 @@ features = [
"time",
"rt-multi-thread",
"io-util",
"tracing",
]
[workspace.dependencies.tokio-metrics]
version = "0.3.1"
version = "0.4.0"
[workspace.dependencies.libloading]
version = "0.8.5"
version = "0.8.6"
# Validating urls in config, was already a transitive dependency
[workspace.dependencies.url]
version = "2.5.0"
version = "2.5.4"
default-features = false
features = ["serde"]
@@ -248,7 +271,7 @@ features = ["alloc", "std"]
default-features = false
[workspace.dependencies.hyper]
version = "1.4.1"
version = "1.5.1"
default-features = false
features = [
"server",
@@ -257,39 +280,40 @@ features = [
]
[workspace.dependencies.hyper-util]
version = "0.1.6"
# hyper-util >=0.1.9 seems to have DNS issues
version = "=0.1.8"
default-features = false
features = [
"client",
"server-auto",
"server-graceful",
"service",
"tokio",
]
# to support multiple variations of setting a config option
[workspace.dependencies.either]
version = "1.11.0"
version = "1.13.0"
default-features = false
features = ["serde"]
# Used for reading the configuration from conduwuit.toml & environment variables
[workspace.dependencies.figment]
version = "0.10.18"
version = "0.10.19"
default-features = false
features = ["env", "toml"]
[workspace.dependencies.hickory-resolver]
version = "0.24.1"
version = "0.24.2"
default-features = false
# Used for conduit::Error type
# Used for conduwuit::Error type
[workspace.dependencies.thiserror]
version = "1.0.63"
version = "2.0.7"
default-features = false
# Used when hashing the state
[workspace.dependencies.ring]
version = "0.17.8"
default-features = false
# Used to make working with iterators easier, was already a transitive depdendency
[workspace.dependencies.itertools]
@@ -300,12 +324,16 @@ version = "0.13.0"
[workspace.dependencies.cyborgtime]
version = "2.1.1"
# used to replace the channels of the tokio runtime
# used for MPSC channels
[workspace.dependencies.loole]
version = "0.3.1"
version = "0.4.0"
# used for MPMC channels
[workspace.dependencies.async-channel]
version = "2.3.1"
[workspace.dependencies.async-trait]
version = "0.1.81"
version = "0.1.83"
[workspace.dependencies.lru-cache]
version = "0.1.2"
@@ -314,7 +342,7 @@ version = "0.1.2"
[workspace.dependencies.ruma]
git = "https://github.com/girlbossceo/ruwuma"
#branch = "conduwuit-changes"
rev = "d7ddcd036f81edb257ab9371f9cadd46444e8a90"
rev = "f5667c6292adb43fbe4725d31d6b5127a0cf60ce"
features = [
"compat",
"rand",
@@ -327,6 +355,7 @@ features = [
"server-util",
"unstable-exhaustive-types",
"ring-compat",
"compat-upload-signatures",
"identifiers-validation",
"unstable-unspecified",
"unstable-msc2448",
@@ -335,12 +364,17 @@ features = [
"unstable-msc2870",
"unstable-msc3026",
"unstable-msc3061",
"unstable-msc3245",
"unstable-msc3266",
"unstable-msc3381", # polls
"unstable-msc3489", # beacon / live location
"unstable-msc3575",
"unstable-msc4075",
"unstable-msc4121",
"unstable-msc4125",
"unstable-msc4186",
"unstable-msc4203", # sending to-device events to appservices
"unstable-msc4210", # remove legacy mentions
"unstable-extensible-events",
]
@@ -356,9 +390,13 @@ features = [
"bzip2",
]
# optional SHA256 media keys feature
[workspace.dependencies.sha2]
version = "0.10.8"
default-features = false
[workspace.dependencies.sha1]
version = "0.10.6"
default-features = false
# optional opentelemetry, performance measurements, flamegraphs, etc for performance measurements and monitoring
[workspace.dependencies.opentelemetry]
@@ -380,7 +418,7 @@ features = ["rt-tokio"]
# optional sentry metrics for crash/panic reporting
[workspace.dependencies.sentry]
version = "0.34.0"
version = "0.35.0"
default-features = false
features = [
"backtrace",
@@ -396,24 +434,30 @@ features = [
]
[workspace.dependencies.sentry-tracing]
version = "0.34.0"
version = "0.35.0"
[workspace.dependencies.sentry-tower]
version = "0.34.0"
version = "0.35.0"
# jemalloc usage
[workspace.dependencies.tikv-jemalloc-sys]
git = "https://github.com/girlbossceo/jemallocator"
rev = "c32af15f3b440ae5e46c3404f78b19093bbd5294"
rev = "82af58d6a13ddd5dcdc7d4e91eae3b63292995b8"
default-features = false
features = ["unprefixed_malloc_on_supported_platforms"]
features = [
"background_threads_runtime_support",
"unprefixed_malloc_on_supported_platforms",
]
[workspace.dependencies.tikv-jemallocator]
git = "https://github.com/girlbossceo/jemallocator"
rev = "c32af15f3b440ae5e46c3404f78b19093bbd5294"
rev = "82af58d6a13ddd5dcdc7d4e91eae3b63292995b8"
default-features = false
features = ["unprefixed_malloc_on_supported_platforms"]
features = [
"background_threads_runtime_support",
"unprefixed_malloc_on_supported_platforms",
]
[workspace.dependencies.tikv-jemalloc-ctl]
git = "https://github.com/girlbossceo/jemallocator"
rev = "c32af15f3b440ae5e46c3404f78b19093bbd5294"
rev = "82af58d6a13ddd5dcdc7d4e91eae3b63292995b8"
default-features = false
features = ["use_std"]
@@ -426,7 +470,8 @@ default-features = false
features = ["resource"]
[workspace.dependencies.sd-notify]
version = "0.4.1"
version = "0.4.3"
default-features = false
[workspace.dependencies.hardened_malloc-rs]
version = "0.1.2"
@@ -442,23 +487,42 @@ version = "0.4.3"
default-features = false
[workspace.dependencies.termimad]
version = "0.30.0"
version = "0.31.1"
default-features = false
[workspace.dependencies.checked_ops]
version = "0.1"
[workspace.dependencies.syn]
version = "2.0.76"
version = "2.0.90"
default-features = false
features = ["full", "extra-traits"]
[workspace.dependencies.quote]
version = "1.0.36"
version = "1.0.37"
[workspace.dependencies.proc-macro2]
version = "1.0.86"
version = "1.0.89"
[workspace.dependencies.bytesize]
version = "1.3.0"
[workspace.dependencies.core_affinity]
version = "0.8.1"
[workspace.dependencies.libc]
version = "0.2"
[workspace.dependencies.num-traits]
version = "0.2"
[workspace.dependencies.minicbor]
version = "0.25.1"
features = ["std"]
[workspace.dependencies.minicbor-serde]
version = "0.3.2"
features = ["std"]
#
# Patches
@@ -469,59 +533,71 @@ version = "1.0.86"
# https://github.com/girlbossceo/tracing/commit/b348dca742af641c47bc390261f60711c2af573c
[patch.crates-io.tracing-subscriber]
git = "https://github.com/girlbossceo/tracing"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
rev = "05825066a6d0e9ad6b80dcf29457eb179ff4768c"
[patch.crates-io.tracing]
git = "https://github.com/girlbossceo/tracing"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
rev = "05825066a6d0e9ad6b80dcf29457eb179ff4768c"
[patch.crates-io.tracing-core]
git = "https://github.com/girlbossceo/tracing"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
rev = "05825066a6d0e9ad6b80dcf29457eb179ff4768c"
[patch.crates-io.tracing-log]
git = "https://github.com/girlbossceo/tracing"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
rev = "05825066a6d0e9ad6b80dcf29457eb179ff4768c"
# adds a tab completion callback: https://github.com/girlbossceo/rustyline-async/commit/de26100b0db03e419a3d8e1dd26895d170d1fe50
# adds event for CTRL+\: https://github.com/girlbossceo/rustyline-async/commit/67d8c49aeac03a5ef4e818f663eaa94dd7bf339b
[patch.crates-io.rustyline-async]
git = "https://github.com/girlbossceo/rustyline-async"
rev = "9654cc84e19241f6e19021eb8e677892656f5071"
rev = "deaeb0694e2083f53d363b648da06e10fc13900c"
# adds LIFO queue scheduling; this should be updated with PR progress.
[patch.crates-io.event-listener]
git = "https://github.com/girlbossceo/event-listener"
rev = "fe4aebeeaae435af60087ddd56b573a2e0be671d"
[patch.crates-io.async-channel]
git = "https://github.com/girlbossceo/async-channel"
rev = "92e5e74063bf2a3b10414bcc8a0d68b235644280"
[patch.crates-io.core_affinity]
git = "https://github.com/girlbossceo/core_affinity_rs"
rev = "9c8e51510c35077df888ee72a36b4b05637147da"
#
# Our crates
#
[workspace.dependencies.conduit-router]
package = "conduit_router"
[workspace.dependencies.conduwuit-router]
package = "conduwuit_router"
path = "src/router"
default-features = false
[workspace.dependencies.conduit-admin]
package = "conduit_admin"
[workspace.dependencies.conduwuit-admin]
package = "conduwuit_admin"
path = "src/admin"
default-features = false
[workspace.dependencies.conduit-api]
package = "conduit_api"
[workspace.dependencies.conduwuit-api]
package = "conduwuit_api"
path = "src/api"
default-features = false
[workspace.dependencies.conduit-service]
package = "conduit_service"
[workspace.dependencies.conduwuit-service]
package = "conduwuit_service"
path = "src/service"
default-features = false
[workspace.dependencies.conduit-database]
package = "conduit_database"
[workspace.dependencies.conduwuit-database]
package = "conduwuit_database"
path = "src/database"
default-features = false
[workspace.dependencies.conduit-core]
package = "conduit_core"
[workspace.dependencies.conduwuit-core]
package = "conduwuit_core"
path = "src/core"
default-features = false
[workspace.dependencies.conduit-macros]
package = "conduit_macros"
[workspace.dependencies.conduwuit-macros]
package = "conduwuit_macros"
path = "src/macros"
default-features = false
@@ -580,7 +656,7 @@ codegen-units = 32
# '-Clink-arg=-Wl,--no-gc-sections',
#]
[profile.release-max-perf.package.conduit_macros]
[profile.release-max-perf.package.conduwuit_macros]
inherits = "release-max-perf.build-override"
#rustflags = [
# '-Crelocation-model=pic',
@@ -608,14 +684,13 @@ inherits = "release"
# and can be raised if build times are tolerable.
[profile.dev]
debug = 1
debug = "full"
opt-level = 0
panic = "unwind"
debug-assertions = true
incremental = true
codegen-units = 64
#rustflags = [
# '--cfg', 'conduit_mods',
# '--cfg', 'conduwuit_mods',
# '-Ztime-passes',
# '-Zmir-opt-level=0',
# '-Zvalidate-mir=false',
@@ -632,11 +707,11 @@ codegen-units = 64
# '-Clink-arg=-Wl,-z,lazy',
#]
[profile.dev.package.conduit_core]
[profile.dev.package.conduwuit_core]
inherits = "dev"
incremental = false
#rustflags = [
# '--cfg', 'conduit_mods',
# '--cfg', 'conduwuit_mods',
# '-Ztime-passes',
# '-Zmir-opt-level=0',
# '-Ztls-model=initial-exec',
@@ -653,11 +728,10 @@ incremental = false
# '-Clink-arg=-Wl,-z,nodelete',
#]
[profile.dev.package.conduit]
[profile.dev.package.conduwuit]
inherits = "dev"
incremental = false
#rustflags = [
# '--cfg', 'conduit_mods',
# '--cfg', 'conduwuit_mods',
# '-Ztime-passes',
# '-Zmir-opt-level=0',
# '-Zvalidate-mir=false',
@@ -679,7 +753,7 @@ incremental = false
codegen-units = 1
opt-level = 'z'
#rustflags = [
# '--cfg', 'conduit_mods',
# '--cfg', 'conduwuit_mods',
# '-Ztls-model=initial-exec',
# '-Cprefer-dynamic=true',
# '-Zstaticlib-prefer-dynamic=true',
@@ -700,7 +774,7 @@ incremental = false
codegen-units = 1
opt-level = 'z'
#rustflags = [
# '--cfg', 'conduit_mods',
# '--cfg', 'conduwuit_mods',
# '-Ztls-model=global-dynamic',
# '-Cprefer-dynamic=true',
# '-Zstaticlib-prefer-dynamic=true',
@@ -715,12 +789,16 @@ opt-level = 'z'
# primarily used for CI
[profile.test]
inherits = "dev"
strip = false
opt-level = 0
codegen-units = 16
incremental = false
[profile.test.package.'*']
inherits = "dev"
debug = 0
strip = false
opt-level = 0
codegen-units = 16
incremental = false
@@ -763,6 +841,7 @@ unused-qualifications = "warn"
#unused-results = "warn" # TODO
## some sadness
elided_named_lifetimes = "allow" # TODO!
let_underscore_drop = "allow"
missing_docs = "allow"
# cfgs cannot be limited to expected cfgs or their de facto non-transitive/opt-in use-case e.g.
@@ -808,17 +887,20 @@ significant_drop_tightening = { level = "allow", priority = 1 } # TODO
pedantic = { level = "warn", priority = -1 }
## some sadness
too_long_first_doc_paragraph = { level = "allow", priority = 1 }
doc_markdown = { level = "allow", priority = 1 }
enum_glob_use = { level = "allow", priority = 1 }
if_not_else = { level = "allow", priority = 1 }
if_then_some_else_none = { level = "allow", priority = 1 }
inline_always = { level = "allow", priority = 1 }
match_bool = { level = "allow", priority = 1 }
missing_docs_in_private_items = { level = "allow", priority = 1 }
missing_errors_doc = { level = "allow", priority = 1 }
missing_panics_doc = { level = "allow", priority = 1 }
module_name_repetitions = { level = "allow", priority = 1 }
no_effect_underscore_binding = { level = "allow", priority = 1 }
similar_names = { level = "allow", priority = 1 }
single_match_else = { level = "allow", priority = 1 }
struct_field_names = { level = "allow", priority = 1 }
unnecessary_wraps = { level = "allow", priority = 1 }
unused_async = { level = "allow", priority = 1 }
+84 -23
View File
@@ -1,31 +1,29 @@
# conduwuit
`main`: [![CI and
Artifacts](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml)
[![conduwuit main room](https://img.shields.io/matrix/conduwuit%3Apuppygock.gay?server_fqdn=matrix.transfem.dev&style=flat&logo=matrix&logoColor=%23f5b3ff&label=%23conduwuit%3Apuppygock.gay&color=%23f652ff)](https://matrix.to/#/#conduwuit:puppygock.gay) [![conduwuit space](https://img.shields.io/matrix/conduwuit-space%3Apuppygock.gay?server_fqdn=matrix.transfem.dev&style=flat&logo=matrix&logoColor=%23f5b3ff&label=%23conduwuit-space%3Apuppygock.gay&color=%23f652ff)](https://matrix.to/#/#conduwuit-space:puppygock.gay) [![CI and Artifacts](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml)
<!-- ANCHOR: catchphrase -->
### a very cool, featureful fork of [Conduit](https://conduit.rs/)
### a very cool [Matrix](https://matrix.org/) chat homeserver written in Rust
<!-- ANCHOR_END: catchphrase -->
Visit the [Conduwuit documentation](https://conduwuit.puppyirl.gay/) for more
information.
Visit the [conduwuit documentation](https://conduwuit.puppyirl.gay/) for more
information and how to deploy/setup conduwuit.
<!-- ANCHOR: body -->
#### What is Matrix?
[Matrix](https://matrix.org) is an open network for secure and decentralized
communication. Users from every Matrix homeserver can chat with users from all
other Matrix servers. You can even use bridges (also called Matrix Appservices)
to communicate with users outside of Matrix, like a community on Discord.
[Matrix](https://matrix.org) is an open, federated, and extensible network for
decentralised communication. Users from any Matrix homeserver can chat with users from all
other homeservers over federation. Matrix is designed to be extensible and built on top of.
You can even use bridges such as Matrix Appservices to communicate with users outside of Matrix, like a community on Discord.
#### What is the goal?
An efficient Matrix homeserver that's easy to set up and just works. You can
install it on a mini-computer like the Raspberry Pi to host Matrix for your
family, friends or company.
A high-performance, efficient, low-cost, and featureful Matrix homeserver that's
easy to set up and just works with minimal configuration needed.
#### Can I try it out?
@@ -38,13 +36,56 @@ homeserver". This means there are rules, so please read the rules:
[https://transfem.dev/homeserver_rules.txt](https://transfem.dev/homeserver_rules.txt)
transfem.dev is also listed at
[servers.joinmatrix.org](https://servers.joinmatrix.org/)
[servers.joinmatrix.org](https://servers.joinmatrix.org/), which is a list of
popular public Matrix homeservers, including some others that run conduwuit.
#### What is the current status?
conduwuit is a hard fork of Conduit which is in beta, meaning you can join and
participate in most Matrix rooms, but not all features are supported and you
might run into bugs from time to time.
conduwuit is technically a hard fork of [Conduit](https://conduit.rs/), which is in beta.
The beta status initially was inherited from Conduit, however the huge amount of
codebase divergance, changes, fixes, and improvements have effectively made this
beta status not entirely applicable to us anymore.
conduwuit is very stable based on our rapidly growing userbase, has lots of features that users
expect, and very usable as a daily driver for small, medium, and upper-end medium sized homeservers.
A lot of critical stability and performance issues have been fixed, and a lot of
necessary groundwork has finished; making this project way better than it was
back in the start at ~early 2024.
#### How is conduwuit funded? Is conduwuit sustainable?
conduwuit has no external funding. This is made possible purely in my freetime with
contributors, also in their free time, and only by user-curated donations.
conduwuit has existed since around November 2023, but [only became more publicly known
in March/April 2024](https://matrix.org/blog/2024/04/26/this-week-in-matrix-2024-04-26/#conduwuit-website)
and we have no plans in stopping or slowing down any time soon!
#### Can I migrate or switch from Conduit?
conduwuit is a complete drop-in replacement for Conduit. As long as you are using RocksDB,
the only "migration" you need to do is replace the binary or container image. There
is no harm or additional steps required for using conduwuit. See the
[Migrating from Conduit](https://conduwuit.puppyirl.gay/deploying/generic.html#migrating-from-conduit) section
on the generic deploying guide.
Note that as of conduwuit version 0.5.0, backwards compatibility with Conduit is
no longer supported. We only support migrating *from* Conduit, not back to
Conduit like before. If you are truly finding yourself wanting to migrate back
to Conduit, we would appreciate all your feedback and if we can assist with
any issues or concerns.
#### Can I migrate from Synapse or Dendrite?
Currently there is no known way to seamlessly migrate all user data from the old
homeserver to conduwuit. However it is perfectly acceptable to replace the old
homeserver software with conduwuit using the same server name and there will not
be any issues with federation.
There is an interest in developing a built-in seamless user data migration
method into conduwuit, however there is no concrete ETA or timeline for this.
<!-- ANCHOR_END: body -->
@@ -52,22 +93,38 @@ might run into bugs from time to time.
#### Contact
If you run into any question, feel free to
[`#conduwuit:puppygock.gay`](https://matrix.to/#/#conduwuit:puppygock.gay)
is the official project Matrix room. You can get support here, ask questions or
concerns, get assistance setting up conduwuit, etc.
- Ask us in `#conduwuit:puppygock.gay` on Matrix
- [Open an issue on GitHub](https://github.com/girlbossceo/conduwuit/issues/new)
This room should stay relevant and focused on conduwuit. An offtopic general
chatter room can be found there as well.
Please keep the issue trackers focused on bug reports and enhancement requests.
General support is extremely difficult to be offered over an issue tracker, and
simple questions should be asked directly in an interactive platform like our
Matrix room above as they can turn into a relevant discussion and/or may not be
simple to answer. If you're not sure, just ask in the Matrix room.
If you have a bug or feature to request: [Open an issue on GitHub](https://github.com/girlbossceo/conduwuit/issues/new)
#### Donate
- Liberapay: <https://liberapay.com/girlbossceo>
conduwuit development is purely made possible by myself and contributors. I do
not get paid to work on this, and I work on it in my free time. Donations are
heavily appreciated! 💜🥺
- Liberapay (preferred): <https://liberapay.com/girlbossceo>
- GitHub Sponsors (preferred): <https://github.com/sponsors/girlbossceo>
- Ko-fi: <https://ko-fi.com/puppygock>
- GitHub Sponsors: <https://github.com/sponsors/girlbossceo>
I do not and will not accept cryptocurrency donations, including things related.
#### Logo
Original repo and Matrix room picture was from bran (<3). Current banner image
and logo is directly from [this cohost
post](https://cohost.org/RatBaby/post/1028290-finally-a-flag-for).
post](https://web.archive.org/web/20241126004041/https://cohost.org/RatBaby/post/1028290-finally-a-flag-for).
#### Is it conduwuit or Conduwuit?
@@ -75,11 +132,15 @@ Both, but I prefer conduwuit.
#### Mirrors of conduwuit
If GitHub is unavailable in your country, or has poor connectivity, conduwuit's
source code is mirrored onto the following additional platforms I maintain:
- GitHub: <https://github.com/girlbossceo/conduwuit>
- GitLab: <https://gitlab.com/conduwuit/conduwuit>
- git.girlcock.ceo: <https://git.girlcock.ceo/strawberry/conduwuit>
- git.gay: <https://git.gay/june/conduwuit>
- Codeberg: <https://codeberg.org/girlbossceo/conduwuit>
- mau.dev: <https://mau.dev/june/conduwuit>
- Codeberg: <https://codeberg.org/arf/conduwuit>
- sourcehut: <https://git.sr.ht/~girlbossceo/conduwuit>
<!-- ANCHOR_END: footer -->
+17 -3
View File
@@ -1,12 +1,26 @@
[Unit]
Description=conduwuit Matrix homeserver
After=network.target
Wants=network-online.target
After=network-online.target
Documentation=https://conduwuit.puppyirl.gay/
RequiresMountsFor=/var/lib/private/conduwuit
[Service]
DynamicUser=yes
Type=notify
Type=notify-reload
ReloadSignal=SIGUSR1
TTYPath=/dev/tty25
DeviceAllow=char-tty
StandardInput=tty-force
StandardOutput=tty
StandardError=journal+console
TTYReset=yes
# uncomment to allow buffer to be cleared every restart
TTYVTDisallocate=no
TTYColumns=120
TTYRows=40
AmbientCapabilities=
CapabilityBoundingSet=
@@ -15,7 +29,7 @@ DevicePolicy=closed
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
ProcSubset=pid
#ProcSubset=pid
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
+4 -3
View File
@@ -15,10 +15,10 @@ LOG_FILE="$2"
# A `.jsonl` file to write test results to
RESULTS_FILE="$3"
OCI_IMAGE="complement-conduit:main"
OCI_IMAGE="complement-conduwuit:main"
# Complement tests that are skipped due to flakiness/reliability issues
SKIPPED_COMPLEMENT_TESTS='-skip=TestClientSpacesSummary.*|TestJoinFederatedRoomFromApplicationServiceBridgeUser.*|TestJumpToDateEndpoint.*'
SKIPPED_COMPLEMENT_TESTS='-skip=TestClientSpacesSummary.*|TestJoinFederatedRoomFromApplicationServiceBridgeUser.*|TestJumpToDateEndpoint.*|TestUnbanViaInvite.*'
# $COMPLEMENT_SRC needs to be a directory to Complement source code
if [ -f "$COMPLEMENT_SRC" ]; then
@@ -34,7 +34,8 @@ toplevel="$(git rev-parse --show-toplevel)"
pushd "$toplevel" > /dev/null
bin/nix-build-and-cache just .#static-complement
#bin/nix-build-and-cache just .#linux-complement
bin/nix-build-and-cache just .#complement
docker load < result
popd > /dev/null
+13 -7
View File
@@ -26,7 +26,12 @@ just() {
"$ATTIC_TOKEN"
# Find all output paths of the installables and their build dependencies
readarray -t derivations < <(nix path-info --derivation "$@")
#readarray -t derivations < <(nix path-info --derivation "$@")
derivations=()
while IFS=$'\n' read derivation; do
derivations+=("$derivation")
done < <(nix path-info --derivation "$@")
cache=()
for derivation in "${derivations[@]}"; do
cache+=(
@@ -34,6 +39,9 @@ just() {
)
done
withattic() {
nix shell --inputs-from "$toplevel" attic --command xargs attic push "$@" <<< "${cache[*]}"
}
# Upload them to Attic (conduit store)
#
# Use `xargs` and a here-string because something would probably explode if
@@ -41,8 +49,7 @@ just() {
# store paths include a newline in them.
(
IFS=$'\n'
nix shell --inputs-from "$toplevel" attic -c xargs \
attic push conduit <<< "${cache[*]}"
withattic conduit || withattic conduit || withattic conduit || true
)
# main "conduwuit" store
@@ -59,8 +66,7 @@ just() {
# store paths include a newline in them.
(
IFS=$'\n'
nix shell --inputs-from "$toplevel" attic -c xargs \
attic push conduwuit <<< "${cache[*]}"
withattic conduwuit || withattic conduwuit || withattic conduwuit || true
# push to cachix if available
if [ "$CACHIX_AUTH_TOKEN" ]; then
@@ -76,8 +82,8 @@ ci() {
--inputs-from "$toplevel"
# Keep sorted
"$toplevel#devShells.x86_64-linux.default"
"$toplevel#devShells.x86_64-linux.all-features"
#"$toplevel#devShells.x86_64-linux.default"
#"$toplevel#devShells.x86_64-linux.all-features"
attic#default
cachix#default
nixpkgs#direnv
+14 -2
View File
@@ -2,6 +2,18 @@ array-size-threshold = 4096
cognitive-complexity-threshold = 94 # TODO reduce me ALARA
excessive-nesting-threshold = 11 # TODO reduce me to 4 or 5
future-size-threshold = 7745 # TODO reduce me ALARA
stack-size-threshold = 144000 # reduce me ALARA
too-many-lines-threshold = 700 # TODO reduce me to <= 100
stack-size-threshold = 196608 # reduce me ALARA
too-many-lines-threshold = 780 # TODO reduce me to <= 100
type-complexity-threshold = 250 # reduce me to ~200
disallowed-macros = [
{ path = "log::error", reason = "use conduwuit_core::error" },
{ path = "log::warn", reason = "use conduwuit_core::warn" },
{ path = "log::info", reason = "use conduwuit_core::info" },
{ path = "log::debug", reason = "use conduwuit_core::debug" },
{ path = "log::trace", reason = "use conduwuit_core::trace" },
]
disallowed-methods = [
{ path = "tokio::spawn", reason = "use and pass conduuwit_core::server::Server::runtime() to spawn from" },
]
+1498 -781
View File
File diff suppressed because it is too large Load Diff
+12 -5
View File
@@ -1,17 +1,24 @@
# conduwuit for Debian
Information about downloading and deploying the Debian package. This may also be referenced for other `apt`-based distros such as Ubuntu.
Information about downloading and deploying the Debian package. This may also be
referenced for other `apt`-based distros such as Ubuntu.
### Installation
It is recommended to see the [generic deployment guide](../deploying/generic.md) for further information if needed as usage of the Debian package is generally related.
It is recommended to see the [generic deployment guide](../deploying/generic.md)
for further information if needed as usage of the Debian package is generally
related.
No `apt` repository is currently offered yet, it is in the works/development.
### Configuration
When installed, the example config is placed at `/etc/conduwuit/conduwuit.toml` as the default config. At the minimum, you will need to change your `server_name` here.
When installed, the example config is placed at `/etc/conduwuit/conduwuit.toml`
as the default config. The config mentions things required to be changed before
starting.
You can tweak more detailed settings by uncommenting and setting the config options
in `/etc/conduwuit/conduwuit.toml`.
You can tweak more detailed settings by uncommenting and setting the config
options in `/etc/conduwuit/conduwuit.toml`.
### Running
+17 -3
View File
@@ -1,13 +1,27 @@
[Unit]
Description=conduwuit Matrix homeserver
Documentation=https://conduwuit.puppyirl.gay/
Wants=network-online.target
After=network-online.target
Documentation=https://conduwuit.puppyirl.gay/
[Service]
DynamicUser=yes
User=conduwuit
Group=conduwuit
Type=notify
Type=notify-reload
ReloadSignal=SIGUSR1
TTYPath=/dev/tty25
DeviceAllow=char-tty
StandardInput=tty-force
StandardOutput=tty
StandardError=journal+console
TTYReset=yes
# uncomment to allow buffer to be cleared every restart
TTYVTDisallocate=no
TTYColumns=120
TTYRows=40
Environment="CONDUWUIT_CONFIG=/etc/conduwuit/conduwuit.toml"
@@ -22,7 +36,7 @@ DevicePolicy=closed
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
ProcSubset=pid
#ProcSubset=pid
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
+16 -4
View File
@@ -10,21 +10,33 @@ CONDUWUIT_DATABASE_PATH_SYMLINK=/var/lib/matrix-conduit
case $1 in
purge)
# Remove debconf changes from the db
db_purge
#db_purge
# Per https://www.debian.org/doc/debian-policy/ch-files.html#behavior
# "configuration files must be preserved when the package is removed, and
# only deleted when the package is purged."
#
if [ -d "$CONDUWUIT_CONFIG_PATH" ]; then
rm -v -r "$CONDUWUIT_CONFIG_PATH"
if test -L "$CONDUWUIT_CONFIG_PATH"; then
echo "Deleting conduwuit configuration files"
rm -v -r "$CONDUWUIT_CONFIG_PATH"
fi
fi
if [ -d "$CONDUWUIT_DATABASE_PATH" ]; then
rm -v -r "$CONDUWUIT_DATABASE_PATH"
if test -L "$CONDUWUIT_DATABASE_PATH"; then
echo "Deleting conduwuit database directory"
rm -r "$CONDUWUIT_DATABASE_PATH"
fi
fi
if [ -d "$CONDUWUIT_DATABASE_PATH_SYMLINK" ]; then
rm -v -r "$CONDUWUIT_DATABASE_PATH_SYMLINK"
if test -L "$CONDUWUIT_DATABASE_SYMLINK"; then
echo "Removing matrix-conduit symlink"
rm -r "$CONDUWUIT_DATABASE_PATH_SYMLINK"
fi
fi
;;
esac
+1 -1
View File
@@ -27,7 +27,7 @@ malloc-usable-size = ["rust-rocksdb/malloc-usable-size"]
[dependencies.rust-rocksdb]
git = "https://github.com/girlbossceo/rust-rocksdb-zaidoon1"
rev = "5383ca8173299066b516406e3a2cf945ead891cb"
rev = "7b0e1bbe395a41ba8a11347a4921da590e3ad0d9"
#branch = "master"
default-features = false
+59 -58
View File
@@ -1,61 +1,62 @@
pub use rust_rocksdb::*;
#[cfg_attr(not(conduit_mods), link(name = "rocksdb"))]
#[cfg_attr(conduit_mods, link(name = "rocksdb", kind = "static"))]
extern "C" {
pub fn rocksdb_list_column_families();
pub fn rocksdb_logger_create_stderr_logger();
pub fn rocksdb_options_set_info_log();
pub fn rocksdb_get_options_from_string();
pub fn rocksdb_writebatch_create();
pub fn rocksdb_writebatch_destroy();
pub fn rocksdb_writebatch_put_cf();
pub fn rocksdb_writebatch_delete_cf();
pub fn rocksdb_iter_value();
pub fn rocksdb_iter_seek_to_last();
pub fn rocksdb_iter_seek_for_prev();
pub fn rocksdb_iter_seek_to_first();
pub fn rocksdb_iter_next();
pub fn rocksdb_iter_prev();
pub fn rocksdb_iter_seek();
pub fn rocksdb_iter_valid();
pub fn rocksdb_iter_get_error();
pub fn rocksdb_iter_key();
pub fn rocksdb_iter_destroy();
pub fn rocksdb_livefiles();
pub fn rocksdb_livefiles_count();
pub fn rocksdb_livefiles_destroy();
pub fn rocksdb_livefiles_column_family_name();
pub fn rocksdb_livefiles_name();
pub fn rocksdb_livefiles_size();
pub fn rocksdb_livefiles_level();
pub fn rocksdb_livefiles_smallestkey();
pub fn rocksdb_livefiles_largestkey();
pub fn rocksdb_livefiles_entries();
pub fn rocksdb_livefiles_deletions();
pub fn rocksdb_put_cf();
pub fn rocksdb_delete_cf();
pub fn rocksdb_get_pinned_cf();
pub fn rocksdb_create_column_family();
pub fn rocksdb_get_latest_sequence_number();
pub fn rocksdb_batched_multi_get_cf();
pub fn rocksdb_cancel_all_background_work();
pub fn rocksdb_repair_db();
pub fn rocksdb_list_column_families_destroy();
pub fn rocksdb_flush();
pub fn rocksdb_flush_wal();
pub fn rocksdb_open_column_families();
pub fn rocksdb_open_for_read_only_column_families();
pub fn rocksdb_open_as_secondary_column_families();
pub fn rocksdb_open_column_families_with_ttl();
pub fn rocksdb_open();
pub fn rocksdb_open_for_read_only();
pub fn rocksdb_open_with_ttl();
pub fn rocksdb_open_as_secondary();
pub fn rocksdb_write();
pub fn rocksdb_create_iterator_cf();
pub fn rocksdb_backup_engine_create_new_backup_flush();
pub fn rocksdb_backup_engine_options_create();
pub fn rocksdb_write_buffer_manager_destroy();
pub fn rocksdb_options_set_ttl();
#[cfg_attr(not(conduwuit_mods), link(name = "rocksdb"))]
#[cfg_attr(conduwuit_mods, link(name = "rocksdb", kind = "static"))]
unsafe extern "C" {
pub unsafe fn rocksdb_list_column_families();
pub unsafe fn rocksdb_logger_create_stderr_logger();
pub unsafe fn rocksdb_logger_create_callback_logger();
pub unsafe fn rocksdb_options_set_info_log();
pub unsafe fn rocksdb_get_options_from_string();
pub unsafe fn rocksdb_writebatch_create();
pub unsafe fn rocksdb_writebatch_destroy();
pub unsafe fn rocksdb_writebatch_put_cf();
pub unsafe fn rocksdb_writebatch_delete_cf();
pub unsafe fn rocksdb_iter_value();
pub unsafe fn rocksdb_iter_seek_to_last();
pub unsafe fn rocksdb_iter_seek_for_prev();
pub unsafe fn rocksdb_iter_seek_to_first();
pub unsafe fn rocksdb_iter_next();
pub unsafe fn rocksdb_iter_prev();
pub unsafe fn rocksdb_iter_seek();
pub unsafe fn rocksdb_iter_valid();
pub unsafe fn rocksdb_iter_get_error();
pub unsafe fn rocksdb_iter_key();
pub unsafe fn rocksdb_iter_destroy();
pub unsafe fn rocksdb_livefiles();
pub unsafe fn rocksdb_livefiles_count();
pub unsafe fn rocksdb_livefiles_destroy();
pub unsafe fn rocksdb_livefiles_column_family_name();
pub unsafe fn rocksdb_livefiles_name();
pub unsafe fn rocksdb_livefiles_size();
pub unsafe fn rocksdb_livefiles_level();
pub unsafe fn rocksdb_livefiles_smallestkey();
pub unsafe fn rocksdb_livefiles_largestkey();
pub unsafe fn rocksdb_livefiles_entries();
pub unsafe fn rocksdb_livefiles_deletions();
pub unsafe fn rocksdb_put_cf();
pub unsafe fn rocksdb_delete_cf();
pub unsafe fn rocksdb_get_pinned_cf();
pub unsafe fn rocksdb_create_column_family();
pub unsafe fn rocksdb_get_latest_sequence_number();
pub unsafe fn rocksdb_batched_multi_get_cf();
pub unsafe fn rocksdb_cancel_all_background_work();
pub unsafe fn rocksdb_repair_db();
pub unsafe fn rocksdb_list_column_families_destroy();
pub unsafe fn rocksdb_flush();
pub unsafe fn rocksdb_flush_wal();
pub unsafe fn rocksdb_open_column_families();
pub unsafe fn rocksdb_open_for_read_only_column_families();
pub unsafe fn rocksdb_open_as_secondary_column_families();
pub unsafe fn rocksdb_open_column_families_with_ttl();
pub unsafe fn rocksdb_open();
pub unsafe fn rocksdb_open_for_read_only();
pub unsafe fn rocksdb_open_with_ttl();
pub unsafe fn rocksdb_open_as_secondary();
pub unsafe fn rocksdb_write();
pub unsafe fn rocksdb_create_iterator_cf();
pub unsafe fn rocksdb_backup_engine_create_new_backup_flush();
pub unsafe fn rocksdb_backup_engine_options_create();
pub unsafe fn rocksdb_write_buffer_manager_destroy();
pub unsafe fn rocksdb_options_set_ttl();
}
+1
View File
@@ -0,0 +1 @@
docs/development.md
+1
View File
@@ -8,6 +8,7 @@
- [Generic](deploying/generic.md)
- [NixOS](deploying/nixos.md)
- [Docker](deploying/docker.md)
- [Kubernetes](deploying/kubernetes.md)
- [Arch Linux](deploying/arch-linux.md)
- [Debian](deploying/debian.md)
- [FreeBSD](deploying/freebsd.md)
+1 -1
View File
@@ -42,7 +42,7 @@ The syntax of this is a standard admin command without the prefix such as
An example output of a success is:
```
INFO conduit_service::admin::startup: Startup command #0 completed:
INFO conduwuit_service::admin::startup: Startup command #0 completed:
Created user with user_id: @june:girlboss.ceo and password: `<redacted>`
```
-1
View File
@@ -1 +0,0 @@
{{#include ../CONTRIBUTING.md}}
+1
View File
@@ -0,0 +1 @@
../CONTRIBUTING.md
@@ -14,10 +14,11 @@ services:
environment:
CONDUWUIT_SERVER_NAME: your.server.name.example # EDIT THIS
CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit
CONDUWUIT_DATABASE_BACKEND: rocksdb
CONDUWUIT_PORT: 6167 # should match the loadbalancer traefik label
CONDUWUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
CONDUWUIT_MAX_REQUEST_SIZE: 20000000 # in bytes, ~20 MB
CONDUWUIT_ALLOW_REGISTRATION: 'true'
CONDUWUIT_REGISTRATION_TOKEN: 'YOUR_TOKEN' # A registration token is required when registration is allowed.
#CONDUWUIT_YES_I_AM_VERY_VERY_SURE_I_WANT_AN_OPEN_REGISTRATION_SERVER_PRONE_TO_ABUSE: 'true'
CONDUWUIT_ALLOW_FEDERATION: 'true'
CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true'
CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]'
+3 -2
View File
@@ -30,10 +30,11 @@ services:
environment:
CONDUWUIT_SERVER_NAME: example.com # EDIT THIS
CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit
CONDUWUIT_DATABASE_BACKEND: rocksdb
CONDUWUIT_PORT: 6167
CONDUWUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
CONDUWUIT_MAX_REQUEST_SIZE: 20000000 # in bytes, ~20 MB
CONDUWUIT_ALLOW_REGISTRATION: 'true'
CONDUWUIT_REGISTRATION_TOKEN: 'YOUR_TOKEN' # A registration token is required when registration is allowed.
#CONDUWUIT_YES_I_AM_VERY_VERY_SURE_I_WANT_AN_OPEN_REGISTRATION_SERVER_PRONE_TO_ABUSE: 'true'
CONDUWUIT_ALLOW_FEDERATION: 'true'
CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true'
CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]'
@@ -15,7 +15,8 @@ services:
CONDUWUIT_SERVER_NAME: your.server.name.example # EDIT THIS
CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]'
CONDUWUIT_ALLOW_REGISTRATION: 'false' # After setting a secure registration token, you can enable this
CONDUWUIT_REGISTRATION_TOKEN: # This is a token you can use to register on the server
CONDUWUIT_REGISTRATION_TOKEN: "" # This is a token you can use to register on the server
#CONDUWUIT_REGISTRATION_TOKEN_FILE: "" # Alternatively you can configure a path to a token file to read
CONDUWUIT_ADDRESS: 0.0.0.0
CONDUWUIT_PORT: 6167 # you need to match this with the traefik load balancer label if you're want to change it
CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit
@@ -23,7 +24,6 @@ services:
### Uncomment and change values as desired, note that conduwuit has plenty of config options, so you should check out the example example config too
# Available levels are: error, warn, info, debug, trace - more info at: https://docs.rs/env_logger/*/env_logger/#enabling-logging
# CONDUWUIT_LOG: info # default is: "warn,state_res=warn"
# CONDUWUIT_ALLOW_JAEGER: 'false'
# CONDUWUIT_ALLOW_ENCRYPTION: 'true'
# CONDUWUIT_ALLOW_FEDERATION: 'true'
# CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true'
@@ -31,7 +31,7 @@ services:
# CONDUWUIT_ALLOW_OUTGOING_PRESENCE: true
# CONDUWUIT_ALLOW_LOCAL_PRESENCE: true
# CONDUWUIT_WORKERS: 10
# CONDUWUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
# CONDUWUIT_MAX_REQUEST_SIZE: 20000000 # in bytes, ~20 MB
# CONDUWUIT_NEW_USER_DISPLAYNAME_SUFFIX = "🏳<200d>⚧"
# We need some way to serve the client and server .well-known json. The simplest way is via the CONDUWUIT_WELL_KNOWN
+3 -2
View File
@@ -14,10 +14,11 @@ services:
environment:
CONDUWUIT_SERVER_NAME: your.server.name # EDIT THIS
CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit
CONDUWUIT_DATABASE_BACKEND: rocksdb
CONDUWUIT_PORT: 6167
CONDUWUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
CONDUWUIT_MAX_REQUEST_SIZE: 20000000 # in bytes, ~20 MB
CONDUWUIT_ALLOW_REGISTRATION: 'true'
CONDUWUIT_REGISTRATION_TOKEN: 'YOUR_TOKEN' # A registration token is required when registration is allowed.
#CONDUWUIT_YES_I_AM_VERY_VERY_SURE_I_WANT_AN_OPEN_REGISTRATION_SERVER_PRONE_TO_ABUSE: 'true'
CONDUWUIT_ALLOW_FEDERATION: 'true'
CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true'
CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]'
+30 -13
View File
@@ -11,9 +11,9 @@ OCI images for conduwuit are available in the registries listed below.
| Registry | Image | Size | Notes |
| --------------- | --------------------------------------------------------------- | ----------------------------- | ---------------------- |
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:latest][gh] | ![Image Size][shield-latest] | Stable tagged image. |
| GitLab Registry | [registry.gitlab.com/conduwuit/conduwuit:latest][gl] | ![Image Size][shield-latest] | Stable tagged image. |
| Docker Hub | [docker.io/girlbossceo/conduwuit:latest][dh] | ![Image Size][shield-latest] | Stable tagged image. |
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:latest][gh] | ![Image Size][shield-latest] | Stable latest tagged image. |
| GitLab Registry | [registry.gitlab.com/conduwuit/conduwuit:latest][gl] | ![Image Size][shield-latest] | Stable latest tagged image. |
| Docker Hub | [docker.io/girlbossceo/conduwuit:latest][dh] | ![Image Size][shield-latest] | Stable latest tagged image. |
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:main][gh] | ![Image Size][shield-main] | Stable main branch. |
| GitLab Registry | [registry.gitlab.com/conduwuit/conduwuit:main][gl] | ![Image Size][shield-main] | Stable main branch. |
| Docker Hub | [docker.io/girlbossceo/conduwuit:main][dh] | ![Image Size][shield-main] | Stable main branch. |
@@ -24,6 +24,9 @@ OCI images for conduwuit are available in the registries listed below.
[shield-latest]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/latest
[shield-main]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main
OCI image `.tar.gz` files are also hosted directly at when uploaded by CI with a
commit hash/revision or a tagged release: <https://pup.systems/~strawberry/conduwuit/>
Use
```bash
@@ -40,9 +43,8 @@ When you have the image you can simply run it with
docker run -d -p 8448:6167 \
-v db:/var/lib/conduwuit/ \
-e CONDUWUIT_SERVER_NAME="your.server.name" \
-e CONDUWUIT_DATABASE_BACKEND="rocksdb" \
-e CONDUWUIT_ALLOW_REGISTRATION=false \
--name conduit $LINK
--name conduwuit $LINK
```
or you can use [docker compose](#docker-compose).
@@ -93,16 +95,28 @@ Additional info about deploying conduwuit can be found [here](generic.md).
### Build
To build the conduwuit image with docker-compose, you first need to open and
modify the `docker-compose.yml` file. There you need to comment the `image:`
option and uncomment the `build:` option. Then call docker compose with:
Official conduwuit images are built using Nix's
[`buildLayeredImage`][nix-buildlayeredimage]. This ensures all OCI images are
repeatable and reproducible by anyone, keeps the images lightweight, and can be
built offline.
```bash
docker compose up
```
This also ensures portability of our images because `buildLayeredImage` builds
OCI images, not Docker images, and works with other container software.
This will also start the container right afterwards, so if want it to run in
detached mode, you also should use the `-d` flag.
The OCI images are OS-less with only a very minimal environment of the `tini`
init system, CA certificates, and the conduwuit binary. This does mean there is
not a shell, but in theory you can get a shell by adding the necessary layers
to the layered image. However it's very unlikely you will need a shell for any
real troubleshooting.
The flake file for the OCI image definition is at [`nix/pkgs/oci-image/default.nix`][oci-image-def].
To build an OCI image using Nix, the following outputs can be built:
- `nix build -L .#oci-image` (default features, x86_64 glibc)
- `nix build -L .#oci-image-x86_64-linux-musl` (default features, x86_64 musl)
- `nix build -L .#oci-image-aarch64-linux-musl` (default features, aarch64 musl)
- `nix build -L .#oci-image-x86_64-linux-musl-all-features` (all features, x86_64 musl)
- `nix build -L .#oci-image-aarch64-linux-musl-all-features` (all features, aarch64 musl)
### Run
@@ -137,3 +151,6 @@ those two files.
## Voice communication
See the [TURN](../turn.md) page.
[nix-buildlayeredimage]: https://ryantm.github.io/nixpkgs/builders/images/dockertools/#ssec-pkgs-dockerTools-buildLayeredImage
[oci-image-def]: https://github.com/girlbossceo/conduwuit/blob/main/nix/pkgs/oci-image/default.nix
+2 -8
View File
@@ -1,11 +1,5 @@
# conduwuit for FreeBSD
conduwuit at the moment does not provide FreeBSD builds. Building conduwuit on
FreeBSD requires a specific environment variable to use the system prebuilt
RocksDB library instead of rust-rocksdb / rust-librocksdb-sys which does *not*
work and will cause a build error or coredump.
conduwuit at the moment does not provide FreeBSD builds or have FreeBSD packaging, however conduwuit does build and work on FreeBSD using the system-provided RocksDB.
Use the following environment variable: `ROCKSDB_LIB_DIR=/usr/local/lib`
Such example commandline with it can be: `ROCKSDB_LIB_DIR=/usr/local/lib cargo
build --release`
Contributions for getting conduwuit packaged are welcome.
+139 -23
View File
@@ -1,6 +1,6 @@
# Generic deployment documentation
> ## Getting help
> ### Getting help
>
> If you run into any problems while setting up conduwuit, ask us in
> `#conduwuit:puppygock.gay` or [open an issue on
@@ -8,22 +8,72 @@
## Installing conduwuit
You may simply download the binary that fits your machine. Run `uname -m` to see
what you need.
### Static prebuilt binary
You may simply download the binary that fits your machine architecture (x86_64
or aarch64). Run `uname -m` to see what you need.
Prebuilt fully static musl binaries can be downloaded from the latest tagged
release [here](https://github.com/girlbossceo/conduwuit/releases/latest) or
`main` CI branch workflow artifact output. These also include Debian packages.
`main` CI branch workflow artifact output. These also include Debian/Ubuntu
packages.
Binaries are also available on my website directly at: <https://pup.systems/~strawberry/conduwuit/>
These can be curl'd directly from. `ci-bins` are CI workflow binaries by commit
hash/revision, and `releases` are tagged releases. Sort by descending last
modified for the latest.
These binaries have jemalloc and io_uring statically linked and included with
them.
them, so no additional dynamic dependencies need to be installed.
For the **best** performance; if using an `x86_64` CPU made in the last ~15 years,
we recommend using the `-haswell-` optimised binaries. This sets
`-march=haswell` which is the most compatible and highest performance with
optimised binaries. The database backend, RocksDB, most benefits from this as it
will then use hardware accelerated CRC32 hashing/checksumming which is critical
for performance.
### Compiling
Alternatively, you may compile the binary yourself. We recommend using
[Lix](https://lix.systems) to build conduwuit as this has the most guaranteed
reproducibiltiy and easiest to get a build environment and output going.
Nix (or [Lix](https://lix.systems)) to build conduwuit as this has the most
guaranteed reproducibiltiy and easiest to get a build environment and output
going. This also allows easy cross-compilation.
Otherwise, follow standard Rust project build guides (installing git and cloning
the repo, getting the Rust toolchain via rustup, installing LLVM toolchain +
libclang for RocksDB, installing liburing for io_uring and RocksDB, etc).
You can run the `nix build -L .#static-x86_64-linux-musl-all-features` or
`nix build -L .#static-aarch64-linux-musl-all-features` commands based
on architecture to cross-compile the necessary static binary located at
`result/bin/conduwuit`. This is reproducible with the static binaries produced
in our CI.
If wanting to build using standard Rust toolchains, make sure you install:
- `liburing-dev` on the compiling machine, and `liburing` on the target host
- LLVM and libclang for RocksDB
You can build conduwuit using `cargo build --release --all-features`
## Migrating from Conduit
As mentioned in the README, there is little to no steps needed to migrate
from Conduit. As long as you are using the RocksDB database backend, just
replace the binary / container image / etc.
**WARNING**: As of conduwuit 0.5.0, all database and backwards compatibility
with Conduit is no longer supported. We only support migrating *from* Conduit,
not back to Conduit like before. If you are truly finding yourself wanting to
migrate back to Conduit, we would appreciate all your feedback and if we can
assist with any issues or concerns.
**Note**: If you are relying on Conduit's "automatic delegation" feature,
this will **NOT** work on conduwuit and you must configure delegation manually.
This is not a mistake and no support for this feature will be added.
If you are using SQLite, you **MUST** migrate to RocksDB. You can use this
tool to migrate from SQLite to RocksDB: <https://github.com/ShadowJonathan/conduit_toolbox/>
See the `[global.well_known]` config section, or configure your web server
appropriately to send the delegation responses.
## Adding a conduwuit user
@@ -31,13 +81,13 @@ While conduwuit can run as any user it is better to use dedicated users for
different services. This also allows you to make sure that the file permissions
are correctly set up.
In Debian or Fedora/RHEL, you can use this command to create a conduwuit user:
In Debian, you can use this command to create a conduwuit user:
```bash
sudo adduser --system conduwuit --group --disabled-login --no-create-home
```
For distros without `adduser`:
For distros without `adduser` (or where it's a symlink to `useradd`):
```bash
sudo useradd -r --shell /usr/bin/nologin --no-create-home conduwuit
@@ -45,18 +95,46 @@ sudo useradd -r --shell /usr/bin/nologin --no-create-home conduwuit
## Forwarding ports in the firewall or the router
conduwuit uses the ports 443 and 8448 both of which need to be open in the
firewall.
Matrix's default federation port is port 8448, and clients must be using port 443.
If you would like to use only port 443, or a different port, you will need to setup
delegation. conduwuit has config options for doing delegation, or you can configure
your reverse proxy to manually serve the necessary JSON files to do delegation
(see the `[global.well_known]` config section).
If conduwuit runs behind a router or in a container and has a different public
IP address than the host system these public ports need to be forwarded directly
or indirectly to the port mentioned in the config.
Note for NAT users; if you have trouble connecting to your server from the inside
of your network, you need to research your router and see if it supports "NAT
hairpinning" or "NAT loopback".
If your router does not support this feature, you need to research doing local
DNS overrides and force your Matrix DNS records to use your local IP internally.
This can be done at the host level using `/etc/hosts`. If you need this to be
on the network level, consider something like NextDNS or Pi-Hole.
## Setting up a systemd service
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.
Two example systemd units for conduwuit can be found
[on the configuration page](../configuration/examples.md#debian-systemd-unit-file).
You may need to change the `ExecStart=` path to where you placed the conduwuit
binary if it is not `/usr/bin/conduwuit`.
On systems where rsyslog is used alongside journald (i.e. Red Hat-based distros
and OpenSUSE), put `$EscapeControlCharactersOnReceive off` inside
`/etc/rsyslog.conf` to allow color in logs.
If you are using a different `database_path` other than the systemd unit
configured default `/var/lib/conduwuit`, you need to add your path to the
systemd unit's `ReadWritePaths=`. This can be done by either directly editing
`conduwuit.service` and reloading systemd, or running `systemctl edit conduwuit.service`
and entering the following:
```
[Service]
ReadWritePaths=/path/to/custom/database/path
```
## Creating the conduwuit configuration file
@@ -64,7 +142,8 @@ 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 the config. You need to change at least the server name.**
**Please take a moment to read the config. You need to change at least the
server name.**
RocksDB is the only supported database backend.
@@ -74,26 +153,60 @@ If you are using a dedicated user for conduwuit, you will need to allow it to
read the config. To do that you can run this:
```bash
sudo chown -R root:root /etc/conduwuit sudo chmod -R 755 /etc/conduwuit
sudo chown -R root:root /etc/conduwuit
sudo chmod -R 755 /etc/conduwuit
```
If you use the default database path you also need to run this:
```bash
sudo mkdir -p /var/lib/conduwuit/ sudo chown -R conduwuit:conduwuit /var/lib/conduwuit/
sudo mkdir -p /var/lib/conduwuit/
sudo chown -R conduwuit:conduwuit /var/lib/conduwuit/
sudo chmod 700 /var/lib/conduwuit/
```
## Setting up the Reverse Proxy
Refer to the documentation or various guides online of your chosen reverse proxy
software. A [Caddy](https://caddyserver.com/) example will be provided as this
software. There are many examples of basic Apache/Nginx reverse proxy setups
out there.
A [Caddy](https://caddyserver.com/) example will be provided as this
is the recommended reverse proxy for new users and is very trivial to use
(handles TLS, reverse proxy headers, etc transparently with proper defaults).
Lighttpd is not supported as it seems to mess with the `X-Matrix` Authorization
header, making federation non-functional. If using Apache, you need to use
`nocanon` to prevent this.
header, making federation non-functional. If a workaround is found, feel free to share to get it added to the documentation here.
If using Apache, you need to use `nocanon` in your `ProxyPass` directive to prevent this (note that Apache isn't very good as a general reverse proxy and we discourage the usage of it if you can).
If using Nginx, you need to give conduwuit the request URI using `$request_uri`, or like so:
- `proxy_pass http://127.0.0.1:6167$request_uri;`
- `proxy_pass http://127.0.0.1:6167;`
Nginx users need to increase `client_max_body_size` (default is 1M) to match
`max_request_size` defined in conduwuit.toml.
You will need to reverse proxy everything under following routes:
- `/_matrix/` - core Matrix C-S and S-S APIs
- `/_conduwuit/` - ad-hoc conduwuit routes such as `/local_user_count` and
`/server_version`
You can optionally reverse proxy the following individual routes:
- `/.well-known/matrix/client` and `/.well-known/matrix/server` if using
conduwuit to perform delegation (see the `[global.well_known]` config section)
- `/.well-known/matrix/support` if using conduwuit to send the homeserver admin
contact and support page (formerly known as MSC1929)
- `/` if you would like to see `hewwo from conduwuit woof!` at the root
See the following spec pages for more details on these files:
- [`/.well-known/matrix/server`](https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixserver)
- [`/.well-known/matrix/client`](https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixclient)
- [`/.well-known/matrix/support`](https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixsupport)
Examples of delegation:
- <https://puppygock.gay/.well-known/matrix/server>
- <https://puppygock.gay/.well-known/matrix/client>
### Caddy
@@ -142,6 +255,9 @@ curl https://your.server.name/_conduwuit/server_version
# If using port 8448
curl https://your.server.name:8448/_conduwuit/server_version
# If federation is enabled
curl https://your.server.name:8448/_matrix/federation/v1/version
```
- To check if your server can talk with other homeservers, you can use the
+8
View File
@@ -0,0 +1,8 @@
# conduwuit for Kubernetes
conduwuit doesn't support horizontal scalability or distributed loading
natively, however a community maintained Helm Chart is available here to run
conduwuit on Kubernetes: <https://gitlab.cronce.io/charts/conduwuit>
Should changes need to be made, please reach out to the maintainer in our
Matrix room as this is not maintained/controlled by the conduwuit maintainers.
+78 -11
View File
@@ -1,11 +1,15 @@
# conduwuit for NixOS
conduwuit can be acquired by [Lix][lix] from various places:
conduwuit can be acquired by Nix (or [Lix][lix]) from various places:
* The `flake.nix` at the root of the repo
* The `default.nix` at the root of the repo
* From conduwuit's binary cache
A community maintained NixOS package is available at [`conduwuit`](https://search.nixos.org/packages?channel=unstable&show=conduwuit&from=0&size=50&sort=relevance&type=packages&query=conduwuit)
### Binary cache
A binary cache for conduwuit that the CI/CD publishes to is available at the
following places (both are the same just different names):
@@ -17,25 +21,88 @@ https://attic.kennel.juneis.dog/conduwuit
conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE=
```
The binary caches have been recreated recently due to attic issues. The old
public keys were:
The binary caches were recreated some months ago due to attic issues. The old public
keys were:
```
conduit:Isq8FGyEC6FOXH6nD+BOeAA+bKp6X6UIbupSlGEPuOg=
conduwuit:lYPVh7o1hLu1idH4Xt2QHaRa49WRGSAqzcfFd94aOTw=
```
If specifying a URL in your flake, please use the GitHub remote:
`github:girlbossceo/conduwuit`
If needed, we have a binary cache on Cachix but it is only limited to 5GB:
The `flake.nix` and `default.nix` do not (currently) provide a NixOS module, so
(for now) [`services.matrix-conduit`][module] from Nixpkgs should be used to
configure conduwuit.
```
https://conduwuit.cachix.org
conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
```
If you want to run the latest code, you should get conduwuit from the
`flake.nix` or `default.nix` and set
[`services.matrix-conduit.package`][package] appropriately.
If specifying a Git remote URL in your flake, you can use any remotes that
are specified on the README (the mirrors), such as the GitHub: `github:girlbossceo/conduwuit`
### NixOS module
The `flake.nix` and `default.nix` do not currently provide a NixOS module (contributions
welcome!), so [`services.matrix-conduit`][module] from Nixpkgs can be used to configure
conduwuit.
### Conduit NixOS Config Module and SQLite
Beware! The [`services.matrix-conduit`][module] module defaults to SQLite as a database backend.
Conduwuit dropped SQLite support in favor of exclusively supporting the much faster RocksDB.
Make sure that you are using the RocksDB backend before migrating!
There is a [tool to migrate a Conduit SQLite database to
RocksDB](https://github.com/ShadowJonathan/conduit_toolbox/).
If you want to run the latest code, you should get conduwuit from the `flake.nix`
or `default.nix` and set [`services.matrix-conduit.package`][package]
appropriately to use conduwuit instead of Conduit.
### UNIX sockets
Due to the lack of a conduwuit NixOS module, when using the `services.matrix-conduit` module
a workaround like the one below is necessary to use UNIX sockets. This is because the UNIX
socket option does not exist in Conduit, and the module forcibly sets the `address` and
`port` config options.
```nix
options.services.matrix-conduit.settings = lib.mkOption {
apply = old: old // (
if (old.global ? "unix_socket_path")
then { global = builtins.removeAttrs old.global [ "address" "port" ]; }
else { }
);
};
```
Additionally, the [`matrix-conduit` systemd unit][systemd-unit] in the module does not allow
the `AF_UNIX` socket address family in their systemd unit's `RestrictAddressFamilies=` which
disallows the namespace from accessing or creating UNIX sockets and has to be enabled like so:
```nix
systemd.services.conduit.serviceConfig.RestrictAddressFamilies = [ "AF_UNIX" ];
```
Even though those workarounds are feasible a conduwuit NixOS configuration module, developed and
published by the community, would be appreciated.
### jemalloc and hardened profile
conduwuit uses jemalloc by default. This may interfere with the [`hardened.nix` profile][hardened.nix]
due to them using `scudo` by default. You must either disable/hide `scudo` from conduwuit, or
disable jemalloc like so:
```nix
let
conduwuit = pkgs.unstable.conduwuit.override {
enableJemalloc = false;
};
in
```
[lix]: https://lix.systems/
[module]: https://search.nixos.org/options?channel=unstable&query=services.matrix-conduit
[package]: https://search.nixos.org/options?channel=unstable&query=services.matrix-conduit.package
[hardened.nix]: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix#L22
[systemd-unit]: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/matrix/conduit.nix#L132
+89 -13
View File
@@ -1,31 +1,95 @@
# Development
Information about developing the project. If you are only interested in using
it, you can safely ignore this section. If you plan on contributing, see the
[contributor's guide](contributing.md).
it, you can safely ignore this page. If you plan on contributing, see the
[contributor's guide](./contributing.md).
## List of forked dependencies During conduwuit development, we have had to fork
## conduwuit project layout
conduwuit uses a collection of sub-crates, packages, or workspace members
that indicate what each general area of code is for. All of the workspace
members are under `src/`. The workspace definition is at the top level / root
`Cargo.toml`.
The crate names are generally self-explanatory:
- `admin` is the admin room
- `api` is the HTTP API, Matrix C-S and S-S endpoints, etc
- `core` is core conduwuit functionality like config loading, error definitions,
global utilities, logging infrastructure, etc
- `database` is RocksDB methods, helpers, RocksDB config, and general database definitions,
utilities, or functions
- `macros` are conduwuit Rust [macros][macros] like general helper macros, logging
and error handling macros, and [syn][syn] and [procedural macros][proc-macro]
used for admin room commands and others
- `main` is the "primary" sub-crate. This is where the `main()` function lives,
tokio worker and async initialisation, Sentry initialisation, [clap][clap] init,
and signal handling. If you are adding new [Rust features][features], they *must*
go here.
- `router` is the webserver and request handling bits, using axum, tower, tower-http,
hyper, etc, and the [global server state][state] to access `services`.
- `service` is the high-level database definitions and functions for data,
outbound/sending code, and other business logic such as media fetching.
It is highly unlikely you will ever need to add a new workspace member, but
if you truly find yourself needing to, we recommend reaching out to us in
the Matrix room for discussions about it beforehand.
The primary inspiration for this design was apart of hot reloadable development,
to support "conduwuit as a library" where specific parts can simply be swapped out.
There is evidence Conduit wanted to go this route too as `axum` is technically an
optional feature in Conduit, and can be compiled without the binary or axum library
for handling inbound web requests; but it was never completed or worked.
See the Rust documentation on [Workspaces][workspaces] for general questions
and information on Cargo workspaces.
## Adding compile-time [features][features]
If you'd like to add a compile-time feature, you must first define it in
the `main` workspace crate located in `src/main/Cargo.toml`. The feature must
enable a feature in the other workspace crate(s) you intend to use it in. Then
the said workspace crate(s) must define the feature there in its `Cargo.toml`.
So, if this is adding a feature to the API such as `woof`, you define the feature
in the `api` crate's `Cargo.toml` as `woof = []`. The feature definition in `main`'s
`Cargo.toml` will be `woof = ["conduwuit-api/woof"]`.
The rationale for this is due to Rust / Cargo not supporting
["workspace level features"][9], we must make a choice of; either scattering
features all over the workspace crates, making it difficult for anyone to add
or remove default features; or define all the features in one central workspace
crate that propagate down/up to the other workspace crates. It is a Cargo pitfall,
and we'd like to see better developer UX in Rust's Workspaces.
Additionally, the definition of one single place makes "feature collection" in our
Nix flake a million times easier instead of collecting and deduping them all from
searching in all the workspace crates' `Cargo.toml`s. Though we wouldn't need to
do this if Rust supported workspace-level features to begin with.
## List of forked dependencies
During conduwuit development, we have had to fork
some dependencies to support our use-cases in some areas. This ranges from
things said upstream project won't accept for any reason, faster-paced
development (unresponsive or slow upstream), conduwuit-specific usecases, or
lack of time to upstream some things.
- [ruma/ruma][1]: <https://github.com/girlbossceo/ruwuma> - various performance
improvements, more features, faster-paced development, client/server interop
improvements, more features, faster-paced development, better client/server interop
hacks upstream won't accept, etc
- [facebook/rocksdb][2]: <https://github.com/girlbossceo/rocksdb> - liburing
build fixes, GCC build fix, and logging callback C API for Rust tracing
integration
build fixes and GCC debug build fix
- [tikv/jemallocator][3]: <https://github.com/girlbossceo/jemallocator> - musl
builds seem to be broken on upstream
builds seem to be broken on upstream, fixes some broken/suspicious code in
places, additional safety measures, and support redzones for Valgrind
- [zyansheep/rustyline-async][4]:
<https://github.com/girlbossceo/rustyline-async> - tab completion callback and
`CTRL+\` signal quit event for CLI
`CTRL+\` signal quit event for conduwuit console CLI
- [rust-rocksdb/rust-rocksdb][5]:
<https://github.com/girlbossceo/rust-rocksdb-zaidoon1> - [`@zaidoon1`'s][8] fork
has quicker updates, more up to date dependencies. Our changes fix musl build
issues, Rust part of the logging callback C API, removes unnecessary `gtest`
include, and uses our RocksDB and jemallocator
<https://github.com/girlbossceo/rust-rocksdb-zaidoon1> - [`@zaidoon1`][8]'s fork
has quicker updates, more up to date dependencies, etc. Our fork fixes musl build
issues, removes unnecessary `gtest` include, and uses our RocksDB and jemallocator
forks.
- [tokio-rs/tracing][6]: <https://github.com/girlbossceo/tracing> - Implements
`Clone` for `EnvFilter` to support dynamically changing tracing envfilter's
alongside other logging/metrics things
@@ -39,12 +103,16 @@ tokio_unstable` flag to enable experimental tokio APIs. A build might look like
this:
```bash
RUSTFLAGS="--cfg tokio_unstable" cargo build \
RUSTFLAGS="--cfg tokio_unstable" cargo +nightly build \
--release \
--no-default-features \
--features=systemd,element_hacks,gzip_compression,brotli_compression,zstd_compression,tokio_console
```
You will also need to enable the `tokio_console` config option in conduwuit when
starting it. This was due to tokio-console causing gradual memory leak/usage
if left enabled.
[1]: https://github.com/ruma/ruma/
[2]: https://github.com/facebook/rocksdb/
[3]: https://github.com/tikv/jemallocator/
@@ -53,3 +121,11 @@ RUSTFLAGS="--cfg tokio_unstable" cargo build \
[6]: https://github.com/tokio-rs/tracing/
[7]: https://docs.rs/tokio-console/latest/tokio_console/
[8]: https://github.com/zaidoon1/
[9]: https://github.com/rust-lang/cargo/issues/12162
[workspaces]: https://doc.rust-lang.org/cargo/reference/workspaces.html
[macros]: https://doc.rust-lang.org/book/ch19-06-macros.html
[syn]: https://docs.rs/syn/latest/syn/
[proc-macro]: https://doc.rust-lang.org/reference/procedural-macros.html
[clap]: https://docs.rs/clap/latest/clap/
[features]: https://doc.rust-lang.org/cargo/reference/features.html
[state]: https://docs.rs/axum/latest/axum/extract/struct.State.html
+2 -3
View File
@@ -5,8 +5,8 @@
Have a look at [Complement's repository][complement] for an explanation of what
it is.
To test against Complement, with [Lix][lix] and direnv installed and set up, you
can:
To test against Complement, with Nix (or [Lix](https://lix.systems) and direnv
installed and set up, you can:
* Run `./bin/complement "$COMPLEMENT_SRC" ./path/to/logs.jsonl
./path/to/results.jsonl` to build a Complement image, run the tests, and output
@@ -18,6 +18,5 @@ Complement OCI image outputted to `result` (it's a `.tar.gz` file)
output from the commit/revision you want to test (e.g. from main)
[here][ci-workflows]
[lix]: https://lix.systems/
[ci-workflows]: https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml?query=event%3Apush+is%3Asuccess+actor%3Agirlbossceo
[complement]: https://github.com/matrix-org/complement
+1 -2
View File
@@ -241,8 +241,7 @@ both new users and power users
- 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
- Repo uses [Renovate](https://docs.renovatebot.com/) and keeps ALL
dependencies as up to date as possible
- Purge unmaintained/irrelevant/broken database backends (heed, sled, persy) and
other unnecessary code or overhead
+50 -12
View File
@@ -22,23 +22,59 @@ conduwuit has moderation admin commands for:
Any commands with `-list` in them will require a codeblock in the message with
each object being newline delimited. An example of doing this is:
```` !admin rooms moderation ban-list-of-rooms ``` !roomid1:server.name
!roomid2:server.name !roomid3:server.name ``` ````
````
!admin rooms moderation ban-list-of-rooms
```
!roomid1:server.name
#badroomalias1:server.name
!roomid2:server.name
!roomid3:server.name
#badroomalias2:server.name
```
````
## Database
## Database (RocksDB)
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.
Generally there is very little you need to do. [Compaction][rocksdb-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, due to
creating unnecessary I/O amplification. RocksDB is built with io_uring support
via liburing for improved read performance.
RocksDB troubleshooting can be found [in the RocksDB section of troubleshooting](troubleshooting.md).
### Compression
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.
the RocksDB section in the [example config](configuration/examples.md).
RocksDB troubleshooting can be found [in the RocksDB section of
troubleshooting](troubleshooting.md).
btrfs users have reported that database compression does not need to be disabled
on conduwuit as the filesystem already does not attempt to compress. This can be
validated by using `filefrag -v` on a `.SST` file in your database, and ensure
the `physical_offset` matches (no filesystem compression). It is very important
to ensure no additional filesystem compression takes place as this can render
unbuffered Direct IO inoperable, significantly slowing down read and write
performance. See <https://btrfs.readthedocs.io/en/latest/Compression.html#compatibility>
> Compression is done using the COW mechanism so its incompatible with
> nodatacow. Direct IO read works on compressed files but will fall back to
> buffered writes and leads to no compression even if force compression is set.
> Currently nodatasum and compression dont work together.
### Files in database
Do not touch any of the files in the database directory. This must be said due
to users being mislead by the `.log` files in the RocksDB directory, thinking
they're server logs or database logs, however they are critical RocksDB files
related to WAL tracking.
The only safe files that can be deleted are the `LOG` files (all caps). These
are the real RocksDB telemetry/log files, however conduwuit has already
configured to only store up to 3 RocksDB `LOG` files due to generall being
useless for average users unless troubleshooting something low-level. If you
would like to store nearly none at all, see the `rocksdb_max_log_files`
config option.
## Backups
@@ -95,3 +131,5 @@ Built-in S3 support is also planned, but for now using a "S3 filesystem" on
`media/` works. conduwuit also sends a `Cache-Control` header of 1 year and
immutable for all media requests (download and thumbnail) to reduce unnecessary
media requests from browsers, reduce bandwidth usage, and reduce load.
[rocksdb-compaction]: https://github.com/facebook/rocksdb/wiki/Compaction
+83 -19
View File
@@ -41,17 +41,56 @@ workarounds for this are:
- Don't use Docker's default DNS setup and instead allow the container to use
and communicate with your host's DNS servers (host's `/etc/resolv.conf`)
#### DNS No connections available error message
If you receive spurious amounts of error logs saying "DNS No connections
available", this is due to your DNS server (servers from `/etc/resolv.conf`)
being overloaded and unable to handle typical Matrix federation volume. Some
users have reported that the upstream servers are rate-limiting them as well
when they get this error (e.g. popular upstreams like Google DNS).
Matrix federation is extremely heavy and sends wild amounts of DNS requests.
Unfortunately this is by design and has only gotten worse with more
server/destination resolution steps. Synapse also expects a very perfect DNS
setup.
There are some ways you can reduce the amount of DNS queries, but ultimately
the best solution/fix is selfhosting a high quality caching DNS server like
[Unbound][unbound-arch] without any upstream resolvers, and without DNSSEC
validation enabled.
DNSSEC validation is highly recommended to be **disabled** due to DNSSEC being
very computationally expensive, and is extremely susceptible to denial of
service, especially on Matrix. Many servers also strangely have broken DNSSEC
setups and will result in non-functional federation.
conduwuit cannot provide a "works-for-everyone" Unbound DNS setup guide, but
the [official Unbound tuning guide][unbound-tuning] and the [Unbound Arch Linux wiki page][unbound-arch]
may be of interest. Disabling DNSSEC on Unbound is commenting out trust-anchors
config options and removing the `validator` module.
**Avoid** using `systemd-resolved` as it does **not** perform very well under
high load, and we have identified its DNS caching to not be very effective.
dnsmasq can possibly work, but it does **not** support TCP fallback which can be
problematic when receiving large DNS responses such as from large SRV records.
If you still want to use dnsmasq, make sure you **disable** `dns_tcp_fallback`
in conduwuit config.
Raising `dns_cache_entries` in conduwuit config from the default can also assist
in DNS caching, but a full-fledged external caching resolver is better and more
reliable.
If you don't have IPv6 connectivity, changing `ip_lookup_strategy` to match
your setup can help reduce unnecessary AAAA queries
(`1 - Ipv4Only (Only query for A records, no AAAA/IPv6)`).
If your DNS server supports it, some users have reported enabling
`query_over_tcp_only` to force only TCP querying by default has improved DNS
reliability at a slight performance cost due to TCP overhead.
## RocksDB / database issues
#### 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/examples.md) for disabling it if needed. Issues from
Direct IO on unsupported filesystems are usually shown as startup errors.
#### Database corruption
If your database is corrupted *and* is failing to start (e.g. checksum
@@ -105,24 +144,49 @@ Various debug commands can be found in `!admin debug`.
#### Debug/Trace log level
conduwuit builds without debug or trace log levels by default for at least
performance reasons. This may change in the future and/or binaries providing
such configurations may be provided. If you need to access debug/trace log
levels, you will need to build without the `release_max_log_level` feature.
conduwuit builds without debug or trace log levels at compile time by default
for substantial performance gains in CPU usage and improved compile times. If
you need to access debug/trace log levels, you will need to build without the
`release_max_log_level` feature or use our provided static debug binaries.
#### Changing log level dynamically
conduwuit supports changing the tracing log environment filter on-the-fly using
the admin command `!admin debug change-log-level`. This accepts a string
**without quotes** the same format as the `log` config option.
the admin command `!admin debug change-log-level <log env filter>`. This accepts
a string **without quotes** the same format as the `log` config option.
Example: `!admin debug change-log-level debug`
This can also accept complex filters such as:
`!admin debug change-log-level info,conduit_service[{dest="example.com"}]=trace,ruma_state_res=trace`
`!admin debug change-log-level info,conduit_service[{dest="example.com"}]=trace,conduit_service[send{dest="example.org"}]=trace`
And to reset the log level to the one that was set at startup / last config
load, simply pass the `--reset` flag.
`!admin debug change-log-level --reset`
#### Pinging servers
conduwuit can ping other servers using `!admin debug ping`. This takes a server
name and goes through the server discovery process and queries
conduwuit can ping other servers using `!admin debug ping <server>`. This takes
a server name and goes through the server discovery process and queries
`/_matrix/federation/v1/version`. Errors are outputted.
While it does measure the latency of the request, it is not indicative of
server performance on either side as that endpoint is completely unauthenticated
and simply fetches a string on a static JSON endpoint. It is very low cost both
bandwidth and computationally.
#### Allocator memory stats
When using jemalloc with jemallocator's `stats` feature, you can see conduwuit's
jemalloc memory stats by using `!admin debug memory-stats`
When using jemalloc with jemallocator's `stats` feature (`--enable-stats`), you
can see conduwuit's high-level allocator stats by using
`!admin server memory-usage` at the bottom.
If you are a developer, you can also view the raw jemalloc statistics with
`!admin debug memory-stats`. Please note that this output is extremely large
which may only be visible in the conduwuit console CLI due to PDU size limits,
and is not easy for non-developers to understand.
[unbound-tuning]: https://unbound.docs.nlnetlabs.nl/en/latest/topics/core/performance.html
[unbound-arch]: https://wiki.archlinux.org/title/Unbound
+16
View File
@@ -21,6 +21,22 @@ 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.
`turn_secret` or a path to `turn_secret_file` must have a value of your
coturn `static-auth-secret`, or use `turn_username` and `turn_password`
if using legacy username:password TURN authentication (not preferred).
`turn_uris` must be the list of TURN URIs you would like to send to the client.
Typically you will just replace the example domain `example.turn.uri` with the
`realm` you set from the example config.
If you are using TURN over TLS, you can replace `turn:` with `turns:` in the
`turn_uris` config option to instruct clients to attempt to connect to
TURN over TLS. This is highly recommended.
If you need unauthenticated access to the TURN URIs, or some clients may be
having trouble, you can enable `turn_guest_access` in conduwuit which disables
authentication for the TURN URI endpoint `/_matrix/client/v3/voip/turnServer`
### Run
Run the [Coturn](https://hub.docker.com/r/coturn/coturn) image using
+67 -26
View File
@@ -86,6 +86,7 @@ env DIRENV_DEVSHELL=all-features \
direnv exec . \
cargo doc \
--workspace \
--locked \
--profile test \
--all-features \
--no-deps \
@@ -97,10 +98,11 @@ env DIRENV_DEVSHELL=all-features \
name = "clippy/default"
group = "lints"
script = """
direnv exec . \
cargo clippy \
--workspace \
--locked \
--profile test \
--all-targets \
--color=always \
-- \
-D warnings
@@ -114,8 +116,8 @@ env DIRENV_DEVSHELL=all-features \
direnv exec . \
cargo clippy \
--workspace \
--locked \
--profile test \
--all-targets \
--all-features \
--color=always \
-- \
@@ -123,36 +125,41 @@ env DIRENV_DEVSHELL=all-features \
"""
[[task]]
name = "clippy/jemalloc"
name = "clippy/no-features"
group = "lints"
script = """
env DIRENV_DEVSHELL=no-features \
direnv exec . \
cargo clippy \
--workspace \
--locked \
--profile test \
--no-default-features \
--color=always \
-- \
-D warnings
"""
[[task]]
name = "clippy/other-features"
group = "lints"
script = """
direnv exec . \
cargo clippy \
--workspace \
--locked \
--profile test \
--features jemalloc \
--all-targets \
--no-default-features \
--features=console,systemd,element_hacks,direct_tls,perf_measurements,brotli_compression,blurhashing \
--color=always \
-- \
-D warnings
"""
#[[task]]
#name = "clippy/hardened_malloc"
#group = "lints"
#script = """
#cargo clippy \
# --workspace \
# --features hardened_malloc \
# --all-targets \
# --color=always \
# -- \
# -D warnings
#"""
[[task]]
name = "lychee"
group = "lints"
script = "lychee --verbose --offline docs *.md --exclude development.md"
script = "lychee --verbose --offline docs *.md --exclude development.md --exclude contributing.md --exclude testing.md"
[[task]]
name = "markdownlint"
@@ -167,8 +174,10 @@ env DIRENV_DEVSHELL=all-features \
direnv exec . \
cargo test \
--workspace \
--locked \
--profile test \
--all-targets \
--no-fail-fast \
--all-features \
--color=always \
-- \
@@ -179,13 +188,45 @@ env DIRENV_DEVSHELL=all-features \
name = "cargo/default"
group = "tests"
script = """
cargo test \
--workspace \
--profile test \
--all-targets \
--color=always \
-- \
--color=always
env DIRENV_DEVSHELL=default \
direnv exec . \
cargo test \
--workspace \
--locked \
--profile test \
--all-targets \
--no-fail-fast \
--color=always \
-- \
--color=always
"""
[[task]]
name = "cargo/no-features"
group = "tests"
script = """
env DIRENV_DEVSHELL=no-features \
direnv exec . \
cargo test \
--workspace \
--locked \
--profile test \
--all-targets \
--no-fail-fast \
--no-default-features \
--color=always \
-- \
--color=always
"""
# Checks if the generated example config differs from the checked in repo's
# example config.
[[task]]
name = "example-config"
group = "tests"
depends = ["cargo/default"]
script = """
git diff --exit-code conduwuit-example.toml
"""
# Ensure that the flake's default output can build and run without crashing
Generated
+215 -341
View File
@@ -4,16 +4,17 @@
"inputs": {
"crane": "crane",
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"flake-parts": "flake-parts",
"nix-github-actions": "nix-github-actions",
"nixpkgs": "nixpkgs",
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1724226964,
"narHash": "sha256-cltFh4su2vcFidxKp7LuEgX3ZGLfPy0DCdrQZ/QTe68=",
"lastModified": 1731270564,
"narHash": "sha256-6KMC/NH/VWP5Eb+hA56hz0urel3jP6Y6cF2PX6xaTkk=",
"owner": "zhaofengli",
"repo": "attic",
"rev": "6d9aeaef0a067d664cb11bb7704f7ec373d47fb2",
"rev": "47752427561f1c34debb16728a210d378f0ece36",
"type": "github"
},
"original": {
@@ -26,16 +27,16 @@
"cachix": {
"inputs": {
"devenv": "devenv",
"flake-compat": "flake-compat_3",
"flake-compat": "flake-compat_2",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs_3"
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1724232775,
"narHash": "sha256-6u2DycIEgrgNYlLxyGqdFVmBNiKIitnQKJ1pbRP5oko=",
"lastModified": 1737621947,
"narHash": "sha256-8HFvG7fvIFbgtaYAY2628Tb89fA55nPm2jSiNs0/Cws=",
"owner": "cachix",
"repo": "cachix",
"rev": "03b6cb3f953097bff378fb8b9ea094bd091a4ec7",
"rev": "f65a3cd5e339c223471e64c051434616e18cc4f5",
"type": "github"
},
"original": {
@@ -47,33 +48,31 @@
},
"cachix_2": {
"inputs": {
"devenv": "devenv_2",
"devenv": [
"cachix",
"devenv"
],
"flake-compat": [
"cachix",
"devenv",
"flake-compat"
"devenv"
],
"nixpkgs": [
"git-hooks": [
"cachix",
"devenv",
"nixpkgs"
"devenv"
],
"pre-commit-hooks": [
"cachix",
"devenv",
"pre-commit-hooks"
]
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1712055811,
"narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=",
"lastModified": 1728672398,
"narHash": "sha256-KxuGSoVUFnQLB2ZcYODW7AVPAh9JqRlD5BrfsC/Q4qs=",
"owner": "cachix",
"repo": "cachix",
"rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30",
"rev": "aac51f698309fd0f381149214b7eee213c66ef0a",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "latest",
"repo": "cachix",
"type": "github"
}
@@ -81,15 +80,15 @@
"complement": {
"flake": false,
"locked": {
"lastModified": 1722323564,
"narHash": "sha256-6w6/N8walz4Ayc9zu7iySqJRmGFukhkaICLn4dweAcA=",
"owner": "matrix-org",
"lastModified": 1734303596,
"narHash": "sha256-HjDRyLR4MBqQ3IjfMM6eE+8ayztXlbz3gXdyDmFla68=",
"owner": "girlbossceo",
"repo": "complement",
"rev": "6e4426a9e63233f9821a4d2382bfed145244183f",
"rev": "14cc5be797b774f1a2b9f826f38181066d4952b8",
"type": "github"
},
"original": {
"owner": "matrix-org",
"owner": "girlbossceo",
"ref": "main",
"repo": "complement",
"type": "github"
@@ -117,17 +116,12 @@
}
},
"crane_2": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1724006180,
"narHash": "sha256-PVxPj0Ga2fMYMtcT9ARCthF+4U71YkOT7ZjgD/vf1Aw=",
"lastModified": 1737689766,
"narHash": "sha256-ivVXYaYlShxYoKfSo5+y5930qMKKJ8CLcAoIBPQfJ6s=",
"owner": "ipetkov",
"repo": "crane",
"rev": "7ce92819802bc583b7e82ebc08013a530f22209f",
"rev": "6fe74265bbb6d016d663b1091f015e2976c4a527",
"type": "github"
},
"original": {
@@ -144,22 +138,22 @@
"cachix",
"flake-compat"
],
"nix": "nix_2",
"git-hooks": [
"cachix",
"git-hooks"
],
"nix": "nix",
"nixpkgs": [
"cachix",
"nixpkgs"
],
"pre-commit-hooks": [
"cachix",
"git-hooks"
]
},
"locked": {
"lastModified": 1723156315,
"narHash": "sha256-0JrfahRMJ37Rf1i0iOOn+8Z4CLvbcGNwa2ChOAVrp/8=",
"lastModified": 1733323168,
"narHash": "sha256-d5DwB4MZvlaQpN6OQ4SLYxb5jA4UH5EtV5t5WOtjLPU=",
"owner": "cachix",
"repo": "devenv",
"rev": "ff5eb4f2accbcda963af67f1a1159e3f6c7f5f91",
"rev": "efa9010b8b1cfd5dd3c7ed1e172a470c3b84a064",
"type": "github"
},
"original": {
@@ -168,39 +162,6 @@
"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"
]
},
"locked": {
"lastModified": 1708704632,
"narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=",
"owner": "cachix",
"repo": "devenv",
"rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "python-rewrite",
"repo": "devenv",
"type": "github"
}
},
"fenix": {
"inputs": {
"nixpkgs": [
@@ -209,11 +170,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1724221791,
"narHash": "sha256-mKX67QPnUybOopVph/LhOV1G/H4EvPxDIfSmbufrVdA=",
"lastModified": 1737786656,
"narHash": "sha256-ubCW9Jy7ZUOF354bWxTgLDpVnTvIpNr6qR4H/j7I0oo=",
"owner": "nix-community",
"repo": "fenix",
"rev": "e88b38a5a3834e039d413a88f8150a75ef6453ef",
"rev": "2f721f527886f801403f389a9cabafda8f1e3b7f",
"type": "github"
},
"original": {
@@ -242,11 +203,11 @@
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"type": "github"
},
"original": {
@@ -258,27 +219,11 @@
"flake-compat_3": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_4": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"type": "github"
},
"original": {
@@ -288,52 +233,60 @@
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"attic",
"nixpkgs"
]
},
"locked": {
"lastModified": 1722555600,
"narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "8471fe90ad337a8074e957b69ca4d0089218391d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": [
"cachix",
"devenv",
"nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1689068808,
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
@@ -357,11 +310,11 @@
"nixpkgs-stable": "nixpkgs-stable_2"
},
"locked": {
"lastModified": 1723202784,
"narHash": "sha256-qbhjc/NEGaDbyy0ucycubq4N3//gDFFH3DOmp1D3u1Q=",
"lastModified": 1733318908,
"narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "c7012d0c18567c889b948781bc74a501e92275d1",
"rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
"type": "github"
},
"original": {
@@ -392,14 +345,30 @@
"type": "github"
}
},
"libgit2": {
"flake": false,
"locked": {
"lastModified": 1697646580,
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
"owner": "libgit2",
"repo": "libgit2",
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
"type": "github"
},
"original": {
"owner": "libgit2",
"repo": "libgit2",
"type": "github"
}
},
"liburing": {
"flake": false,
"locked": {
"lastModified": 1724199144,
"narHash": "sha256-MVjnwO6EbKzzSrU51dSseLarZ1fRp+6SagAf/nE/XZU=",
"lastModified": 1737600516,
"narHash": "sha256-EKyLQ3pbcjoU5jH5atge59F4fzuhTsb6yalUj6Ve2t8=",
"owner": "axboe",
"repo": "liburing",
"rev": "2d4e799017d64cd2f8304503eef9064931bb3fbd",
"rev": "6c509e2b0c881a13b83b259a221bf15fc9b3f681",
"type": "github"
},
"original": {
@@ -411,38 +380,48 @@
},
"nix": {
"inputs": {
"flake-compat": "flake-compat_2",
"nixpkgs": [
"flake-compat": [
"cachix",
"devenv",
"cachix",
"devenv",
"nixpkgs"
"devenv"
],
"nixpkgs-regression": "nixpkgs-regression"
"flake-parts": "flake-parts_2",
"libgit2": "libgit2",
"nixpkgs": "nixpkgs_3",
"nixpkgs-23-11": [
"cachix",
"devenv"
],
"nixpkgs-regression": [
"cachix",
"devenv"
],
"pre-commit-hooks": [
"cachix",
"devenv"
]
},
"locked": {
"lastModified": 1712911606,
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
"lastModified": 1727438425,
"narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=",
"owner": "domenkozar",
"repo": "nix",
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
"rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546",
"type": "github"
},
"original": {
"owner": "domenkozar",
"ref": "devenv-2.21",
"ref": "devenv-2.24",
"repo": "nix",
"type": "github"
}
},
"nix-filter": {
"locked": {
"lastModified": 1710156097,
"narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=",
"lastModified": 1731533336,
"narHash": "sha256-oRam5PS1vcrr5UPgALW0eo1m/5/pls27Z/pabHNy2Ms=",
"owner": "numtide",
"repo": "nix-filter",
"rev": "3342559a24e85fc164b295c3444e8a139924675b",
"rev": "f7653272fd234696ae94229839a99b73c9ab7de0",
"type": "github"
},
"original": {
@@ -455,20 +434,16 @@
"nix-github-actions": {
"inputs": {
"nixpkgs": [
"cachix",
"devenv",
"cachix",
"devenv",
"poetry2nix",
"attic",
"nixpkgs"
]
},
"locked": {
"lastModified": 1688870561,
"narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
"lastModified": 1729742964,
"narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
"owner": "nix-community",
"repo": "nix-github-actions",
"rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
"rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
"type": "github"
},
"original": {
@@ -477,42 +452,13 @@
"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": 1723827930,
"narHash": "sha256-EU+W5F6y2CVNxGrGIMpY7nSVYq72WRChYxF4zpjx0y4=",
"lastModified": 1726042813,
"narHash": "sha256-LnNKCCxnwgF+575y0pxUdlGZBO/ru1CtGHIqQVfvjlA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d4a7a4d0e066278bfb0d77bd2a7adde1c0ec9e3d",
"rev": "159be5db480d1df880a0135ca0bfed84c2f88353",
"type": "github"
},
"original": {
@@ -522,61 +468,29 @@
"type": "github"
}
},
"nixpkgs-regression": {
"locked": {
"lastModified": 1643052045,
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"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": 1720535198,
"narHash": "sha256-zwVvxrdIzralnSbcpghA92tWu2DV2lwv89xZc8MTrbg=",
"lastModified": 1724316499,
"narHash": "sha256-Qb9MhKBUTCfWg/wqqaxt89Xfi6qTD3XpTzQ9eXi3JmE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "205fd4226592cc83fd4c0885a3e4c9c400efabb5",
"rev": "797f7dc49e0bc7fab4b57c021cdf68f595e47841",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_2": {
"locked": {
"lastModified": 1720386169,
"narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=",
"lastModified": 1730741070,
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "194846768975b7ad2c4988bdb82572c00222c0d7",
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
"type": "github"
},
"original": {
@@ -588,11 +502,59 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1692808169,
"narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=",
"lastModified": 1730531603,
"narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9201b5ff357e781bf014d0330d18555695df7ba8",
"rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1717432640,
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1733212471,
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_5": {
"locked": {
"lastModified": 1737717945,
"narHash": "sha256-ET91TMkab3PmOZnqiJQYOtSGvSTvGeHoegAv4zcTefM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ecd26a469ac56357fd333946a99086e992452b6a",
"type": "github"
},
"original": {
@@ -602,77 +564,19 @@
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1722813957,
"narHash": "sha256-IAoYyYnED7P8zrBFMnmp7ydaJfwTnwcnqxUElC1I26Y=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "cb9a96f23c491c081b38eab96d22fa958043c9fa",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1724271409,
"narHash": "sha256-z4nw9HxkaXEn+5OT8ljLVL2oataHvAzUQ1LEi8Fp+SY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "36a9aeaaa17a2d4348498275f9fe530cd4f9e519",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"poetry2nix": {
"inputs": {
"flake-utils": "flake-utils_2",
"nix-github-actions": "nix-github-actions",
"nixpkgs": [
"cachix",
"devenv",
"cachix",
"devenv",
"nixpkgs"
]
},
"locked": {
"lastModified": 1692876271,
"narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=",
"owner": "nix-community",
"repo": "poetry2nix",
"rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "poetry2nix",
"type": "github"
}
},
"rocksdb": {
"flake": false,
"locked": {
"lastModified": 1724285323,
"narHash": "sha256-k60kreKQ0v+bQ16yBd2SfLYpuNjMw2qoRmZL/S3k6CU=",
"lastModified": 1737828695,
"narHash": "sha256-8Ev6zzhNPU798JNvU27a7gj5X+6SDG3jBweUkQ59DbA=",
"owner": "girlbossceo",
"repo": "rocksdb",
"rev": "5a67ad7ce46328578ee5587fb0c23faa03d14e67",
"rev": "a4d9230dcc9d03be428b9a728133f8f646c0065c",
"type": "github"
},
"original": {
"owner": "girlbossceo",
"ref": "v9.5.2",
"ref": "v9.9.3",
"repo": "rocksdb",
"type": "github"
}
@@ -684,22 +588,22 @@
"complement": "complement",
"crane": "crane_2",
"fenix": "fenix",
"flake-compat": "flake-compat_4",
"flake-utils": "flake-utils_3",
"flake-compat": "flake-compat_3",
"flake-utils": "flake-utils",
"liburing": "liburing",
"nix-filter": "nix-filter",
"nixpkgs": "nixpkgs_4",
"nixpkgs": "nixpkgs_5",
"rocksdb": "rocksdb"
}
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1724153119,
"narHash": "sha256-WxpvDJDttkINkXmUA/W5o11lwLPYhATAgu0QUAacZ2g=",
"lastModified": 1737728869,
"narHash": "sha256-U4pl3Hi0lT6GP4ecN3q9wdD2sdaKMbmD/5NJ1NdJ9AM=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "3723e5910c14f0ffbd13de474b8a8fcc74db04ce",
"rev": "6e4c29f7ce18cea7d3d31237a4661ab932eab636",
"type": "github"
},
"original": {
@@ -723,36 +627,6 @@
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"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",
+233 -63
View File
@@ -2,14 +2,14 @@
inputs = {
attic.url = "github:zhaofengli/attic?ref=main";
cachix.url = "github:cachix/cachix?ref=master";
complement = { url = "github:matrix-org/complement?ref=main"; flake = false; };
crane = { url = "github:ipetkov/crane?ref=master"; inputs.nixpkgs.follows = "nixpkgs"; };
complement = { url = "github:girlbossceo/complement?ref=main"; flake = false; };
crane = { url = "github:ipetkov/crane?ref=master"; };
fenix = { url = "github:nix-community/fenix?ref=main"; inputs.nixpkgs.follows = "nixpkgs"; };
flake-compat = { url = "github:edolstra/flake-compat?ref=master"; flake = false; };
flake-utils.url = "github:numtide/flake-utils?ref=main";
nix-filter.url = "github:numtide/nix-filter?ref=main";
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.5.2"; flake = false; };
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixpkgs-unstable";
rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.9.3"; flake = false; };
liburing = { url = "github:axboe/liburing?ref=master"; flake = false; };
};
@@ -18,7 +18,6 @@
let
pkgsHost = import inputs.nixpkgs{
inherit system;
config.permittedInsecurePackages = [ "olm-3.2.16" ];
};
pkgsHostStatic = pkgsHost.pkgsStatic;
@@ -27,7 +26,7 @@
file = ./rust-toolchain.toml;
# See also `rust-toolchain.toml`
sha256 = "sha256-3jVIIf5XPnUU1CRaTyAiO0XHVbJl12MSx3eucTXCjtE=";
sha256 = "sha256-lMLAupxng4Fd9F1oDw8gx+qA0RuF7ou7xhNU8wgs0PU=";
};
mkScope = pkgs: pkgs.lib.makeScope pkgs.newScope (self: {
@@ -38,7 +37,23 @@
inherit inputs;
main = self.callPackage ./nix/pkgs/main {};
oci-image = self.callPackage ./nix/pkgs/oci-image {};
rocksdb = pkgs.rocksdb.overrideAttrs (old: {
tini = pkgs.tini.overrideAttrs {
# newer clang/gcc is unhappy with tini-static: <https://3.dog/~strawberry/pb/c8y4>
patches = [ (pkgs.fetchpatch {
url = "https://patch-diff.githubusercontent.com/raw/krallin/tini/pull/224.patch";
hash = "sha256-4bTfAhRyIT71VALhHY13hUgbjLEUyvgkIJMt3w9ag3k=";
})
];
};
liburing = pkgs.liburing.overrideAttrs {
# Tests weren't building
outputs = [ "out" "dev" "man" ];
buildFlags = [ "library" ];
src = inputs.liburing;
};
rocksdb = (pkgs.rocksdb.override {
liburing = self.liburing;
}).overrideAttrs (old: {
src = inputs.rocksdb;
version = pkgs.lib.removePrefix
"v"
@@ -57,9 +72,16 @@
"-DWITH_TESTS=1"
# we use rust-rocksdb via C interface and dont need C++ RTTI
"-DUSE_RTTI=1"
# this doesn't exist in RocksDB, and USE_SSE is deprecated for
# PORTABLE=$(march)
"-DFORCE_SSE42=1"
# PORTABLE will get set in main/default.nix
"-DPORTABLE=1"
]
old.cmakeFlags
++ [
# no real reason to have snappy, no one uses this
"-DWITH_SNAPPY=0"
# we dont need to use ldb or sst_dump (core_tools)
"-DWITH_CORE_TOOLS=0"
# we dont need trace tools
@@ -76,18 +98,20 @@
# preInstall hooks has stuff for messing with ldb/sst_dump which we dont need or use
preInstall = "";
});
# TODO: remove once https://github.com/NixOS/nixpkgs/pull/314945 is available
liburing = pkgs.liburing.overrideAttrs (old: {
# the configure script doesn't support these, and unconditionally
# builds both static and dynamic libraries.
configureFlags = pkgs.lib.subtractLists
[ "--enable-static" "--disable-shared" ]
old.configureFlags;
});
});
scopeHost = mkScope pkgsHost;
scopeHostStatic = mkScope pkgsHostStatic;
scopeCrossLinux = mkScope pkgsHost.pkgsLinux.pkgsStatic;
mkCrossScope = crossSystem:
let pkgsCrossStatic = (import inputs.nixpkgs {
inherit system;
crossSystem = {
config = crossSystem;
};
}).pkgsStatic;
in
mkScope pkgsCrossStatic;
mkDevShell = scope: scope.pkgs.mkShell {
env = scope.main.env // {
@@ -100,9 +124,9 @@
# code.
COMPLEMENT_SRC = inputs.complement.outPath;
# Needed for Complement
CGO_CFLAGS = "-I${scope.pkgs.olm}/include";
CGO_LDFLAGS = "-L${scope.pkgs.olm}/lib";
# Needed for Complement: <https://github.com/golang/go/issues/52690>
CGO_CFLAGS = "-Wl,--no-gc-sections";
CGO_LDFLAGS = "-Wl,--no-gc-sections";
};
# Development tools
@@ -119,6 +143,9 @@
engage
cargo-audit
# Required by hardened-malloc.rs dep
binutils
# Needed for producing Debian packages
cargo-deb
@@ -142,36 +169,69 @@
# used for rust caching in CI to speed it up
sccache
# needed so we can get rid of gcc and other unused deps that bloat OCI images
removeReferencesTo
])
]
# liburing is Linux-exclusive
++ lib.optional stdenv.hostPlatform.isLinux liburing)
++ scope.main.buildInputs
++ scope.main.propagatedBuildInputs
++ scope.main.nativeBuildInputs;
meta.broken = scope.main.meta.broken;
};
in
{
packages = {
default = scopeHost.main;
default = scopeHost.main.override {
disable_features = [
# dont include experimental features
"experimental"
# jemalloc profiling/stats features are expensive and shouldn't
# be expected on non-debug builds.
"jemalloc_prof"
"jemalloc_stats"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
default-debug = scopeHost.main.override {
profile = "dev";
# debug build users expect full logs
disable_release_max_log_level = true;
disable_features = [
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
# just a test profile used for things like CI and complement
default-test = scopeHost.main.override {
profile = "test";
disable_release_max_log_level = true;
disable_features = [
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
all-features = scopeHost.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
# jemalloc profiling/stats features are expensive and shouldn't
# be expected on non-debug builds.
"jemalloc_prof"
"jemalloc_stats"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
all-features-debug = scopeHost.main.override {
@@ -180,10 +240,12 @@
# debug build users expect full logs
disable_release_max_log_level = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
hmalloc = scopeHost.main.override { features = ["hardened_malloc"]; };
@@ -193,10 +255,16 @@
main = scopeHost.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
# jemalloc profiling/stats features are expensive and shouldn't
# be expected on non-debug builds.
"jemalloc_prof"
"jemalloc_stats"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
};
@@ -207,10 +275,12 @@
# debug build users expect full logs
disable_release_max_log_level = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
};
@@ -224,6 +294,8 @@
complement = scopeHost.complement;
static-complement = scopeHostStatic.complement;
# macOS containers don't exist, so the complement images must be forced to linux
linux-complement = (mkCrossScope "${pkgsHost.hostPlatform.qemuArch}-linux-musl").complement;
}
//
builtins.listToAttrs
@@ -232,14 +304,7 @@
(crossSystem:
let
binaryName = "static-${crossSystem}";
pkgsCrossStatic =
(import inputs.nixpkgs {
inherit system;
crossSystem = {
config = crossSystem;
};
}).pkgsStatic;
scopeCrossStatic = mkScope pkgsCrossStatic;
scopeCrossStatic = mkCrossScope crossSystem;
in
[
# An output for a statically-linked binary
@@ -248,6 +313,15 @@
value = scopeCrossStatic.main;
}
# An output for a statically-linked binary with x86_64 haswell
# target optimisations
{
name = "${binaryName}-x86_64-haswell-optimised";
value = scopeCrossStatic.main.override {
x86_64_haswell_target_optimised = (if (crossSystem == "x86_64-linux-gnu" || crossSystem == "x86_64-linux-musl") then true else false);
};
}
# An output for a statically-linked unstripped debug ("dev") binary
{
name = "${binaryName}-debug";
@@ -265,6 +339,14 @@
value = scopeCrossStatic.main.override {
profile = "test";
disable_release_max_log_level = true;
disable_features = [
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
}
@@ -274,14 +356,42 @@
value = scopeCrossStatic.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
# jemalloc profiling/stats features are expensive and shouldn't
# be expected on non-debug builds.
"jemalloc_prof"
"jemalloc_stats"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
}
# An output for a statically-linked binary with `--all-features` and with x86_64 haswell
# target optimisations
{
name = "${binaryName}-all-features-x86_64-haswell-optimised";
value = scopeCrossStatic.main.override {
all_features = true;
disable_features = [
# dont include experimental features
"experimental"
# jemalloc profiling/stats features are expensive and shouldn't
# be expected on non-debug builds.
"jemalloc_prof"
"jemalloc_stats"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
x86_64_haswell_target_optimised = (if (crossSystem == "x86_64-linux-gnu" || crossSystem == "x86_64-linux-musl") then true else false);
};
}
# An output for a statically-linked unstripped debug ("dev") binary with `--all-features`
{
name = "${binaryName}-all-features-debug";
@@ -291,10 +401,12 @@
# debug build users expect full logs
disable_release_max_log_level = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
}
@@ -313,6 +425,17 @@
value = scopeCrossStatic.oci-image;
}
# An output for an OCI image based on that binary with x86_64 haswell
# target optimisations
{
name = "oci-image-${crossSystem}-x86_64-haswell-optimised";
value = scopeCrossStatic.oci-image.override {
main = scopeCrossStatic.main.override {
x86_64_haswell_target_optimised = (if (crossSystem == "x86_64-linux-gnu" || crossSystem == "x86_64-linux-musl") then true else false);
};
};
}
# An output for an OCI image based on that unstripped debug ("dev") binary
{
name = "oci-image-${crossSystem}-debug";
@@ -332,30 +455,62 @@
main = scopeCrossStatic.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
# dont include experimental features
"experimental"
# jemalloc profiling/stats features are expensive and shouldn't
# be expected on non-debug builds.
"jemalloc_prof"
"jemalloc_stats"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
};
}
# An output for an OCI image based on that binary with `--all-features` and with x86_64 haswell
# target optimisations
{
name = "oci-image-${crossSystem}-all-features-x86_64-haswell-optimised";
value = scopeCrossStatic.oci-image.override {
main = scopeCrossStatic.main.override {
all_features = true;
disable_features = [
# dont include experimental features
"experimental"
# jemalloc profiling/stats features are expensive and shouldn't
# be expected on non-debug builds.
"jemalloc_prof"
"jemalloc_stats"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
x86_64_haswell_target_optimised = (if (crossSystem == "x86_64-linux-gnu" || crossSystem == "x86_64-linux-musl") then true else false);
};
};
}
# An output for an OCI image based on that unstripped debug ("dev") binary with `--all-features`
{
name = "oci-image-${crossSystem}-all-features-debug";
value = scopeCrossStatic.oci-image.override {
main = scopeCrossStatic.main.override {
profile = "dev";
all_features = true;
# debug build users expect full logs
disable_release_max_log_level = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
profile = "dev";
all_features = true;
# debug build users expect full logs
disable_release_max_log_level = true;
disable_features = [
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
};
}
@@ -369,11 +524,20 @@
};
};
}
# An output for a complement OCI image for the specified platform
{
name = "complement-${crossSystem}";
value = scopeCrossStatic.complement;
}
]
)
[
"x86_64-unknown-linux-musl"
"aarch64-unknown-linux-musl"
#"x86_64-apple-darwin"
#"aarch64-apple-darwin"
"x86_64-linux-gnu"
"x86_64-linux-musl"
"aarch64-linux-musl"
]
)
);
@@ -384,10 +548,16 @@
main = prev.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
# jemalloc profiling/stats features are expensive and shouldn't
# be expected on non-debug builds.
"jemalloc_prof"
"jemalloc_stats"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
];
};
}));
+2
View File
@@ -14,8 +14,10 @@ stdenv.mkDerivation {
include = [
"book.toml"
"conduwuit-example.toml"
"CODE_OF_CONDUCT.md"
"CONTRIBUTING.md"
"README.md"
"development.md"
"debian/conduwuit.service"
"debian/README.md"
"arch/conduwuit.service"
+29 -2
View File
@@ -9,13 +9,40 @@ database_path = "/database"
log = "trace,h2=warn,hyper=warn"
port = [8008, 8448]
trusted_servers = []
only_query_trusted_key_servers = false
query_trusted_key_servers_first = false
query_trusted_key_servers_first_on_join = false
yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse = true
ip_range_denylist = []
url_preview_domain_contains_allowlist = ["*"]
url_preview_domain_explicit_denylist = ["*"]
media_compat_file_link = false
media_startup_check = false
rocksdb_direct_io = false
media_startup_check = true
prune_missing_media = true
log_colors = false
admin_room_notices = false
allow_check_for_updates = false
intentionally_unknown_config_option_for_testing = true
rocksdb_log_level = "debug"
rocksdb_max_log_files = 1
rocksdb_recovery_mode = 0
rocksdb_paranoid_file_checks = true
log_guest_registrations = false
allow_legacy_media = true
startup_netburst = true
startup_netburst_keep = -1
# valgrind makes things so slow
dns_timeout = 60
dns_attempts = 20
request_conn_timeout = 60
request_timeout = 120
well_known_conn_timeout = 60
well_known_timeout = 60
federation_idle_timeout = 300
sender_timeout = 300
sender_idle_timeout = 300
sender_retry_backoff_limit = 300
[global.tls]
certs = "/certificate.crt"
+17 -2
View File
@@ -18,10 +18,24 @@ let
all_features = true;
disable_release_max_log_level = true;
disable_features = [
# console/CLI stuff isn't used or relevant for complement
"console"
"tokio_console"
# sentry telemetry isn't useful for complement, disabled by default anyways
"sentry_telemetry"
"perf_measurements"
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
# compression isn't needed for complement
"brotli_compression"
"gzip_compression"
"zstd_compression"
# complement doesn't need hot reloading
"conduwuit_mods"
# complement doesn't have URL preview media tests
"url_preview"
];
};
@@ -57,7 +71,7 @@ let
in
dockerTools.buildImage {
name = "complement-${main.pname}";
name = "complement-conduwuit";
tag = "main";
copyToRoot = buildEnv {
@@ -78,7 +92,7 @@ dockerTools.buildImage {
"${lib.getExe start}"
];
Entrypoint = if !stdenv.isDarwin
Entrypoint = if !stdenv.hostPlatform.isDarwin
# Use the `tini` init system so that signals (e.g. ctrl+c/SIGINT)
# are handled as expected
then [ "${lib.getExe' tini "tini"}" "--" ]
@@ -87,6 +101,7 @@ dockerTools.buildImage {
Env = [
"SSL_CERT_FILE=/complement/ca/ca.crt"
"CONDUWUIT_CONFIG=${./config.toml}"
"RUST_BACKTRACE=full"
];
ExposedPorts = {
+8 -27
View File
@@ -13,12 +13,6 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
lib.concatStringsSep
" "
([]
++ lib.optionals
stdenv.targetPlatform.isx86_64
[ "-C" "target-cpu=x86-64-v2" ]
++ lib.optionals
stdenv.targetPlatform.isAarch64
[ "-C" "target-cpu=cortex-a55" ] # cortex-a55 == ARMv8.2-a
# This disables PIE for static builds, which isn't great in terms
# of security. Unfortunately, my hand is forced because nixpkgs'
# `libstdc++.a` is built without `-fPIE`, which precludes us from
@@ -28,25 +22,13 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
[ "-C" "relocation-model=static" ]
++ lib.optionals
(stdenv.buildPlatform.config != stdenv.hostPlatform.config)
[ "-l" "c" ]
++ lib.optionals
# This check has to match the one [here][0]. We only need to set
# these flags when using a different linker. Don't ask me why,
# though, because I don't know. All I know is it breaks otherwise.
#
# [0]: https://github.com/NixOS/nixpkgs/blob/5cdb38bb16c6d0a38779db14fcc766bc1b2394d6/pkgs/build-support/rust/lib/default.nix#L37-L40
(
# Nixpkgs doesn't check for x86_64 here but we do, because I
# observed a failure building statically for x86_64 without
# including it here. Linkers are weird.
(stdenv.hostPlatform.isAarch64 || stdenv.hostPlatform.isx86_64)
&& stdenv.hostPlatform.isStatic
&& !stdenv.isDarwin
&& !stdenv.cc.bintools.isLLVM
)
[
"-l"
"c"
"-l"
"stdc++"
"-L"
"${stdenv.cc.cc.lib}/${stdenv.hostPlatform.config}/lib"
]
@@ -58,7 +40,7 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
# even covers the case of build scripts that need native code compiled and
# run on the build platform (I think).
#
# [0]: https://github.com/NixOS/nixpkgs/blob/5cdb38bb16c6d0a38779db14fcc766bc1b2394d6/pkgs/build-support/rust/lib/default.nix#L57-L80
# [0]: https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/pkgs/build-support/rust/lib/default.nix#L48-L68
//
(
let
@@ -74,8 +56,7 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
{
"CC_${cargoEnvVarTarget}" = envVars.ccForTarget;
"CXX_${cargoEnvVarTarget}" = envVars.cxxForTarget;
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" =
envVars.linkerForTarget;
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.ccForTarget;
}
)
//
@@ -86,7 +67,7 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
{
"CC_${cargoEnvVarTarget}" = envVars.ccForHost;
"CXX_${cargoEnvVarTarget}" = envVars.cxxForHost;
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.linkerForHost;
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.ccForHost;
CARGO_BUILD_TARGET = rustcTarget;
}
)
@@ -98,7 +79,7 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
{
"CC_${cargoEnvVarTarget}" = envVars.ccForBuild;
"CXX_${cargoEnvVarTarget}" = envVars.cxxForBuild;
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.linkerForBuild;
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.ccForBuild;
HOST_CC = "${pkgsBuildHost.stdenv.cc}/bin/cc";
HOST_CXX = "${pkgsBuildHost.stdenv.cc}/bin/c++";
}
+69 -56
View File
@@ -13,12 +13,29 @@
, stdenv
# Options (keep sorted)
, default_features ? true
, disable_release_max_log_level ? false
, all_features ? false
, disable_features ? []
, default_features ? true
# default list of disabled features
, disable_features ? [
# dont include experimental features
"experimental"
# jemalloc profiling/stats features are expensive and shouldn't
# be expected on non-debug builds.
"jemalloc_prof"
"jemalloc_stats"
# this is non-functional on nix for some reason
"hardened_malloc"
# conduwuit_mods is a development-only hot reload feature
"conduwuit_mods"
]
, disable_release_max_log_level ? false
, features ? []
, profile ? "release"
# rocksdb compiled with -march=haswell and target-cpu=haswell rustflag
# haswell is pretty much any x86 cpu made in the last 12 years, and
# supports modern CPU extensions that rocksdb can make use of.
# disable if trying to make a portable x86_64 build for very old hardware
, x86_64_haswell_target_optimised ? false
}:
let
@@ -40,7 +57,7 @@ features'' = lib.subtractLists disable_features' features';
featureEnabled = feature : builtins.elem feature features'';
enableLiburing = featureEnabled "io_uring" && !stdenv.isDarwin;
enableLiburing = featureEnabled "io_uring" && !stdenv.hostPlatform.isDarwin;
# This derivation will set the JEMALLOC_OVERRIDE variable, causing the
# tikv-jemalloc-sys crate to use the nixpkgs jemalloc instead of building it's
@@ -65,42 +82,33 @@ rust-jemalloc-sys' = (rust-jemalloc-sys.override {
buildDepsOnlyEnv =
let
rocksdb' = (rocksdb.override {
jemalloc = rust-jemalloc-sys';
jemalloc = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys';
# rocksdb fails to build with prefixed jemalloc, which is required on
# darwin due to [1]. In this case, fall back to building rocksdb with
# libc malloc. This should not cause conflicts, because all of the
# jemalloc symbols are prefixed.
#
# [1]: https://github.com/tikv/jemallocator/blob/ab0676d77e81268cd09b059260c75b38dbef2d51/jemalloc-sys/src/env.rs#L17
enableJemalloc = featureEnabled "jemalloc" && !stdenv.isDarwin;
enableJemalloc = featureEnabled "jemalloc" && !stdenv.hostPlatform.isDarwin;
# for some reason enableLiburing in nixpkgs rocksdb is default true
# which breaks Darwin entirely
enableLiburing = enableLiburing;
}).overrideAttrs (old: {
# TODO: static rocksdb fails to build on darwin, also see <https://github.com/NixOS/nixpkgs/issues/320448>
# build log at <https://girlboss.ceo/~strawberry/pb/JjGH>
meta.broken = stdenv.hostPlatform.isStatic && stdenv.isDarwin;
enableLiburing = enableLiburing;
cmakeFlags = (if x86_64_haswell_target_optimised then (lib.subtractLists [
# dont make a portable build if x86_64_haswell_target_optimised is enabled
"-DPORTABLE=1"
] old.cmakeFlags
++ [ "-DPORTABLE=haswell" ]) else ([ "-DPORTABLE=1" ])
)
++ old.cmakeFlags;
sse42Support = stdenv.targetPlatform.isx86_64;
# outputs has "tools" which we dont need or use
outputs = [ "out" ];
cmakeFlags = if stdenv.targetPlatform.isx86_64
then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags
++ lib.optionals stdenv.targetPlatform.isx86_64 [
"-DPORTABLE=x86-64-v2"
"-DUSE_SSE=1"
"-DHAVE_SSE=1"
"-DHAVE_SSE42=1"
]
else if stdenv.targetPlatform.isAarch64
then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags
++ lib.optionals stdenv.targetPlatform.isAarch64 [
# cortex-a73 == ARMv8-A
"-DPORTABLE=armv8-a"
]
else old.cmakeFlags;
# preInstall hooks has stuff for messing with ldb/sst_dump which we dont need or use
preInstall = "";
});
in
{
@@ -128,10 +136,8 @@ buildPackageEnv = {
CARGO_BUILD_RUSTFLAGS = buildDepsOnlyEnv.CARGO_BUILD_RUSTFLAGS
+ lib.optionalString (enableLiburing && stdenv.hostPlatform.isStatic)
" -L${lib.getLib liburing}/lib -luring"
+ lib.optionalString stdenv.targetPlatform.isx86_64
" -Ctarget-cpu=x86-64-v2"
+ lib.optionalString stdenv.targetPlatform.isAarch64
" -Ctarget-cpu=cortex-a73"; # cortex-a73 == ARMv8-A
+ lib.optionalString x86_64_haswell_target_optimised
" -Ctarget-cpu=haswell";
};
@@ -156,10 +162,32 @@ commonAttrs = {
];
};
# This is redundant with CI
doCheck = false;
cargoTestCommand = "cargo test --locked ";
cargoExtraArgs = "--no-default-features --locked "
+ lib.optionalString
(features'' != [])
"--features " + (builtins.concatStringsSep "," features'');
cargoTestExtraArgs = "--no-default-features --locked "
+ lib.optionalString
(features'' != [])
"--features " + (builtins.concatStringsSep "," features'');
dontStrip = profile == "dev" || profile == "test";
dontPatchELF = profile == "dev" || profile == "test";
buildInputs = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys';
buildInputs = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys'
# needed to build Rust applications on macOS
++ lib.optionals stdenv.hostPlatform.isDarwin [
# https://github.com/NixOS/nixpkgs/issues/206242
# ld: library not found for -liconv
libiconv
# https://stackoverflow.com/questions/69869574/properly-adding-darwin-apple-sdk-to-a-nix-shell
# https://discourse.nixos.org/t/compile-a-rust-binary-on-macos-dbcrossbar/8612
pkgsBuildHost.darwin.apple_sdk.frameworks.Security
];
nativeBuildInputs = [
# bindgen needs the build platform's libclang. Apparently due to "splicing
@@ -172,25 +200,7 @@ commonAttrs = {
# differing values for `NIX_CFLAGS_COMPILE`, which contributes to spurious
# rebuilds of bindgen and its depedents.
jq
# needed so we can get rid of gcc and other unused deps that bloat OCI images
removeReferencesTo
]
++ lib.optionals stdenv.isDarwin [
# https://github.com/NixOS/nixpkgs/issues/206242
libiconv
# https://stackoverflow.com/questions/69869574/properly-adding-darwin-apple-sdk-to-a-nix-shell
# https://discourse.nixos.org/t/compile-a-rust-binary-on-macos-dbcrossbar/8612
pkgsBuildHost.darwin.apple_sdk.frameworks.Security
];
# for some reason gcc and other weird deps are added to OCI images and bloats it up
#
# <https://github.com/input-output-hk/haskell.nix/issues/829>
postInstall = with pkgsBuildHost; ''
find "$out" -type f -exec remove-references-to -t ${stdenv.cc} -t ${gcc} -t ${libgcc} -t ${linuxHeaders} -t ${libidn2} -t ${libunistring} '{}' +
'';
];
};
in
@@ -199,15 +209,18 @@ craneLib.buildPackage ( commonAttrs // {
env = buildDepsOnlyEnv;
});
cargoExtraArgs = "--no-default-features "
# This is redundant with CI
doCheck = false;
cargoTestCommand = "cargo test --locked ";
cargoExtraArgs = "--no-default-features --locked "
+ lib.optionalString
(features'' != [])
"--features " + (builtins.concatStringsSep "," features'');
cargoTestExtraArgs = "--no-default-features --locked "
+ lib.optionalString
(features'' != [])
"--features " + (builtins.concatStringsSep "," features'');
# This is redundant with CI
cargoTestCommand = "";
cargoCheckCommand = "";
doCheck = false;
env = buildPackageEnv;
+19 -1
View File
@@ -14,9 +14,10 @@ dockerTools.buildLayeredImage {
created = "@${toString inputs.self.lastModified}";
contents = [
dockerTools.caCertificates
main
];
config = {
Entrypoint = if !stdenv.isDarwin
Entrypoint = if !stdenv.hostPlatform.isDarwin
# Use the `tini` init system so that signals (e.g. ctrl+c/SIGINT)
# are handled as expected
then [ "${lib.getExe' tini "tini"}" "--" ]
@@ -24,5 +25,22 @@ dockerTools.buildLayeredImage {
Cmd = [
"${lib.getExe main}"
];
Env = [
"RUST_BACKTRACE=full"
];
Labels = {
"org.opencontainers.image.authors" = "June Clementine Strawberry <june@girlboss.ceo> and Jason Volk
<jason@zemos.net>";
"org.opencontainers.image.created" ="@${toString inputs.self.lastModified}";
"org.opencontainers.image.description" = "a very cool Matrix chat homeserver written in Rust";
"org.opencontainers.image.documentation" = "https://conduwuit.puppyirl.gay/";
"org.opencontainers.image.licenses" = "Apache-2.0";
"org.opencontainers.image.revision" = inputs.self.rev or inputs.self.dirtyRev or "";
"org.opencontainers.image.source" = "https://github.com/girlbossceo/conduwuit";
"org.opencontainers.image.title" = main.pname;
"org.opencontainers.image.url" = "https://conduwuit.puppyirl.gay/";
"org.opencontainers.image.vendor" = "girlbossceo";
"org.opencontainers.image.version" = main.version;
};
};
}
+8 -3
View File
@@ -2,8 +2,6 @@
#
# Other files that need upkeep when this changes:
#
# * `.gitlab-ci.yml`
# * `.github/workflows/ci.yml`
# * `Cargo.toml`
# * `flake.nix`
#
@@ -11,13 +9,20 @@
# If you're having trouble making the relevant changes, bug a maintainer.
[toolchain]
channel = "1.80.1"
channel = "1.84.0"
profile = "minimal"
components = [
# For rust-analyzer
"rust-src",
"rust-analyzer",
# For CI and editors
"rustfmt",
"clippy",
]
targets = [
#"x86_64-apple-darwin",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-musl",
"aarch64-unknown-linux-musl",
#"aarch64-apple-darwin",
]
+20 -15
View File
@@ -1,28 +1,33 @@
edition = "2021"
array_width = 80
chain_width = 60
comment_width = 80
condense_wildcard_suffixes = true
edition = "2024"
fn_call_width = 80
fn_single_line = true
format_code_in_doc_comments = true
format_macro_bodies = true
format_macro_matchers = true
format_strings = true
hex_literal_case = "Upper"
max_width = 120
tab_spaces = 4
array_width = 80
comment_width = 80
wrap_comments = true
fn_params_layout = "Compressed"
fn_call_width = 80
fn_single_line = true
group_imports = "StdExternalCrate"
hard_tabs = true
match_block_trailing_comma = true
hex_literal_case = "Upper"
imports_granularity = "Crate"
match_arm_blocks = false
match_arm_leading_pipes = "Always"
match_block_trailing_comma = true
max_width = 98
newline_style = "Unix"
normalize_comments = false
overflow_delimited_expr = true
reorder_impl_items = true
reorder_imports = true
group_imports = "StdExternalCrate"
newline_style = "Unix"
single_line_if_else_max_width = 60
single_line_let_else_max_width = 80
struct_lit_width = 40
tab_spaces = 4
unstable_features = true
use_field_init_shorthand = true
use_small_heuristics = "Off"
use_try_shorthand = true
chain_width = 60
wrap_comments = true
+7 -7
View File
@@ -1,5 +1,5 @@
[package]
name = "conduit_admin"
name = "conduwuit_admin"
categories.workspace = true
description.workspace = true
edition.workspace = true
@@ -17,7 +17,6 @@ crate-type = [
]
[features]
#dev_release_log_level = []
release_max_log_level = [
"tracing/max_level_trace",
"tracing/release_max_level_info",
@@ -27,12 +26,13 @@ release_max_log_level = [
[dependencies]
clap.workspace = true
conduit-api.workspace = true
conduit-core.workspace = true
conduit-macros.workspace = true
conduit-service.workspace = true
conduwuit-api.workspace = true
conduwuit-core.workspace = true
conduwuit-database.workspace = true
conduwuit-macros.workspace = true
conduwuit-service.workspace = true
const-str.workspace = true
futures-util.workspace = true
futures.workspace = true
log.workspace = true
ruma.workspace = true
serde_json.workspace = true
+20 -18
View File
@@ -1,15 +1,15 @@
use clap::Parser;
use conduit::Result;
use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use crate::{
appservice, appservice::AppserviceCommand, check, check::CheckCommand, command::Command, debug,
debug::DebugCommand, federation, federation::FederationCommand, media, media::MediaCommand, query,
query::QueryCommand, room, room::RoomCommand, server, server::ServerCommand, user, user::UserCommand,
appservice, appservice::AppserviceCommand, check, check::CheckCommand, command::Command,
debug, debug::DebugCommand, federation, federation::FederationCommand, media,
media::MediaCommand, query, query::QueryCommand, room, room::RoomCommand, server,
server::ServerCommand, user, user::UserCommand,
};
#[derive(Debug, Parser)]
#[command(name = "admin", version = env!("CARGO_PKG_VERSION"))]
#[command(name = "conduwuit", version = conduwuit::version())]
pub(super) enum AdminCommand {
#[command(subcommand)]
/// - Commands for managing appservices
@@ -49,18 +49,20 @@ pub(super) enum AdminCommand {
}
#[tracing::instrument(skip_all, name = "command")]
pub(super) async fn process(command: AdminCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(command: AdminCommand, context: &Command<'_>) -> Result {
use AdminCommand::*;
Ok(match command {
Appservices(command) => appservice::process(command, context).await?,
Media(command) => media::process(command, context).await?,
Users(command) => user::process(command, context).await?,
Rooms(command) => room::process(command, context).await?,
Federation(command) => federation::process(command, context).await?,
Server(command) => server::process(command, context).await?,
Debug(command) => debug::process(command, context).await?,
Query(command) => query::process(command, context).await?,
Check(command) => check::process(command, context).await?,
})
match command {
| Appservices(command) => appservice::process(command, context).await?,
| Media(command) => media::process(command, context).await?,
| Users(command) => user::process(command, context).await?,
| Rooms(command) => room::process(command, context).await?,
| Federation(command) => federation::process(command, context).await?,
| Server(command) => server::process(command, context).await?,
| Debug(command) => debug::process(command, context).await?,
| Query(command) => query::process(command, context).await?,
| Check(command) => check::process(command, context).await?,
};
Ok(())
}
+33 -17
View File
@@ -4,59 +4,75 @@ use crate::{admin_command, Result};
#[admin_command]
pub(super) async fn register(&self) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
));
}
let appservice_config = self.body[1..self.body.len().checked_sub(1).unwrap()].join("\n");
let parsed_config = serde_yaml::from_str::<Registration>(&appservice_config);
let appservice_config_body = self.body[1..self.body.len().checked_sub(1).unwrap()].join("\n");
let parsed_config = serde_yaml::from_str::<Registration>(&appservice_config_body);
match parsed_config {
Ok(yaml) => match self.services.appservice.register_appservice(yaml).await {
Ok(id) => Ok(RoomMessageEventContent::text_plain(format!(
"Appservice registered with ID: {id}."
| Ok(registration) => match self
.services
.appservice
.register_appservice(&registration, &appservice_config_body)
.await
{
| Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
"Appservice registered with ID: {}",
registration.id
))),
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to register appservice: {e}"
))),
},
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Could not parse appservice config: {e}"
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Could not parse appservice config as YAML: {e}"
))),
}
}
#[admin_command]
pub(super) async fn unregister(&self, appservice_identifier: String) -> Result<RoomMessageEventContent> {
pub(super) async fn unregister(
&self,
appservice_identifier: String,
) -> Result<RoomMessageEventContent> {
match self
.services
.appservice
.unregister_appservice(&appservice_identifier)
.await
{
Ok(()) => Ok(RoomMessageEventContent::text_plain("Appservice unregistered.")),
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
| Ok(()) => Ok(RoomMessageEventContent::text_plain("Appservice unregistered.")),
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to unregister appservice: {e}"
))),
}
}
#[admin_command]
pub(super) async fn show_appservice_config(&self, appservice_identifier: String) -> Result<RoomMessageEventContent> {
pub(super) async fn show_appservice_config(
&self,
appservice_identifier: String,
) -> Result<RoomMessageEventContent> {
match self
.services
.appservice
.get_registration(&appservice_identifier)
.await
{
Some(config) => {
let config_str = serde_yaml::to_string(&config).expect("config should've been validated on register");
let output = format!("Config for {appservice_identifier}:\n\n```yaml\n{config_str}\n```",);
| Some(config) => {
let config_str = serde_yaml::to_string(&config)
.expect("config should've been validated on register");
let output =
format!("Config for {appservice_identifier}:\n\n```yaml\n{config_str}\n```",);
Ok(RoomMessageEventContent::notice_markdown(output))
},
None => Ok(RoomMessageEventContent::text_plain("Appservice does not exist.")),
| None => Ok(RoomMessageEventContent::text_plain("Appservice does not exist.")),
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
mod commands;
use clap::Subcommand;
use conduit::Result;
use conduwuit::Result;
use crate::admin_command_dispatch;
+9 -9
View File
@@ -1,5 +1,6 @@
use conduit::Result;
use conduit_macros::implement;
use conduwuit::Result;
use conduwuit_macros::implement;
use futures::StreamExt;
use ruma::events::room::message::RoomMessageEventContent;
use crate::Command;
@@ -10,18 +11,17 @@ use crate::Command;
#[implement(Command, params = "<'_>")]
pub(super) async fn check_all_users(&self) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let results = self.services.users.db.iter();
let users = self.services.users.iter().collect::<Vec<_>>().await;
let query_time = timer.elapsed();
let users = results.collect::<Vec<_>>();
let total = users.len();
let err_count = users.iter().filter(|user| user.is_err()).count();
let ok_count = users.iter().filter(|user| user.is_ok()).count();
let err_count = users.iter().filter(|_user| false).count();
let ok_count = users.iter().filter(|_user| true).count();
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:?}\n```"
"Database query completed in {query_time:?}:\n\n```\nTotal entries: \
{total:?}\nFailure/Invalid user count: {err_count:?}\nSuccess/Valid user count: \
{ok_count:?}\n```"
);
Ok(RoomMessageEventContent::notice_markdown(message))
+4 -10
View File
@@ -1,18 +1,12 @@
mod commands;
use clap::Subcommand;
use conduit::Result;
use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use crate::Command;
use crate::admin_command_dispatch;
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
pub(super) enum CheckCommand {
AllUsers,
}
pub(super) async fn process(command: CheckCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
Ok(match command {
CheckCommand::AllUsers => context.check_all_users().await?,
})
CheckAllUsers,
}
+30 -2
View File
@@ -1,6 +1,12 @@
use std::time::SystemTime;
use std::{fmt, time::SystemTime};
use conduit_service::Services;
use conduwuit::Result;
use conduwuit_service::Services;
use futures::{
io::{AsyncWriteExt, BufWriter},
lock::Mutex,
Future, FutureExt,
};
use ruma::EventId;
pub(crate) struct Command<'a> {
@@ -8,4 +14,26 @@ pub(crate) struct Command<'a> {
pub(crate) body: &'a [&'a str],
pub(crate) timer: SystemTime,
pub(crate) reply_id: Option<&'a EventId>,
pub(crate) output: Mutex<BufWriter<Vec<u8>>>,
}
impl Command<'_> {
pub(crate) fn write_fmt(
&self,
arguments: fmt::Arguments<'_>,
) -> impl Future<Output = Result> + Send + '_ {
let buf = format!("{arguments}");
self.output.lock().then(|mut output| async move {
output.write_all(buf.as_bytes()).await.map_err(Into::into)
})
}
pub(crate) fn write_str<'a>(
&'a self,
s: &'a str,
) -> impl Future<Output = Result> + Send + 'a {
self.output.lock().then(move |mut output| async move {
output.write_all(s.as_bytes()).await.map_err(Into::into)
})
}
}
File diff suppressed because it is too large Load Diff
+46 -4
View File
@@ -2,8 +2,9 @@ mod commands;
pub(crate) mod tester;
use clap::Subcommand;
use conduit::Result;
use conduwuit::Result;
use ruma::{EventId, OwnedRoomOrAliasId, RoomId, ServerName};
use service::rooms::short::{ShortEventId, ShortRoomId};
use self::tester::TesterCommand;
use crate::admin_command_dispatch;
@@ -31,12 +32,21 @@ pub(super) enum DebugCommand {
/// the command.
ParsePdu,
/// - Retrieve and print a PDU by ID from the conduwuit database
/// - Retrieve and print a PDU by EventID from the conduwuit database
GetPdu {
/// An event ID (a $ followed by the base64 reference hash)
event_id: Box<EventId>,
},
/// - Retrieve and print a PDU by PduId from the conduwuit database
GetShortPdu {
/// Shortroomid integer
shortroomid: ShortRoomId,
/// Shorteventid integer
shorteventid: ShortEventId,
},
/// - Attempts to retrieve a PDU from a remote server. Inserts it into our
/// database/timeline if found and we do not have this PDU already
/// (following normal event auth rules, handles it as an incoming PDU).
@@ -80,8 +90,16 @@ pub(super) enum DebugCommand {
GetSigningKeys {
server_name: Option<Box<ServerName>>,
#[arg(long)]
notary: Option<Box<ServerName>>,
#[arg(short, long)]
cached: bool,
query: bool,
},
/// - Get and display signing keys from local cache or remote server.
GetVerifyKeys {
server_name: Option<Box<ServerName>>,
},
/// - Sends a federation request to the remote server's
@@ -119,6 +137,13 @@ pub(super) enum DebugCommand {
/// the command.
VerifyJson,
/// - Verify PDU
///
/// This re-verifies a PDU existing in the database found by ID.
VerifyPdu {
event_id: Box<EventId>,
},
/// - Prints the very first PDU in the specified room (typically
/// m.room.create)
FirstPduInRoom {
@@ -166,7 +191,13 @@ pub(super) enum DebugCommand {
},
/// - Print extended memory usage
MemoryStats,
///
/// Optional argument is a character mask (a sequence of characters in any
/// order) which enable additional extended statistics. Known characters are
/// "abdeglmx". For convenience, a '*' will enable everything.
MemoryStats {
opts: Option<String>,
},
/// - Print general tokio runtime metric totals.
RuntimeMetrics,
@@ -192,6 +223,17 @@ pub(super) enum DebugCommand {
map: Option<String>,
},
/// - Trim memory usage
TrimMemory,
/// - List database files
DatabaseFiles {
map: Option<String>,
#[arg(long)]
level: Option<i32>,
},
/// - Developer test stubs
#[command(subcommand)]
#[allow(non_snake_case)]
+2 -2
View File
@@ -1,4 +1,4 @@
use conduit::Err;
use conduwuit::Err;
use ruma::events::room::message::RoomMessageEventContent;
use crate::{admin_command, admin_command_dispatch, Result};
@@ -31,7 +31,7 @@ async fn failure(&self) -> Result<RoomMessageEventContent> {
#[admin_command]
async fn tester(&self) -> Result<RoomMessageEventContent> {
Ok(RoomMessageEventContent::notice_plain("completed"))
Ok(RoomMessageEventContent::notice_plain("legacy"))
}
#[inline(never)]
+37 -41
View File
@@ -1,19 +1,22 @@
use std::fmt::Write;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, RoomId, ServerName, UserId};
use conduwuit::Result;
use futures::StreamExt;
use ruma::{
events::room::message::RoomMessageEventContent, OwnedRoomId, RoomId, ServerName, UserId,
};
use crate::{admin_command, escape_html, get_room_info};
use crate::{admin_command, get_room_info};
#[admin_command]
pub(super) async fn disable_room(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
self.services.rooms.metadata.disable_room(&room_id, true)?;
self.services.rooms.metadata.disable_room(&room_id, true);
Ok(RoomMessageEventContent::text_plain("Room disabled."))
}
#[admin_command]
pub(super) async fn enable_room(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
self.services.rooms.metadata.disable_room(&room_id, false)?;
self.services.rooms.metadata.disable_room(&room_id, false);
Ok(RoomMessageEventContent::text_plain("Room enabled."))
}
@@ -37,7 +40,10 @@ pub(super) async fn incoming_federation(&self) -> Result<RoomMessageEventContent
}
#[admin_command]
pub(super) async fn fetch_support_well_known(&self, server_name: Box<ServerName>) -> Result<RoomMessageEventContent> {
pub(super) async fn fetch_support_well_known(
&self,
server_name: Box<ServerName>,
) -> Result<RoomMessageEventContent> {
let response = self
.services
.client
@@ -59,16 +65,20 @@ pub(super) async fn fetch_support_well_known(&self, server_name: Box<ServerName>
}
let json: serde_json::Value = match serde_json::from_str(&text) {
Ok(json) => json,
Err(_) => {
return Ok(RoomMessageEventContent::text_plain("Response text/body is not valid JSON."));
| Ok(json) => json,
| Err(_) => {
return Ok(RoomMessageEventContent::text_plain(
"Response text/body is not valid JSON.",
));
},
};
let pretty_json: String = match serde_json::to_string_pretty(&json) {
Ok(json) => json,
Err(_) => {
return Ok(RoomMessageEventContent::text_plain("Response text/body is not valid JSON."));
| Ok(json) => json,
| Err(_) => {
return Ok(RoomMessageEventContent::text_plain(
"Response text/body is not valid JSON.",
));
},
};
@@ -78,14 +88,18 @@ pub(super) async fn fetch_support_well_known(&self, server_name: Box<ServerName>
}
#[admin_command]
pub(super) async fn remote_user_in_rooms(&self, user_id: Box<UserId>) -> Result<RoomMessageEventContent> {
if user_id.server_name() == self.services.globals.config.server_name {
pub(super) async fn remote_user_in_rooms(
&self,
user_id: Box<UserId>,
) -> Result<RoomMessageEventContent> {
if user_id.server_name() == self.services.server.name {
return Ok(RoomMessageEventContent::text_plain(
"User belongs to our server, please use `list-joined-rooms` user admin command instead.",
"User belongs to our server, please use `list-joined-rooms` user admin command \
instead.",
));
}
if !self.services.users.exists(&user_id)? {
if !self.services.users.exists(&user_id).await {
return Ok(RoomMessageEventContent::text_plain(
"Remote user does not exist in our database.",
));
@@ -96,9 +110,9 @@ pub(super) async fn remote_user_in_rooms(&self, user_id: Box<UserId>) -> Result<
.rooms
.state_cache
.rooms_joined(&user_id)
.filter_map(Result::ok)
.map(|room_id| get_room_info(self.services, &room_id))
.collect();
.then(|room_id| get_room_info(self.services, room_id))
.collect()
.await;
if rooms.is_empty() {
return Ok(RoomMessageEventContent::text_plain("User is not in any rooms."));
@@ -107,33 +121,15 @@ pub(super) async fn remote_user_in_rooms(&self, user_id: Box<UserId>) -> Result<
rooms.sort_by_key(|r| r.1);
rooms.reverse();
let output_plain = format!(
"Rooms {user_id} shares with us ({}):\n{}",
let output = format!(
"Rooms {user_id} shares with us ({}):\n```\n{}\n```",
rooms.len(),
rooms
.iter()
.map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}"))
.map(|(id, members, name)| format!("{id} | Members: {members} | Name: {name}"))
.collect::<Vec<_>>()
.join("\n")
);
let output_html = format!(
"<table><caption>Rooms {user_id} shares with us \
({})</caption>\n<tr><th>id</th>\t<th>members</th>\t<th>name</th></tr>\n{}</table>",
rooms.len(),
rooms
.iter()
.fold(String::new(), |mut output, (id, members, name)| {
writeln!(
output,
"<tr><td>{}</td>\t<td>{}</td>\t<td>{}</td></tr>",
id,
members,
escape_html(name)
)
.expect("should be able to write to string buffer");
output
})
);
Ok(RoomMessageEventContent::text_html(output_plain, output_html))
Ok(RoomMessageEventContent::text_markdown(output))
}
+1 -1
View File
@@ -1,7 +1,7 @@
mod commands;
use clap::Subcommand;
use conduit::Result;
use conduwuit::Result;
use ruma::{RoomId, ServerName, UserId};
use crate::admin_command_dispatch;
+158 -76
View File
@@ -1,16 +1,21 @@
use std::time::Duration;
use conduit::{debug, info, trace, utils::time::parse_timepoint_ago, warn, Result};
use conduit_service::media::Dim;
use conduwuit::{
debug, debug_info, debug_warn, error, info, trace, utils::time::parse_timepoint_ago, Result,
};
use conduwuit_service::media::Dim;
use ruma::{
events::room::message::RoomMessageEventContent, EventId, Mxc, MxcUri, OwnedMxcUri, OwnedServerName, ServerName,
events::room::message::RoomMessageEventContent, EventId, Mxc, MxcUri, OwnedMxcUri,
OwnedServerName, ServerName,
};
use crate::{admin_command, utils::parse_local_user_id};
#[admin_command]
pub(super) async fn delete(
&self, mxc: Option<Box<MxcUri>>, event_id: Option<Box<EventId>>,
&self,
mxc: Option<Box<MxcUri>>,
event_id: Option<Box<EventId>>,
) -> Result<RoomMessageEventContent> {
if event_id.is_some() && mxc.is_some() {
return Ok(RoomMessageEventContent::text_plain(
@@ -19,7 +24,7 @@ pub(super) async fn delete(
}
if let Some(mxc) = mxc {
debug!("Got MXC URL: {mxc}");
trace!("Got MXC URL: {mxc}");
self.services
.media
.delete(&mxc.as_str().try_into()?)
@@ -28,14 +33,15 @@ pub(super) async fn delete(
return Ok(RoomMessageEventContent::text_plain(
"Deleted the MXC from our database and on our filesystem.",
));
} else if let Some(event_id) = event_id {
debug!("Got event ID to delete media from: {event_id}");
}
let mut mxc_urls = vec![];
let mut mxc_deletion_count: usize = 0;
if let Some(event_id) = event_id {
trace!("Got event ID to delete media from: {event_id}");
let mut mxc_urls = Vec::with_capacity(4);
// parsing the PDU for any MXC URLs begins here
if let Some(event_json) = self.services.rooms.timeline.get_pdu_json(&event_id)? {
if let Ok(event_json) = self.services.rooms.timeline.get_pdu_json(&event_id).await {
if let Some(content_key) = event_json.get("content") {
debug!("Event ID has \"content\".");
let content_obj = content_key.as_object();
@@ -51,7 +57,10 @@ pub(super) async fn delete(
let final_url = url.to_string().replace('"', "");
mxc_urls.push(final_url);
} else {
info!("Found a URL in the event ID {event_id} but did not start with mxc://, ignoring");
info!(
"Found a URL in the event ID {event_id} but did not start with \
mxc://, ignoring"
);
}
}
@@ -66,17 +75,24 @@ pub(super) async fn delete(
debug!("Found a thumbnail_url in info key: {thumbnail_url}");
if thumbnail_url.to_string().starts_with("\"mxc://") {
debug!("Pushing thumbnail URL {thumbnail_url} to list of MXCs to delete");
let final_thumbnail_url = thumbnail_url.to_string().replace('"', "");
debug!(
"Pushing thumbnail URL {thumbnail_url} to list of MXCs \
to delete"
);
let final_thumbnail_url =
thumbnail_url.to_string().replace('"', "");
mxc_urls.push(final_thumbnail_url);
} else {
info!(
"Found a thumbnail URL in the event ID {event_id} but did not start with \
mxc://, ignoring"
"Found a thumbnail URL in the event ID {event_id} but \
did not start with mxc://, ignoring"
);
}
} else {
info!("No \"thumbnail_url\" key in \"info\" key, assuming no thumbnails.");
info!(
"No \"thumbnail_url\" key in \"info\" key, assuming no \
thumbnails."
);
}
}
}
@@ -97,8 +113,8 @@ pub(super) async fn delete(
mxc_urls.push(final_url);
} else {
info!(
"Found a URL in the event ID {event_id} but did not start with mxc://, \
ignoring"
"Found a URL in the event ID {event_id} but did not \
start with mxc://, ignoring"
);
}
} else {
@@ -108,13 +124,14 @@ pub(super) async fn delete(
}
} else {
return Ok(RoomMessageEventContent::text_plain(
"Event ID does not have a \"content\" key or failed parsing the event ID JSON.",
"Event ID does not have a \"content\" key or failed parsing the event \
ID JSON.",
));
}
} else {
return Ok(RoomMessageEventContent::text_plain(
"Event ID does not have a \"content\" key, this is not a message or an event type that contains \
media.",
"Event ID does not have a \"content\" key, this is not a message or an \
event type that contains media.",
));
}
} else {
@@ -124,68 +141,120 @@ pub(super) async fn delete(
}
if mxc_urls.is_empty() {
// we shouldn't get here (should have errored earlier) but just in case for
// whatever reason we do...
info!("Parsed event ID {event_id} but did not contain any MXC URLs.");
return Ok(RoomMessageEventContent::text_plain("Parsed event ID but found no MXC URLs."));
return Ok(RoomMessageEventContent::text_plain(
"Parsed event ID but found no MXC URLs.",
));
}
let mut mxc_deletion_count: usize = 0;
for mxc_url in mxc_urls {
self.services
match self
.services
.media
.delete(&mxc_url.as_str().try_into()?)
.await?;
mxc_deletion_count = mxc_deletion_count.saturating_add(1);
.await
{
| Ok(()) => {
debug_info!("Successfully deleted {mxc_url} from filesystem and database");
mxc_deletion_count = mxc_deletion_count.saturating_add(1);
},
| Err(e) => {
debug_warn!("Failed to delete {mxc_url}, ignoring error and skipping: {e}");
continue;
},
}
}
return Ok(RoomMessageEventContent::text_plain(format!(
"Deleted {mxc_deletion_count} total MXCs from our database and the filesystem from event ID {event_id}."
"Deleted {mxc_deletion_count} total MXCs from our database and the filesystem from \
event ID {event_id}."
)));
}
Ok(RoomMessageEventContent::text_plain(
"Please specify either an MXC using --mxc or an event ID using --event-id of the message containing an image. \
See --help for details.",
"Please specify either an MXC using --mxc or an event ID using --event-id of the \
message containing an image. See --help for details.",
))
}
#[admin_command]
pub(super) async fn delete_list(&self) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
));
}
let mut failed_parsed_mxcs: usize = 0;
let mxc_list = self
.body
.to_vec()
.drain(1..self.body.len().checked_sub(1).unwrap())
.collect::<Vec<_>>();
.filter_map(|mxc_s| {
mxc_s
.try_into()
.inspect_err(|e| {
debug_warn!("Failed to parse user-provided MXC URI: {e}");
failed_parsed_mxcs = failed_parsed_mxcs.saturating_add(1);
})
.ok()
})
.collect::<Vec<Mxc<'_>>>();
let mut mxc_deletion_count: usize = 0;
for mxc in mxc_list {
debug!("Deleting MXC {mxc} in bulk");
self.services.media.delete(&mxc.try_into()?).await?;
mxc_deletion_count = mxc_deletion_count
.checked_add(1)
.expect("mxc_deletion_count should not get this high");
for mxc in &mxc_list {
trace!(%failed_parsed_mxcs, %mxc_deletion_count, "Deleting MXC {mxc} in bulk");
match self.services.media.delete(mxc).await {
| Ok(()) => {
debug_info!("Successfully deleted {mxc} from filesystem and database");
mxc_deletion_count = mxc_deletion_count.saturating_add(1);
},
| Err(e) => {
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
continue;
},
}
}
Ok(RoomMessageEventContent::text_plain(format!(
"Finished bulk MXC deletion, deleted {mxc_deletion_count} total MXCs from our database and the filesystem.",
"Finished bulk MXC deletion, deleted {mxc_deletion_count} total MXCs from our database \
and the filesystem. {failed_parsed_mxcs} MXCs failed to be parsed from the database.",
)))
}
#[admin_command]
pub(super) async fn delete_past_remote_media(&self, duration: String, force: bool) -> Result<RoomMessageEventContent> {
pub(super) async fn delete_past_remote_media(
&self,
duration: String,
before: bool,
after: bool,
yes_i_want_to_delete_local_media: bool,
) -> Result<RoomMessageEventContent> {
if before && after {
return Ok(RoomMessageEventContent::text_plain(
"Please only pick one argument, --before or --after.",
));
}
assert!(!(before && after), "--before and --after should not be specified together");
let duration = parse_timepoint_ago(&duration)?;
let deleted_count = self
.services
.media
.delete_all_remote_media_at_after_time(duration, force)
.delete_all_remote_media_at_after_time(
duration,
before,
after,
yes_i_want_to_delete_local_media,
)
.await?;
Ok(RoomMessageEventContent::text_plain(format!(
@@ -194,14 +263,13 @@ pub(super) async fn delete_past_remote_media(&self, duration: String, force: boo
}
#[admin_command]
pub(super) async fn delete_all_from_user(&self, username: String, force: bool) -> Result<RoomMessageEventContent> {
pub(super) async fn delete_all_from_user(
&self,
username: String,
) -> Result<RoomMessageEventContent> {
let user_id = parse_local_user_id(self.services, &username)?;
let deleted_count = self
.services
.media
.delete_from_user(&user_id, force)
.await?;
let deleted_count = self.services.media.delete_from_user(&user_id).await?;
Ok(RoomMessageEventContent::text_plain(format!(
"Deleted {deleted_count} total files.",
@@ -210,34 +278,44 @@ pub(super) async fn delete_all_from_user(&self, username: String, force: bool) -
#[admin_command]
pub(super) async fn delete_all_from_server(
&self, server_name: Box<ServerName>, force: bool,
&self,
server_name: Box<ServerName>,
yes_i_want_to_delete_local_media: bool,
) -> Result<RoomMessageEventContent> {
if server_name == self.services.globals.server_name() {
return Ok(RoomMessageEventContent::text_plain("This command only works for remote media."));
if server_name == self.services.globals.server_name() && !yes_i_want_to_delete_local_media {
return Ok(RoomMessageEventContent::text_plain(
"This command only works for remote media by default.",
));
}
let Ok(all_mxcs) = self.services.media.get_all_mxcs().await else {
return Ok(RoomMessageEventContent::text_plain("Failed to get MXC URIs from our database"));
let Ok(all_mxcs) = self
.services
.media
.get_all_mxcs()
.await
.inspect_err(|e| error!("Failed to get MXC URIs from our database: {e}"))
else {
return Ok(RoomMessageEventContent::text_plain(
"Failed to get MXC URIs from our database",
));
};
let mut deleted_count: usize = 0;
for mxc in all_mxcs {
let mxc_server_name = match mxc.server_name() {
Ok(server_name) => server_name,
Err(e) => {
if force {
warn!("Failed to parse MXC {mxc} server name from database, ignoring error and skipping: {e}");
continue;
}
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to parse MXC {mxc} server name from database: {e}",
)));
},
let Ok(mxc_server_name) = mxc.server_name().inspect_err(|e| {
debug_warn!(
"Failed to parse MXC {mxc} server name from database, ignoring error and \
skipping: {e}"
);
}) else {
continue;
};
if mxc_server_name != server_name || self.services.globals.server_is_ours(mxc_server_name) {
if mxc_server_name != server_name
|| (self.services.globals.server_is_ours(mxc_server_name)
&& !yes_i_want_to_delete_local_media)
{
trace!("skipping MXC URI {mxc}");
continue;
}
@@ -245,16 +323,12 @@ pub(super) async fn delete_all_from_server(
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
match self.services.media.delete(&mxc).await {
Ok(()) => {
| Ok(()) => {
deleted_count = deleted_count.saturating_add(1);
},
Err(e) => {
if force {
warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
continue;
}
return Ok(RoomMessageEventContent::text_plain(format!("Failed to delete MXC {mxc}: {e}")));
| Err(e) => {
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
continue;
},
}
}
@@ -267,14 +341,17 @@ pub(super) async fn delete_all_from_server(
#[admin_command]
pub(super) async fn get_file_info(&self, mxc: OwnedMxcUri) -> Result<RoomMessageEventContent> {
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
let metadata = self.services.media.get_metadata(&mxc);
let metadata = self.services.media.get_metadata(&mxc).await;
Ok(RoomMessageEventContent::notice_markdown(format!("```\n{metadata:#?}\n```")))
}
#[admin_command]
pub(super) async fn get_remote_file(
&self, mxc: OwnedMxcUri, server: Option<OwnedServerName>, timeout: u32,
&self,
mxc: OwnedMxcUri,
server: Option<OwnedServerName>,
timeout: u32,
) -> Result<RoomMessageEventContent> {
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
let timeout = Duration::from_millis(timeout.into());
@@ -294,7 +371,12 @@ pub(super) async fn get_remote_file(
#[admin_command]
pub(super) async fn get_remote_thumbnail(
&self, mxc: OwnedMxcUri, server: Option<OwnedServerName>, timeout: u32, width: u32, height: u32,
&self,
mxc: OwnedMxcUri,
server: Option<OwnedServerName>,
timeout: u32,
width: u32,
height: u32,
) -> Result<RoomMessageEventContent> {
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
let timeout = Duration::from_millis(timeout.into());
+28 -21
View File
@@ -1,7 +1,7 @@
mod commands;
use clap::Subcommand;
use conduit::Result;
use conduwuit::Result;
use ruma::{EventId, MxcUri, OwnedMxcUri, OwnedServerName, ServerName};
use crate::admin_command_dispatch;
@@ -10,7 +10,7 @@ use crate::admin_command_dispatch;
#[derive(Debug, Subcommand)]
pub(super) enum MediaCommand {
/// - Deletes a single media file from our database and on the filesystem
/// via a single MXC URL
/// via a single MXC URL or event ID (not redacted)
Delete {
/// The MXC URL to delete
#[arg(long)]
@@ -23,37 +23,44 @@ pub(super) enum MediaCommand {
},
/// - Deletes a codeblock list of MXC URLs from our database and on the
/// filesystem
/// filesystem. This will always ignore errors.
DeleteList,
/// - Deletes all remote media in the last X amount of time using filesystem
/// metadata first created at date.
/// - Deletes all remote (and optionally local) media created before or
/// after \[duration] time using filesystem metadata first created at
/// date, or fallback to last modified date. This will always ignore
/// errors by default.
DeletePastRemoteMedia {
/// - The duration (at or after), e.g. "5m" to delete all media in the
/// past 5 minutes
/// - The relative time (e.g. 30s, 5m, 7d) within which to search
duration: String,
/// Continues deleting remote media if an undeletable object is found
#[arg(short, long)]
force: bool,
/// - Only delete media created more recently than \[duration] ago
#[arg(long, short)]
before: bool,
/// - Only delete media created after \[duration] ago
#[arg(long, short)]
after: bool,
/// - Long argument to additionally delete local media
#[arg(long)]
yes_i_want_to_delete_local_media: bool,
},
/// - Deletes all the local media from a local user on our server
/// - Deletes all the local media from a local user on our server. This will
/// always ignore errors by default.
DeleteAllFromUser {
username: String,
/// Continues deleting media if an undeletable object is found
#[arg(short, long)]
force: bool,
},
/// - Deletes all remote media from the specified remote server
/// - Deletes all remote media from the specified remote server. This will
/// always ignore errors by default.
DeleteAllFromServer {
server_name: Box<ServerName>,
/// Continues deleting media if an undeletable object is found
#[arg(short, long)]
force: bool,
/// Long argument to delete local media
#[arg(long)]
yes_i_want_to_delete_local_media: bool,
},
GetFileInfo {
@@ -82,10 +89,10 @@ pub(super) enum MediaCommand {
#[arg(short, long, default_value("10000"))]
timeout: u32,
#[arg(short, long)]
#[arg(short, long, default_value("800"))]
width: u32,
#[arg(short, long)]
#[arg(short, long, default_value("800"))]
height: u32,
},
}
+9 -8
View File
@@ -1,6 +1,7 @@
#![recursion_limit = "192"]
#![allow(clippy::wildcard_imports)]
#![allow(clippy::enum_glob_use)]
#![allow(clippy::too_many_arguments)]
pub(crate) mod admin;
pub(crate) mod command;
@@ -18,12 +19,12 @@ pub(crate) mod room;
pub(crate) mod server;
pub(crate) mod user;
extern crate conduit_api as api;
extern crate conduit_core as conduit;
extern crate conduit_service as service;
extern crate conduwuit_api as api;
extern crate conduwuit_core as conduwuit;
extern crate conduwuit_service as service;
pub(crate) use conduit::Result;
pub(crate) use conduit_macros::{admin_command, admin_command_dispatch};
pub(crate) use conduwuit::Result;
pub(crate) use conduwuit_macros::{admin_command, admin_command_dispatch};
pub(crate) use crate::{
command::Command,
@@ -32,9 +33,9 @@ pub(crate) use crate::{
pub(crate) const PAGE_SIZE: usize = 100;
conduit::mod_ctor! {}
conduit::mod_dtor! {}
conduit::rustc_flags_capture! {}
conduwuit::mod_ctor! {}
conduwuit::mod_dtor! {}
conduwuit::rustc_flags_capture! {}
/// Install the admin command processor
pub async fn init(admin_service: &service::admin::Service) {
+50 -31
View File
@@ -1,12 +1,13 @@
use std::{
fmt::Write,
mem::take,
panic::AssertUnwindSafe,
sync::{Arc, Mutex},
time::SystemTime,
};
use clap::{CommandFactory, Parser};
use conduit::{
use conduwuit::{
debug, error,
log::{
capture,
@@ -17,7 +18,7 @@ use conduit::{
utils::string::{collect_stream, common_prefix},
warn, Error, Result,
};
use futures_util::future::FutureExt;
use futures::{future::FutureExt, io::BufWriter, AsyncWriteExt};
use ruma::{
events::{
relation::InReplyTo,
@@ -53,8 +54,8 @@ async fn handle_command(services: Arc<Services>, command: CommandInput) -> Proce
async fn process_command(services: Arc<Services>, input: &CommandInput) -> ProcessorResult {
let (command, args, body) = match parse(&services, input) {
Err(error) => return Err(error),
Ok(parsed) => parsed,
| Err(error) => return Err(error),
| Ok(parsed) => parsed,
};
let context = Command {
@@ -62,13 +63,37 @@ async fn process_command(services: Arc<Services>, input: &CommandInput) -> Proce
body: &body,
timer: SystemTime::now(),
reply_id: input.reply_id.as_deref(),
output: BufWriter::new(Vec::new()).into(),
};
process(&context, command, &args).await
let (result, mut logs) = process(&context, command, &args).await;
let output = &mut context.output.lock().await;
output.flush().await.expect("final flush of output stream");
let output =
String::from_utf8(take(output.get_mut())).expect("invalid utf8 in command output stream");
match result {
| Ok(()) if logs.is_empty() =>
Ok(Some(reply(RoomMessageEventContent::notice_markdown(output), context.reply_id))),
| Ok(()) => {
logs.write_str(output.as_str()).expect("output buffer");
Ok(Some(reply(RoomMessageEventContent::notice_markdown(logs), context.reply_id)))
},
| Err(error) => {
write!(&mut logs, "Command failed with error:\n```\n{error:#?}\n```")
.expect("output buffer");
Err(reply(RoomMessageEventContent::notice_markdown(logs), context.reply_id))
},
}
}
fn handle_panic(error: &Error, command: &CommandInput) -> ProcessorResult {
let link = "Please submit a [bug report](https://github.com/girlbossceo/conduwuit/issues/new). 🥺";
let link =
"Please submit a [bug report](https://github.com/girlbossceo/conduwuit/issues/new). 🥺";
let msg = format!("Panic occurred while processing command:\n```\n{error:#?}\n```\n{link}");
let content = RoomMessageEventContent::notice_markdown(msg);
error!("Panic while processing command: {error:?}");
@@ -76,7 +101,11 @@ fn handle_panic(error: &Error, command: &CommandInput) -> ProcessorResult {
}
// Parse and process a message from the admin room
async fn process(context: &Command<'_>, command: AdminCommand, args: &[String]) -> ProcessorResult {
async fn process(
context: &Command<'_>,
command: AdminCommand,
args: &[String],
) -> (Result, String) {
let (capture, logs) = capture_create(context);
let capture_scope = capture.start();
@@ -99,17 +128,7 @@ async fn process(context: &Command<'_>, command: AdminCommand, args: &[String])
}
drop(logs);
match result {
Ok(content) => {
write!(&mut output, "{0}", content.body()).expect("failed to format command result to output buffer");
Ok(Some(reply(RoomMessageEventContent::notice_markdown(output), context.reply_id)))
},
Err(error) => {
write!(&mut output, "Command failed with error:\n```\n{error:#?}\n```")
.expect("failed to format command result to output");
Err(reply(RoomMessageEventContent::notice_markdown(output), context.reply_id))
},
}
(result, output)
}
fn capture_create(context: &Command<'_>) -> (Arc<Capture>, Arc<Mutex<String>>) {
@@ -128,8 +147,9 @@ fn capture_create(context: &Command<'_>) -> (Arc<Capture>, Arc<Mutex<String>>) {
.and_then(LevelFilter::into_level)
.unwrap_or(Level::DEBUG);
let filter =
move |data: capture::Data<'_>| data.level() <= log_level && data.our_modules() && data.scope.contains(&"admin");
let filter = move |data: capture::Data<'_>| {
data.level() <= log_level && data.our_modules() && data.scope.contains(&"admin")
};
let logs = Arc::new(Mutex::new(
collect_stream(|s| markdown_table_head(s)).expect("markdown table header"),
@@ -146,21 +166,19 @@ fn capture_create(context: &Command<'_>) -> (Arc<Capture>, Arc<Mutex<String>>) {
// Parse chat messages from the admin room into an AdminCommand object
fn parse<'a>(
services: &Arc<Services>, input: &'a CommandInput,
services: &Arc<Services>,
input: &'a CommandInput,
) -> Result<(AdminCommand, Vec<String>, Vec<&'a str>), CommandOutput> {
let lines = input.command.lines().filter(|line| !line.trim().is_empty());
let command_line = lines.clone().next().expect("command missing first line");
let body = lines.skip(1).collect();
match parse_command(command_line) {
Ok((command, args)) => Ok((command, args, body)),
Err(error) => {
| Ok((command, args)) => Ok((command, args, body)),
| Err(error) => {
let message = error
.to_string()
.replace("server.name", services.globals.server_name().as_str());
Err(reply(
RoomMessageEventContent::notice_markdown(message),
input.reply_id.as_deref(),
))
Err(reply(RoomMessageEventContent::notice_plain(message), input.reply_id.as_deref()))
},
}
}
@@ -258,11 +276,12 @@ fn parse_line(command_line: &str) -> Vec<String> {
argv
}
fn reply(mut content: RoomMessageEventContent, reply_id: Option<&EventId>) -> RoomMessageEventContent {
fn reply(
mut content: RoomMessageEventContent,
reply_id: Option<&EventId>,
) -> RoomMessageEventContent {
content.relates_to = reply_id.map(|event_id| Reply {
in_reply_to: InReplyTo {
event_id: event_id.to_owned(),
},
in_reply_to: InReplyTo { event_id: event_id.to_owned() },
});
content
+45 -43
View File
@@ -1,12 +1,11 @@
use clap::Subcommand;
use conduit::Result;
use ruma::{
events::{room::message::RoomMessageEventContent, RoomAccountDataEventType},
RoomId, UserId,
};
use conduwuit::Result;
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, RoomId, UserId};
use crate::Command;
use crate::{admin_command, admin_command_dispatch};
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
/// All the getters and iterators from src/database/key_value/account_data.rs
pub(crate) enum AccountDataCommand {
@@ -21,50 +20,53 @@ pub(crate) enum AccountDataCommand {
},
/// - Searches the account data for a specific kind.
Get {
AccountDataGet {
/// Full user ID
user_id: Box<UserId>,
/// Account data event type
kind: RoomAccountDataEventType,
kind: String,
/// Optional room ID of the account data
room_id: Option<Box<RoomId>>,
},
}
/// All the getters and iterators from src/database/key_value/account_data.rs
pub(super) async fn process(subcommand: AccountDataCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
let services = context.services;
#[admin_command]
async fn changes_since(
&self,
user_id: Box<UserId>,
since: u64,
room_id: Option<Box<RoomId>>,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let results: Vec<_> = self
.services
.account_data
.changes_since(room_id.as_deref(), &user_id, since, None)
.collect()
.await;
let query_time = timer.elapsed();
match subcommand {
AccountDataCommand::ChangesSince {
user_id,
since,
room_id,
} => {
let timer = tokio::time::Instant::now();
let results = services
.account_data
.changes_since(room_id.as_deref(), &user_id, since)?;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
AccountDataCommand::Get {
user_id,
kind,
room_id,
} => {
let timer = tokio::time::Instant::now();
let results = services
.account_data
.get(room_id.as_deref(), &user_id, kind)?;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
}
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
}
#[admin_command]
async fn account_data_get(
&self,
user_id: Box<UserId>,
kind: String,
room_id: Option<Box<RoomId>>,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let results = self
.services
.account_data
.get_raw(room_id.as_deref(), &user_id, &kind)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
}
+10 -18
View File
@@ -1,6 +1,5 @@
use clap::Subcommand;
use conduit::Result;
use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use crate::Command;
@@ -18,32 +17,25 @@ pub(crate) enum AppserviceCommand {
}
/// All the getters and iterators from src/database/key_value/appservice.rs
pub(super) async fn process(subcommand: AppserviceCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(subcommand: AppserviceCommand, context: &Command<'_>) -> Result {
let services = context.services;
match subcommand {
AppserviceCommand::GetRegistration {
appservice_id,
} => {
| AppserviceCommand::GetRegistration { appservice_id } => {
let timer = tokio::time::Instant::now();
let results = services
.appservice
.db
.get_registration(appservice_id.as_ref());
let results = services.appservice.get_registration(&appservice_id).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
AppserviceCommand::All => {
| AppserviceCommand::All => {
let timer = tokio::time::Instant::now();
let results = services.appservice.all();
let results = services.appservice.all().await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
}
.await
}
+15 -35
View File
@@ -1,6 +1,6 @@
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, ServerName};
use conduwuit::Result;
use ruma::ServerName;
use crate::Command;
@@ -13,8 +13,6 @@ pub(crate) enum GlobalsCommand {
LastCheckForUpdatesId,
LoadKeypair,
/// - This returns an empty `Ok(BTreeMap<..>)` when there are no keys found
/// for the server.
SigningKeysFor {
@@ -23,56 +21,38 @@ pub(crate) enum GlobalsCommand {
}
/// All the getters and iterators from src/database/key_value/globals.rs
pub(super) async fn process(subcommand: GlobalsCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(subcommand: GlobalsCommand, context: &Command<'_>) -> Result {
let services = context.services;
match subcommand {
GlobalsCommand::DatabaseVersion => {
| GlobalsCommand::DatabaseVersion => {
let timer = tokio::time::Instant::now();
let results = services.globals.db.database_version();
let results = services.globals.db.database_version().await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
GlobalsCommand::CurrentCount => {
| GlobalsCommand::CurrentCount => {
let timer = tokio::time::Instant::now();
let results = services.globals.db.current_count();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
GlobalsCommand::LastCheckForUpdatesId => {
| GlobalsCommand::LastCheckForUpdatesId => {
let timer = tokio::time::Instant::now();
let results = services.updates.last_check_for_updates_id();
let results = services.updates.last_check_for_updates_id().await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
GlobalsCommand::LoadKeypair => {
| GlobalsCommand::SigningKeysFor { origin } => {
let timer = tokio::time::Instant::now();
let results = services.globals.db.load_keypair();
let results = services.server_keys.verify_keys_for(&origin).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
GlobalsCommand::SigningKeysFor {
origin,
} => {
let timer = tokio::time::Instant::now();
let results = services.globals.db.verify_keys_for(&origin);
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
}
.await
}
+25 -3
View File
@@ -2,19 +2,25 @@ mod account_data;
mod appservice;
mod globals;
mod presence;
mod pusher;
mod raw;
mod resolver;
mod room_alias;
mod room_state_cache;
mod room_timeline;
mod sending;
mod short;
mod users;
use clap::Subcommand;
use conduit::Result;
use conduwuit::Result;
use self::{
account_data::AccountDataCommand, appservice::AppserviceCommand, globals::GlobalsCommand,
presence::PresenceCommand, resolver::ResolverCommand, room_alias::RoomAliasCommand,
room_state_cache::RoomStateCacheCommand, sending::SendingCommand, users::UsersCommand,
presence::PresenceCommand, pusher::PusherCommand, raw::RawCommand, resolver::ResolverCommand,
room_alias::RoomAliasCommand, room_state_cache::RoomStateCacheCommand,
room_timeline::RoomTimelineCommand, sending::SendingCommand, short::ShortCommand,
users::UsersCommand,
};
use crate::admin_command_dispatch;
@@ -42,6 +48,10 @@ pub(super) enum QueryCommand {
#[command(subcommand)]
RoomStateCache(RoomStateCacheCommand),
/// - rooms/timeline iterators and getters
#[command(subcommand)]
RoomTimeline(RoomTimelineCommand),
/// - globals.rs iterators and getters
#[command(subcommand)]
Globals(GlobalsCommand),
@@ -57,4 +67,16 @@ pub(super) enum QueryCommand {
/// - resolver service
#[command(subcommand)]
Resolver(ResolverCommand),
/// - pusher service
#[command(subcommand)]
Pusher(PusherCommand),
/// - short service
#[command(subcommand)]
Short(ShortCommand),
/// - raw service
#[command(subcommand)]
Raw(RawCommand),
}
+16 -18
View File
@@ -1,6 +1,7 @@
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, UserId};
use conduwuit::Result;
use futures::StreamExt;
use ruma::UserId;
use crate::Command;
@@ -22,32 +23,29 @@ pub(crate) enum PresenceCommand {
}
/// All the getters and iterators in key_value/presence.rs
pub(super) async fn process(subcommand: PresenceCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(subcommand: PresenceCommand, context: &Command<'_>) -> Result {
let services = context.services;
match subcommand {
PresenceCommand::GetPresence {
user_id,
} => {
| PresenceCommand::GetPresence { user_id } => {
let timer = tokio::time::Instant::now();
let results = services.presence.db.get_presence(&user_id)?;
let results = services.presence.get_presence(&user_id).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
PresenceCommand::PresenceSince {
since,
} => {
| PresenceCommand::PresenceSince { since } => {
let timer = tokio::time::Instant::now();
let results = services.presence.db.presence_since(since);
let presence_since: Vec<(_, _, _)> = results.collect();
let results: Vec<(_, _, _)> = services
.presence
.presence_since(since)
.map(|(user_id, count, bytes)| (user_id.to_owned(), count, bytes.to_vec()))
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{presence_since:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
}
.await
}
+29
View File
@@ -0,0 +1,29 @@
use clap::Subcommand;
use conduwuit::Result;
use ruma::UserId;
use crate::Command;
#[derive(Debug, Subcommand)]
pub(crate) enum PusherCommand {
/// - Returns all the pushers for the user.
GetPushers {
/// Full user ID
user_id: Box<UserId>,
},
}
pub(super) async fn process(subcommand: PusherCommand, context: &Command<'_>) -> Result {
let services = context.services;
match subcommand {
| PusherCommand::GetPushers { user_id } => {
let timer = tokio::time::Instant::now();
let results = services.pusher.get_pushers(&user_id).await;
let query_time = timer.elapsed();
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
}
.await
}
+576
View File
@@ -0,0 +1,576 @@
use std::{borrow::Cow, collections::BTreeMap, ops::Deref};
use clap::Subcommand;
use conduwuit::{
apply, at, is_zero,
utils::{
stream::{ReadyExt, TryIgnore, TryParallelExt},
string::EMPTY,
IterStream,
},
Err, Result,
};
use futures::{FutureExt, StreamExt, TryStreamExt};
use ruma::events::room::message::RoomMessageEventContent;
use tokio::time::Instant;
use crate::{admin_command, admin_command_dispatch};
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
#[allow(clippy::enum_variant_names)]
/// Query tables from database
pub(crate) enum RawCommand {
/// - List database maps
RawMaps,
/// - Raw database query
RawGet {
/// Map name
map: String,
/// Key
key: String,
},
/// - Raw database delete (for string keys)
RawDel {
/// Map name
map: String,
/// Key
key: String,
},
/// - Raw database keys iteration
RawKeys {
/// Map name
map: String,
/// Key prefix
prefix: Option<String>,
},
/// - Raw database key size breakdown
RawKeysSizes {
/// Map name
map: Option<String>,
/// Key prefix
prefix: Option<String>,
},
/// - Raw database keys total bytes
RawKeysTotal {
/// Map name
map: Option<String>,
/// Key prefix
prefix: Option<String>,
},
/// - Raw database values size breakdown
RawValsSizes {
/// Map name
map: Option<String>,
/// Key prefix
prefix: Option<String>,
},
/// - Raw database values total bytes
RawValsTotal {
/// Map name
map: Option<String>,
/// Key prefix
prefix: Option<String>,
},
/// - Raw database items iteration
RawIter {
/// Map name
map: String,
/// Key prefix
prefix: Option<String>,
},
/// - Raw database keys iteration
RawKeysFrom {
/// Map name
map: String,
/// Lower-bound
start: String,
/// Limit
#[arg(short, long)]
limit: Option<usize>,
},
/// - Raw database items iteration
RawIterFrom {
/// Map name
map: String,
/// Lower-bound
start: String,
/// Limit
#[arg(short, long)]
limit: Option<usize>,
},
/// - Raw database record count
RawCount {
/// Map name
map: Option<String>,
/// Key prefix
prefix: Option<String>,
},
/// - Compact database
Compact {
#[arg(short, long, alias("column"))]
map: Option<Vec<String>>,
#[arg(long)]
start: Option<String>,
#[arg(long)]
stop: Option<String>,
#[arg(long)]
from: Option<usize>,
#[arg(long)]
into: Option<usize>,
/// There is one compaction job per column; then this controls how many
/// columns are compacted in parallel. If zero, one compaction job is
/// still run at a time here, but in exclusive-mode blocking any other
/// automatic compaction jobs until complete.
#[arg(long)]
parallelism: Option<usize>,
#[arg(long, default_value("false"))]
exhaustive: bool,
},
}
#[admin_command]
pub(super) async fn compact(
&self,
map: Option<Vec<String>>,
start: Option<String>,
stop: Option<String>,
from: Option<usize>,
into: Option<usize>,
parallelism: Option<usize>,
exhaustive: bool,
) -> Result<RoomMessageEventContent> {
use conduwuit_database::compact::Options;
let default_all_maps = map
.is_none()
.then(|| {
self.services
.db
.keys()
.map(Deref::deref)
.map(ToOwned::to_owned)
})
.into_iter()
.flatten();
let maps: Vec<_> = map
.unwrap_or_default()
.into_iter()
.chain(default_all_maps)
.map(|map| self.services.db.get(&map))
.filter_map(Result::ok)
.cloned()
.collect();
if maps.is_empty() {
return Err!("--map argument invalid. not found in database");
}
let range = (
start.as_ref().map(String::as_bytes).map(Into::into),
stop.as_ref().map(String::as_bytes).map(Into::into),
);
let options = Options {
range,
level: (from, into),
exclusive: parallelism.is_some_and(is_zero!()),
exhaustive,
};
let runtime = self.services.server.runtime().clone();
let parallelism = parallelism.unwrap_or(1);
let results = maps
.into_iter()
.try_stream()
.paralleln_and_then(runtime, parallelism, move |map| {
map.compact_blocking(options.clone())?;
Ok(map.name().to_owned())
})
.collect::<Vec<_>>();
let timer = Instant::now();
let results = results.await;
let query_time = timer.elapsed();
self.write_str(&format!("Jobs completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"))
.await?;
Ok(RoomMessageEventContent::text_plain(""))
}
#[admin_command]
pub(super) async fn raw_count(
&self,
map: Option<String>,
prefix: Option<String>,
) -> Result<RoomMessageEventContent> {
let prefix = prefix.as_deref().unwrap_or(EMPTY);
let default_all_maps = map
.is_none()
.then(|| self.services.db.keys().map(Deref::deref))
.into_iter()
.flatten();
let maps: Vec<_> = map
.iter()
.map(String::as_str)
.chain(default_all_maps)
.map(|map| self.services.db.get(map))
.filter_map(Result::ok)
.cloned()
.collect();
let timer = Instant::now();
let count = maps
.iter()
.stream()
.then(|map| map.raw_count_prefix(&prefix))
.ready_fold(0_usize, usize::saturating_add)
.await;
let query_time = timer.elapsed();
self.write_str(&format!("Query completed in {query_time:?}:\n\n```rs\n{count:#?}\n```"))
.await?;
Ok(RoomMessageEventContent::text_plain(""))
}
#[admin_command]
pub(super) async fn raw_keys(
&self,
map: String,
prefix: Option<String>,
) -> Result<RoomMessageEventContent> {
writeln!(self, "```").boxed().await?;
let map = self.services.db.get(map.as_str())?;
let timer = Instant::now();
prefix
.as_deref()
.map_or_else(|| map.raw_keys().boxed(), |prefix| map.raw_keys_prefix(prefix).boxed())
.map_ok(String::from_utf8_lossy)
.try_for_each(|str| writeln!(self, "{str:?}"))
.boxed()
.await?;
let query_time = timer.elapsed();
let out = format!("\n```\n\nQuery completed in {query_time:?}");
self.write_str(out.as_str()).await?;
Ok(RoomMessageEventContent::text_plain(""))
}
#[admin_command]
pub(super) async fn raw_keys_sizes(
&self,
map: Option<String>,
prefix: Option<String>,
) -> Result<RoomMessageEventContent> {
let prefix = prefix.as_deref().unwrap_or(EMPTY);
let default_all_maps = map
.is_none()
.then(|| self.services.db.keys().map(Deref::deref))
.into_iter()
.flatten();
let maps: Vec<_> = map
.iter()
.map(String::as_str)
.chain(default_all_maps)
.map(|map| self.services.db.get(map))
.filter_map(Result::ok)
.cloned()
.collect();
let timer = Instant::now();
let result = maps
.iter()
.stream()
.map(|map| map.raw_keys_prefix(&prefix))
.flatten()
.ignore_err()
.map(<[u8]>::len)
.ready_fold_default(|mut map: BTreeMap<_, usize>, len| {
let entry = map.entry(len).or_default();
*entry = entry.saturating_add(1);
map
})
.await;
let query_time = timer.elapsed();
let result = format!("```\n{result:#?}\n```\n\nQuery completed in {query_time:?}");
self.write_str(result.as_str()).await?;
Ok(RoomMessageEventContent::text_plain(""))
}
#[admin_command]
pub(super) async fn raw_keys_total(
&self,
map: Option<String>,
prefix: Option<String>,
) -> Result<RoomMessageEventContent> {
let prefix = prefix.as_deref().unwrap_or(EMPTY);
let default_all_maps = map
.is_none()
.then(|| self.services.db.keys().map(Deref::deref))
.into_iter()
.flatten();
let maps: Vec<_> = map
.iter()
.map(String::as_str)
.chain(default_all_maps)
.map(|map| self.services.db.get(map))
.filter_map(Result::ok)
.cloned()
.collect();
let timer = Instant::now();
let result = maps
.iter()
.stream()
.map(|map| map.raw_keys_prefix(&prefix))
.flatten()
.ignore_err()
.map(<[u8]>::len)
.ready_fold_default(|acc: usize, len| acc.saturating_add(len))
.await;
let query_time = timer.elapsed();
self.write_str(&format!("```\n{result:#?}\n\n```\n\nQuery completed in {query_time:?}"))
.await?;
Ok(RoomMessageEventContent::text_plain(""))
}
#[admin_command]
pub(super) async fn raw_vals_sizes(
&self,
map: Option<String>,
prefix: Option<String>,
) -> Result<RoomMessageEventContent> {
let prefix = prefix.as_deref().unwrap_or(EMPTY);
let default_all_maps = map
.is_none()
.then(|| self.services.db.keys().map(Deref::deref))
.into_iter()
.flatten();
let maps: Vec<_> = map
.iter()
.map(String::as_str)
.chain(default_all_maps)
.map(|map| self.services.db.get(map))
.filter_map(Result::ok)
.cloned()
.collect();
let timer = Instant::now();
let result = maps
.iter()
.stream()
.map(|map| map.raw_stream_prefix(&prefix))
.flatten()
.ignore_err()
.map(at!(1))
.map(<[u8]>::len)
.ready_fold_default(|mut map: BTreeMap<_, usize>, len| {
let entry = map.entry(len).or_default();
*entry = entry.saturating_add(1);
map
})
.await;
let query_time = timer.elapsed();
let result = format!("```\n{result:#?}\n```\n\nQuery completed in {query_time:?}");
self.write_str(result.as_str()).await?;
Ok(RoomMessageEventContent::text_plain(""))
}
#[admin_command]
pub(super) async fn raw_vals_total(
&self,
map: Option<String>,
prefix: Option<String>,
) -> Result<RoomMessageEventContent> {
let prefix = prefix.as_deref().unwrap_or(EMPTY);
let default_all_maps = map
.is_none()
.then(|| self.services.db.keys().map(Deref::deref))
.into_iter()
.flatten();
let maps: Vec<_> = map
.iter()
.map(String::as_str)
.chain(default_all_maps)
.map(|map| self.services.db.get(map))
.filter_map(Result::ok)
.cloned()
.collect();
let timer = Instant::now();
let result = maps
.iter()
.stream()
.map(|map| map.raw_stream_prefix(&prefix))
.flatten()
.ignore_err()
.map(at!(1))
.map(<[u8]>::len)
.ready_fold_default(|acc: usize, len| acc.saturating_add(len))
.await;
let query_time = timer.elapsed();
self.write_str(&format!("```\n{result:#?}\n\n```\n\nQuery completed in {query_time:?}"))
.await?;
Ok(RoomMessageEventContent::text_plain(""))
}
#[admin_command]
pub(super) async fn raw_iter(
&self,
map: String,
prefix: Option<String>,
) -> Result<RoomMessageEventContent> {
writeln!(self, "```").await?;
let map = self.services.db.get(&map)?;
let timer = Instant::now();
prefix
.as_deref()
.map_or_else(|| map.raw_stream().boxed(), |prefix| map.raw_stream_prefix(prefix).boxed())
.map_ok(apply!(2, String::from_utf8_lossy))
.map_ok(apply!(2, Cow::into_owned))
.try_for_each(|keyval| writeln!(self, "{keyval:?}"))
.boxed()
.await?;
let query_time = timer.elapsed();
self.write_str(&format!("\n```\n\nQuery completed in {query_time:?}"))
.await?;
Ok(RoomMessageEventContent::text_plain(""))
}
#[admin_command]
pub(super) async fn raw_keys_from(
&self,
map: String,
start: String,
limit: Option<usize>,
) -> Result<RoomMessageEventContent> {
writeln!(self, "```").await?;
let map = self.services.db.get(&map)?;
let timer = Instant::now();
map.raw_keys_from(&start)
.map_ok(String::from_utf8_lossy)
.take(limit.unwrap_or(usize::MAX))
.try_for_each(|str| writeln!(self, "{str:?}"))
.boxed()
.await?;
let query_time = timer.elapsed();
self.write_str(&format!("\n```\n\nQuery completed in {query_time:?}"))
.await?;
Ok(RoomMessageEventContent::text_plain(""))
}
#[admin_command]
pub(super) async fn raw_iter_from(
&self,
map: String,
start: String,
limit: Option<usize>,
) -> Result<RoomMessageEventContent> {
let map = self.services.db.get(&map)?;
let timer = Instant::now();
let result = map
.raw_stream_from(&start)
.map_ok(apply!(2, String::from_utf8_lossy))
.map_ok(apply!(2, Cow::into_owned))
.take(limit.unwrap_or(usize::MAX))
.try_collect::<Vec<(String, String)>>()
.await?;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
pub(super) async fn raw_del(&self, map: String, key: String) -> Result<RoomMessageEventContent> {
let map = self.services.db.get(&map)?;
let timer = Instant::now();
map.remove(&key);
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Operation completed in {query_time:?}"
)))
}
#[admin_command]
pub(super) async fn raw_get(&self, map: String, key: String) -> Result<RoomMessageEventContent> {
let map = self.services.db.get(&map)?;
let timer = Instant::now();
let handle = map.get(&key).await?;
let query_time = timer.elapsed();
let result = String::from_utf8_lossy(&handle);
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:?}\n```"
)))
}
#[admin_command]
pub(super) async fn raw_maps(&self) -> Result<RoomMessageEventContent> {
let list: Vec<_> = self.services.db.iter().map(at!(0)).copied().collect();
Ok(RoomMessageEventContent::notice_markdown(format!("{list:#?}")))
}
+38 -58
View File
@@ -1,7 +1,6 @@
use std::fmt::Write;
use clap::Subcommand;
use conduit::{utils::time, Result};
use conduwuit::{utils::time, Result};
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, OwnedServerName};
use crate::{admin_command, admin_command_dispatch};
@@ -22,73 +21,54 @@ pub(crate) enum ResolverCommand {
}
#[admin_command]
async fn destinations_cache(&self, server_name: Option<OwnedServerName>) -> Result<RoomMessageEventContent> {
async fn destinations_cache(
&self,
server_name: Option<OwnedServerName>,
) -> Result<RoomMessageEventContent> {
use service::resolver::cache::CachedDest;
let mut out = String::new();
writeln!(out, "| Server Name | Destination | Hostname | Expires |")?;
writeln!(out, "| ----------- | ----------- | -------- | ------- |")?;
let row = |(
name,
&CachedDest {
ref dest,
ref host,
expire,
},
)| {
writeln!(self, "| Server Name | Destination | Hostname | Expires |").await?;
writeln!(self, "| ----------- | ----------- | -------- | ------- |").await?;
let mut destinations = self.services.resolver.cache.destinations().boxed();
while let Some((name, CachedDest { dest, host, expire })) = destinations.next().await {
if let Some(server_name) = server_name.as_ref() {
if name != server_name {
continue;
}
}
let expire = time::format(expire, "%+");
writeln!(out, "| {name} | {dest} | {host} | {expire} |").expect("wrote line");
};
let map = self
.services
.resolver
.cache
.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);
self.write_str(&format!("| {name} | {dest} | {host} | {expire} |\n"))
.await?;
}
Ok(RoomMessageEventContent::notice_markdown(out))
Ok(RoomMessageEventContent::notice_plain(""))
}
#[admin_command]
async fn overrides_cache(&self, server_name: Option<String>) -> Result<RoomMessageEventContent> {
use service::resolver::cache::CachedOverride;
let mut out = String::new();
writeln!(out, "| Server Name | IP | Port | Expires |")?;
writeln!(out, "| ----------- | --- | ----:| ------- |")?;
let row = |(
name,
&CachedOverride {
ref ips,
port,
expire,
},
)| {
writeln!(self, "| Server Name | IP | Port | Expires | Overriding |").await?;
writeln!(self, "| ----------- | --- | ----:| ------- | ---------- |").await?;
let mut overrides = self.services.resolver.cache.overrides().boxed();
while let Some((name, CachedOverride { ips, port, expire, overriding })) =
overrides.next().await
{
if let Some(server_name) = server_name.as_ref() {
if name != server_name {
continue;
}
}
let expire = time::format(expire, "%+");
writeln!(out, "| {name} | {ips:?} | {port} | {expire} |").expect("wrote line");
};
let map = self
.services
.resolver
.cache
.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);
self.write_str(&format!("| {name} | {ips:?} | {port} | {expire} | {overriding:?} |\n"))
.await?;
}
Ok(RoomMessageEventContent::notice_markdown(out))
Ok(RoomMessageEventContent::notice_plain(""))
}
+26 -24
View File
@@ -1,6 +1,7 @@
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, RoomAliasId, RoomId};
use conduwuit::Result;
use futures::StreamExt;
use ruma::{RoomAliasId, RoomId};
use crate::Command;
@@ -23,42 +24,43 @@ pub(crate) enum RoomAliasCommand {
}
/// All the getters and iterators in src/database/key_value/rooms/alias.rs
pub(super) async fn process(subcommand: RoomAliasCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(subcommand: RoomAliasCommand, context: &Command<'_>) -> Result {
let services = context.services;
match subcommand {
RoomAliasCommand::ResolveLocalAlias {
alias,
} => {
| RoomAliasCommand::ResolveLocalAlias { alias } => {
let timer = tokio::time::Instant::now();
let results = services.rooms.alias.resolve_local_alias(&alias);
let results = services.rooms.alias.resolve_local_alias(&alias).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
RoomAliasCommand::LocalAliasesForRoom {
room_id,
} => {
| RoomAliasCommand::LocalAliasesForRoom { room_id } => {
let timer = tokio::time::Instant::now();
let results = services.rooms.alias.local_aliases_for_room(&room_id);
let aliases: Vec<_> = results.collect();
let aliases: Vec<_> = services
.rooms
.alias
.local_aliases_for_room(&room_id)
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```")
},
RoomAliasCommand::AllLocalAliases => {
| RoomAliasCommand::AllLocalAliases => {
let timer = tokio::time::Instant::now();
let results = services.rooms.alias.all_local_aliases();
let aliases: Vec<_> = results.collect();
let aliases = services
.rooms
.alias
.all_local_aliases()
.map(|(room_id, alias)| (room_id.to_owned(), alias.to_owned()))
.collect::<Vec<_>>()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```"
)))
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```")
},
}
.await
}
+115 -92
View File
@@ -1,5 +1,6 @@
use clap::Subcommand;
use conduit::Result;
use conduwuit::{Error, Result};
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, RoomId, ServerName, UserId};
use crate::Command;
@@ -75,213 +76,235 @@ pub(crate) enum RoomStateCacheCommand {
},
}
pub(super) async fn process(
subcommand: RoomStateCacheCommand, context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
pub(super) async fn process(subcommand: RoomStateCacheCommand, context: &Command<'_>) -> Result {
let services = context.services;
match subcommand {
RoomStateCacheCommand::ServerInRoom {
server,
room_id,
} => {
let c = match subcommand {
| RoomStateCacheCommand::ServerInRoom { server, room_id } => {
let timer = tokio::time::Instant::now();
let result = services.rooms.state_cache.server_in_room(&server, &room_id);
let result = services
.rooms
.state_cache
.server_in_room(&server, &room_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
},
RoomStateCacheCommand::RoomServers {
room_id,
} => {
| RoomStateCacheCommand::RoomServers { room_id } => {
let timer = tokio::time::Instant::now();
let results: Result<Vec<_>> = services.rooms.state_cache.room_servers(&room_id).collect();
let results: Vec<_> = services
.rooms
.state_cache
.room_servers(&room_id)
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::ServerRooms {
server,
} => {
| RoomStateCacheCommand::ServerRooms { server } => {
let timer = tokio::time::Instant::now();
let results: Result<Vec<_>> = services.rooms.state_cache.server_rooms(&server).collect();
let results: Vec<_> = services
.rooms
.state_cache
.server_rooms(&server)
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomMembers {
room_id,
} => {
| RoomStateCacheCommand::RoomMembers { room_id } => {
let timer = tokio::time::Instant::now();
let results: Result<Vec<_>> = services.rooms.state_cache.room_members(&room_id).collect();
let results: Vec<_> = services
.rooms
.state_cache
.room_members(&room_id)
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::LocalUsersInRoom {
room_id,
} => {
| RoomStateCacheCommand::LocalUsersInRoom { room_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
.state_cache
.local_users_in_room(&room_id)
.collect();
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::ActiveLocalUsersInRoom {
room_id,
} => {
| RoomStateCacheCommand::ActiveLocalUsersInRoom { room_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
.state_cache
.active_local_users_in_room(&room_id)
.collect();
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomJoinedCount {
room_id,
} => {
| RoomStateCacheCommand::RoomJoinedCount { room_id } => {
let timer = tokio::time::Instant::now();
let results = services.rooms.state_cache.room_joined_count(&room_id);
let results = services.rooms.state_cache.room_joined_count(&room_id).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomInvitedCount {
room_id,
} => {
| RoomStateCacheCommand::RoomInvitedCount { room_id } => {
let timer = tokio::time::Instant::now();
let results = services.rooms.state_cache.room_invited_count(&room_id);
let results = services
.rooms
.state_cache
.room_invited_count(&room_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomUserOnceJoined {
room_id,
} => {
| RoomStateCacheCommand::RoomUserOnceJoined { room_id } => {
let timer = tokio::time::Instant::now();
let results: Result<Vec<_>> = services
let results: Vec<_> = services
.rooms
.state_cache
.room_useroncejoined(&room_id)
.collect();
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomMembersInvited {
room_id,
} => {
| RoomStateCacheCommand::RoomMembersInvited { room_id } => {
let timer = tokio::time::Instant::now();
let results: Result<Vec<_>> = services
let results: Vec<_> = services
.rooms
.state_cache
.room_members_invited(&room_id)
.collect();
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::GetInviteCount {
room_id,
user_id,
} => {
| RoomStateCacheCommand::GetInviteCount { room_id, user_id } => {
let timer = tokio::time::Instant::now();
let results = services
.rooms
.state_cache
.get_invite_count(&room_id, &user_id);
.get_invite_count(&room_id, &user_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::GetLeftCount {
room_id,
user_id,
} => {
| RoomStateCacheCommand::GetLeftCount { room_id, user_id } => {
let timer = tokio::time::Instant::now();
let results = services
.rooms
.state_cache
.get_left_count(&room_id, &user_id);
.get_left_count(&room_id, &user_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomsJoined {
user_id,
} => {
| RoomStateCacheCommand::RoomsJoined { user_id } => {
let timer = tokio::time::Instant::now();
let results: Result<Vec<_>> = services.rooms.state_cache.rooms_joined(&user_id).collect();
let results: Vec<_> = services
.rooms
.state_cache
.rooms_joined(&user_id)
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomsInvited {
user_id,
} => {
| RoomStateCacheCommand::RoomsInvited { user_id } => {
let timer = tokio::time::Instant::now();
let results: Result<Vec<_>> = services.rooms.state_cache.rooms_invited(&user_id).collect();
let results: Vec<_> = services
.rooms
.state_cache
.rooms_invited(&user_id)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomsLeft {
user_id,
} => {
| RoomStateCacheCommand::RoomsLeft { user_id } => {
let timer = tokio::time::Instant::now();
let results: Result<Vec<_>> = services.rooms.state_cache.rooms_left(&user_id).collect();
let results: Vec<_> = services
.rooms
.state_cache
.rooms_left(&user_id)
.collect()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::InviteState {
user_id,
room_id,
} => {
| RoomStateCacheCommand::InviteState { user_id, room_id } => {
let timer = tokio::time::Instant::now();
let results = services.rooms.state_cache.invite_state(&user_id, &room_id);
let results = services
.rooms
.state_cache
.invite_state(&user_id, &room_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
}
}?;
context.write_str(c.body()).await?;
Ok(())
}
+61
View File
@@ -0,0 +1,61 @@
use clap::Subcommand;
use conduwuit::{utils::stream::TryTools, PduCount, Result};
use futures::TryStreamExt;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomOrAliasId};
use crate::{admin_command, admin_command_dispatch};
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
/// Query tables from database
pub(crate) enum RoomTimelineCommand {
Pdus {
room_id: OwnedRoomOrAliasId,
from: Option<String>,
#[arg(short, long)]
limit: Option<usize>,
},
Last {
room_id: OwnedRoomOrAliasId,
},
}
#[admin_command]
pub(super) async fn last(&self, room_id: OwnedRoomOrAliasId) -> Result<RoomMessageEventContent> {
let room_id = self.services.rooms.alias.resolve(&room_id).await?;
let result = self
.services
.rooms
.timeline
.last_timeline_count(None, &room_id)
.await?;
Ok(RoomMessageEventContent::notice_markdown(format!("{result:#?}")))
}
#[admin_command]
pub(super) async fn pdus(
&self,
room_id: OwnedRoomOrAliasId,
from: Option<String>,
limit: Option<usize>,
) -> Result<RoomMessageEventContent> {
let room_id = self.services.rooms.alias.resolve(&room_id).await?;
let from: Option<PduCount> = from.as_deref().map(str::parse).transpose()?;
let result: Vec<_> = self
.services
.rooms
.timeline
.pdus_rev(None, &room_id, from)
.try_take(limit.unwrap_or(3))
.try_collect()
.await?;
Ok(RoomMessageEventContent::notice_markdown(format!("{result:#?}")))
}
+63 -46
View File
@@ -1,5 +1,6 @@
use clap::Subcommand;
use conduit::Result;
use conduwuit::Result;
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, ServerName, UserId};
use service::sending::Destination;
@@ -61,39 +62,53 @@ pub(crate) enum SendingCommand {
}
/// All the getters and iterators in key_value/sending.rs
pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -> Result {
let c = reprocess(subcommand, context).await?;
context.write_str(c.body()).await?;
Ok(())
}
/// All the getters and iterators in key_value/sending.rs
pub(super) async fn reprocess(
subcommand: SendingCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand {
SendingCommand::ActiveRequests => {
| SendingCommand::ActiveRequests => {
let timer = tokio::time::Instant::now();
let results = services.sending.db.active_requests();
let active_requests: Result<Vec<(_, _, _)>> = results.collect();
let active_requests = results.collect::<Vec<_>>().await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{active_requests:#?}\n```"
)))
},
SendingCommand::QueuedRequests {
| SendingCommand::QueuedRequests {
appservice_id,
server_name,
user_id,
push_key,
} => {
if appservice_id.is_none() && server_name.is_none() && user_id.is_none() && push_key.is_none() {
if appservice_id.is_none()
&& server_name.is_none()
&& user_id.is_none()
&& push_key.is_none()
{
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. See \
--help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
let timer = tokio::time::Instant::now();
let results = match (appservice_id, server_name, user_id, push_key) {
(Some(appservice_id), None, None, None) => {
| (Some(appservice_id), None, None, None) => {
if appservice_id.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via \
arguments. See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
@@ -102,15 +117,15 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
.db
.queued_requests(&Destination::Appservice(appservice_id))
},
(None, Some(server_name), None, None) => services
| (None, Some(server_name), None, None) => services
.sending
.db
.queued_requests(&Destination::Normal(server_name.into())),
(None, None, Some(user_id), Some(push_key)) => {
.queued_requests(&Destination::Federation(server_name.into())),
| (None, None, Some(user_id), Some(push_key)) => {
if push_key.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via \
arguments. See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
@@ -119,47 +134,51 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
.db
.queued_requests(&Destination::Push(user_id.into(), push_key))
},
(Some(_), Some(_), Some(_), Some(_)) => {
| (Some(_), Some(_), Some(_), Some(_)) => {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. \
Not all of them See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. Not all of them See --help for more details.",
));
},
_ => {
| _ => {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. \
See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
},
};
let queued_requests = results.collect::<Result<Vec<(_, _)>>>();
let queued_requests = results.collect::<Vec<_>>().await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{queued_requests:#?}\n```"
)))
},
SendingCommand::ActiveRequestsFor {
| SendingCommand::ActiveRequestsFor {
appservice_id,
server_name,
user_id,
push_key,
} => {
if appservice_id.is_none() && server_name.is_none() && user_id.is_none() && push_key.is_none() {
if appservice_id.is_none()
&& server_name.is_none()
&& user_id.is_none()
&& push_key.is_none()
{
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. See \
--help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
let timer = tokio::time::Instant::now();
let results = match (appservice_id, server_name, user_id, push_key) {
(Some(appservice_id), None, None, None) => {
| (Some(appservice_id), None, None, None) => {
if appservice_id.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via \
arguments. See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
@@ -168,15 +187,15 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
.db
.active_requests_for(&Destination::Appservice(appservice_id))
},
(None, Some(server_name), None, None) => services
| (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)) => {
.active_requests_for(&Destination::Federation(server_name.into())),
| (None, None, Some(user_id), Some(push_key)) => {
if push_key.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via \
arguments. See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
@@ -185,32 +204,30 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
.db
.active_requests_for(&Destination::Push(user_id.into(), push_key))
},
(Some(_), Some(_), Some(_), Some(_)) => {
| (Some(_), Some(_), Some(_), Some(_)) => {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. \
Not all of them See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. Not all of them See --help for more details.",
));
},
_ => {
| _ => {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. \
See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
},
};
let active_requests = results.collect::<Result<Vec<(_, _)>>>();
let active_requests = results.collect::<Vec<_>>().await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{active_requests:#?}\n```"
)))
},
SendingCommand::GetLatestEduCount {
server_name,
} => {
| SendingCommand::GetLatestEduCount { server_name } => {
let timer = tokio::time::Instant::now();
let results = services.sending.db.get_latest_educount(&server_name);
let results = services.sending.db.get_latest_educount(&server_name).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
+45
View File
@@ -0,0 +1,45 @@
use clap::Subcommand;
use conduwuit::Result;
use ruma::{events::room::message::RoomMessageEventContent, OwnedEventId, OwnedRoomOrAliasId};
use crate::{admin_command, admin_command_dispatch};
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
/// Query tables from database
pub(crate) enum ShortCommand {
ShortEventId {
event_id: OwnedEventId,
},
ShortRoomId {
room_id: OwnedRoomOrAliasId,
},
}
#[admin_command]
pub(super) async fn short_event_id(
&self,
event_id: OwnedEventId,
) -> Result<RoomMessageEventContent> {
let shortid = self
.services
.rooms
.short
.get_shorteventid(&event_id)
.await?;
Ok(RoomMessageEventContent::notice_markdown(format!("{shortid:#?}")))
}
#[admin_command]
pub(super) async fn short_room_id(
&self,
room_id: OwnedRoomOrAliasId,
) -> Result<RoomMessageEventContent> {
let room_id = self.services.rooms.alias.resolve(&room_id).await?;
let shortid = self.services.rooms.short.get_shortroomid(&room_id).await?;
Ok(RoomMessageEventContent::notice_markdown(format!("{shortid:#?}")))
}
+414 -19
View File
@@ -1,29 +1,424 @@
use clap::Subcommand;
use conduit::Result;
use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use futures::stream::StreamExt;
use ruma::{
events::room::message::RoomMessageEventContent, OwnedDeviceId, OwnedRoomId, OwnedUserId,
};
use crate::Command;
use crate::{admin_command, admin_command_dispatch};
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
/// All the getters and iterators from src/database/key_value/users.rs
pub(crate) enum UsersCommand {
Iter,
CountUsers,
IterUsers,
IterUsers2,
PasswordHash {
user_id: OwnedUserId,
},
ListDevices {
user_id: OwnedUserId,
},
ListDevicesMetadata {
user_id: OwnedUserId,
},
GetDeviceMetadata {
user_id: OwnedUserId,
device_id: OwnedDeviceId,
},
GetDevicesVersion {
user_id: OwnedUserId,
},
CountOneTimeKeys {
user_id: OwnedUserId,
device_id: OwnedDeviceId,
},
GetDeviceKeys {
user_id: OwnedUserId,
device_id: OwnedDeviceId,
},
GetUserSigningKey {
user_id: OwnedUserId,
},
GetMasterKey {
user_id: OwnedUserId,
},
GetToDeviceEvents {
user_id: OwnedUserId,
device_id: OwnedDeviceId,
},
GetLatestBackup {
user_id: OwnedUserId,
},
GetLatestBackupVersion {
user_id: OwnedUserId,
},
GetBackupAlgorithm {
user_id: OwnedUserId,
version: String,
},
GetAllBackups {
user_id: OwnedUserId,
version: String,
},
GetRoomBackups {
user_id: OwnedUserId,
version: String,
room_id: OwnedRoomId,
},
GetBackupSession {
user_id: OwnedUserId,
version: String,
room_id: OwnedRoomId,
session_id: String,
},
GetSharedRooms {
user_a: OwnedUserId,
user_b: OwnedUserId,
},
}
/// All the getters and iterators in key_value/users.rs
pub(super) async fn process(subcommand: UsersCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
let services = context.services;
#[admin_command]
async fn get_shared_rooms(
&self,
user_a: OwnedUserId,
user_b: OwnedUserId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result: Vec<_> = self
.services
.rooms
.state_cache
.get_shared_rooms(&user_a, &user_b)
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed();
match subcommand {
UsersCommand::Iter => {
let timer = tokio::time::Instant::now();
let results = services.users.db.iter();
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```"
)))
},
}
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_backup_session(
&self,
user_id: OwnedUserId,
version: String,
room_id: OwnedRoomId,
session_id: String,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
.key_backups
.get_session(&user_id, &version, &room_id, &session_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_room_backups(
&self,
user_id: OwnedUserId,
version: String,
room_id: OwnedRoomId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
.key_backups
.get_room(&user_id, &version, &room_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_all_backups(
&self,
user_id: OwnedUserId,
version: String,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self.services.key_backups.get_all(&user_id, &version).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_backup_algorithm(
&self,
user_id: OwnedUserId,
version: String,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
.key_backups
.get_backup(&user_id, &version)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_latest_backup_version(
&self,
user_id: OwnedUserId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
.key_backups
.get_latest_backup_version(&user_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_latest_backup(&self, user_id: OwnedUserId) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self.services.key_backups.get_latest_backup(&user_id).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn iter_users(&self) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result: Vec<OwnedUserId> = self.services.users.stream().map(Into::into).collect().await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn iter_users2(&self) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result: Vec<_> = self.services.users.stream().collect().await;
let result: Vec<_> = result
.into_iter()
.map(ruma::UserId::as_bytes)
.map(String::from_utf8_lossy)
.collect();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:?}\n```"
)))
}
#[admin_command]
async fn count_users(&self) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self.services.users.count().await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn password_hash(&self, user_id: OwnedUserId) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self.services.users.password_hash(&user_id).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn list_devices(&self, user_id: OwnedUserId) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let devices = self
.services
.users
.all_device_ids(&user_id)
.map(ToOwned::to_owned)
.collect::<Vec<_>>()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{devices:#?}\n```"
)))
}
#[admin_command]
async fn list_devices_metadata(&self, user_id: OwnedUserId) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let devices = self
.services
.users
.all_devices_metadata(&user_id)
.collect::<Vec<_>>()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{devices:#?}\n```"
)))
}
#[admin_command]
async fn get_device_metadata(
&self,
user_id: OwnedUserId,
device_id: OwnedDeviceId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let device = self
.services
.users
.get_device_metadata(&user_id, &device_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{device:#?}\n```"
)))
}
#[admin_command]
async fn get_devices_version(&self, user_id: OwnedUserId) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let device = self.services.users.get_devicelist_version(&user_id).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{device:#?}\n```"
)))
}
#[admin_command]
async fn count_one_time_keys(
&self,
user_id: OwnedUserId,
device_id: OwnedDeviceId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
.users
.count_one_time_keys(&user_id, &device_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_device_keys(
&self,
user_id: OwnedUserId,
device_id: OwnedDeviceId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
.users
.get_device_keys(&user_id, &device_id)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_user_signing_key(&self, user_id: OwnedUserId) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self.services.users.get_user_signing_key(&user_id).await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_master_key(&self, user_id: OwnedUserId) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
.users
.get_master_key(None, &user_id, &|_| true)
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
#[admin_command]
async fn get_to_device_events(
&self,
user_id: OwnedUserId,
device_id: OwnedDeviceId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
.users
.get_to_device_events(&user_id, &device_id, None, None)
.collect::<Vec<_>>()
.await;
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
}
+136 -120
View File
@@ -1,8 +1,11 @@
use std::fmt::Write;
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, RoomAliasId, RoomId};
use conduwuit::Result;
use futures::StreamExt;
use ruma::{
events::room::message::RoomMessageEventContent, OwnedRoomAliasId, OwnedRoomId, RoomId,
};
use crate::{escape_html, Command};
@@ -41,148 +44,161 @@ pub(crate) enum RoomAliasCommand {
},
}
pub(super) async fn process(command: RoomAliasCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(command: RoomAliasCommand, context: &Command<'_>) -> Result {
let c = reprocess(command, context).await?;
context.write_str(c.body()).await?;
Ok(())
}
pub(super) async fn reprocess(
command: RoomAliasCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
let server_user = &services.globals.server_user;
match command {
RoomAliasCommand::Set {
ref room_alias_localpart,
..
}
| RoomAliasCommand::Remove {
ref room_alias_localpart,
}
| RoomAliasCommand::Which {
ref room_alias_localpart,
} => {
let room_alias_str = format!("#{}:{}", room_alias_localpart, services.globals.server_name());
let room_alias = match RoomAliasId::parse_box(room_alias_str) {
Ok(alias) => alias,
Err(err) => return Ok(RoomMessageEventContent::text_plain(format!("Failed to parse alias: {err}"))),
| RoomAliasCommand::Set { ref room_alias_localpart, .. }
| RoomAliasCommand::Remove { ref room_alias_localpart }
| RoomAliasCommand::Which { ref room_alias_localpart } => {
let room_alias_str =
format!("#{}:{}", room_alias_localpart, services.globals.server_name());
let room_alias = match OwnedRoomAliasId::parse(room_alias_str) {
| Ok(alias) => alias,
| Err(err) =>
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to parse alias: {err}"
))),
};
match command {
RoomAliasCommand::Set {
force,
room_id,
..
} => match (force, services.rooms.alias.resolve_local_alias(&room_alias)) {
(true, Ok(Some(id))) => match services
.rooms
.alias
.set_alias(&room_alias, &room_id, server_user)
{
Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
"Successfully overwrote alias (formerly {id})"
| RoomAliasCommand::Set { force, room_id, .. } => {
match (force, services.rooms.alias.resolve_local_alias(&room_alias).await) {
| (true, Ok(id)) => {
match services.rooms.alias.set_alias(
&room_alias,
&room_id,
server_user,
) {
| Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
"Successfully overwrote alias (formerly {id})"
))),
| Err(err) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to remove alias: {err}"
))),
}
},
| (false, Ok(id)) => Ok(RoomMessageEventContent::text_plain(format!(
"Refusing to overwrite in use alias for {id}, use -f or --force to \
overwrite"
))),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {err}"))),
},
(false, Ok(Some(id))) => Ok(RoomMessageEventContent::text_plain(format!(
"Refusing to overwrite in use alias for {id}, use -f or --force to overwrite"
))),
(_, Ok(None)) => match services
.rooms
.alias
.set_alias(&room_alias, &room_id, server_user)
{
Ok(()) => Ok(RoomMessageEventContent::text_plain("Successfully set alias")),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {err}"))),
},
(_, Err(err)) => Ok(RoomMessageEventContent::text_plain(format!("Unable to lookup alias: {err}"))),
| (_, Err(_)) => {
match services.rooms.alias.set_alias(
&room_alias,
&room_id,
server_user,
) {
| Ok(()) => Ok(RoomMessageEventContent::text_plain(
"Successfully set alias",
)),
| Err(err) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to remove alias: {err}"
))),
}
},
}
},
RoomAliasCommand::Remove {
..
} => match services.rooms.alias.resolve_local_alias(&room_alias) {
Ok(Some(id)) => match services
.rooms
.alias
.remove_alias(&room_alias, server_user)
.await
{
Ok(()) => Ok(RoomMessageEventContent::text_plain(format!("Removed alias from {id}"))),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {err}"))),
},
Ok(None) => Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to lookup alias: {err}"))),
| RoomAliasCommand::Remove { .. } => {
match services.rooms.alias.resolve_local_alias(&room_alias).await {
| Ok(id) => match services
.rooms
.alias
.remove_alias(&room_alias, server_user)
.await
{
| Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
"Removed alias from {id}"
))),
| Err(err) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to remove alias: {err}"
))),
},
| Err(_) =>
Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")),
}
},
RoomAliasCommand::Which {
..
} => match services.rooms.alias.resolve_local_alias(&room_alias) {
Ok(Some(id)) => Ok(RoomMessageEventContent::text_plain(format!("Alias resolves to {id}"))),
Ok(None) => Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to lookup alias: {err}"))),
| RoomAliasCommand::Which { .. } => {
match services.rooms.alias.resolve_local_alias(&room_alias).await {
| Ok(id) => Ok(RoomMessageEventContent::text_plain(format!(
"Alias resolves to {id}"
))),
| Err(_) =>
Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")),
}
},
RoomAliasCommand::List {
..
} => unreachable!(),
| RoomAliasCommand::List { .. } => unreachable!(),
}
},
RoomAliasCommand::List {
room_id,
} => {
| RoomAliasCommand::List { room_id } =>
if let Some(room_id) = room_id {
let aliases = services
let aliases: Vec<OwnedRoomAliasId> = services
.rooms
.alias
.local_aliases_for_room(&room_id)
.collect::<Result<Vec<_>, _>>();
match aliases {
Ok(aliases) => {
let plain_list = aliases.iter().fold(String::new(), |mut output, alias| {
writeln!(output, "- {alias}").expect("should be able to write to string buffer");
output
});
.map(Into::into)
.collect()
.await;
let html_list = aliases.iter().fold(String::new(), |mut output, alias| {
writeln!(output, "<li>{}</li>", escape_html(alias.as_ref()))
.expect("should be able to write to string buffer");
output
});
let plain_list = aliases.iter().fold(String::new(), |mut output, alias| {
writeln!(output, "- {alias}")
.expect("should be able to write to string buffer");
output
});
let plain = format!("Aliases for {room_id}:\n{plain_list}");
let html = format!("Aliases for {room_id}:\n<ul>{html_list}</ul>");
Ok(RoomMessageEventContent::text_html(plain, html))
},
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to list aliases: {err}"))),
}
let html_list = aliases.iter().fold(String::new(), |mut output, alias| {
writeln!(output, "<li>{}</li>", escape_html(alias.as_ref()))
.expect("should be able to write to string buffer");
output
});
let plain = format!("Aliases for {room_id}:\n{plain_list}");
let html = format!("Aliases for {room_id}:\n<ul>{html_list}</ul>");
Ok(RoomMessageEventContent::text_html(plain, html))
} else {
let aliases = services
.rooms
.alias
.all_local_aliases()
.collect::<Result<Vec<_>, _>>();
match aliases {
Ok(aliases) => {
let server_name = services.globals.server_name();
let plain_list = aliases
.iter()
.fold(String::new(), |mut output, (alias, id)| {
writeln!(output, "- `{alias}` -> #{id}:{server_name}")
.expect("should be able to write to string buffer");
output
});
.map(|(room_id, localpart)| (room_id.into(), localpart.into()))
.collect::<Vec<(OwnedRoomId, String)>>()
.await;
let html_list = aliases
.iter()
.fold(String::new(), |mut output, (alias, id)| {
writeln!(
output,
"<li><code>{}</code> -> #{}:{}</li>",
escape_html(alias.as_ref()),
escape_html(id.as_ref()),
server_name
)
.expect("should be able to write to string buffer");
output
});
let server_name = services.globals.server_name();
let plain_list = aliases
.iter()
.fold(String::new(), |mut output, (alias, id)| {
writeln!(output, "- `{alias}` -> #{id}:{server_name}")
.expect("should be able to write to string buffer");
output
});
let plain = format!("Aliases:\n{plain_list}");
let html = format!("Aliases:\n<ul>{html_list}</ul>");
Ok(RoomMessageEventContent::text_html(plain, html))
},
Err(e) => Ok(RoomMessageEventContent::text_plain(format!("Unable to list room aliases: {e}"))),
}
}
},
let html_list = aliases
.iter()
.fold(String::new(), |mut output, (alias, id)| {
writeln!(
output,
"<li><code>{}</code> -> #{}:{}</li>",
escape_html(alias.as_ref()),
escape_html(id),
server_name
)
.expect("should be able to write to string buffer");
output
});
let plain = format!("Aliases:\n{plain_list}");
let html = format!("Aliases:\n<ul>{html_list}</ul>");
Ok(RoomMessageEventContent::text_html(plain, html))
},
}
}
+26 -33
View File
@@ -1,11 +1,16 @@
use conduit::Result;
use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId};
use crate::{admin_command, get_room_info, PAGE_SIZE};
#[admin_command]
pub(super) async fn list_rooms(
&self, page: Option<usize>, exclude_disabled: bool, exclude_banned: bool, no_details: bool,
&self,
page: Option<usize>,
exclude_disabled: bool,
exclude_banned: bool,
no_details: bool,
) -> Result<RoomMessageEventContent> {
// TODO: i know there's a way to do this with clap, but i can't seem to find it
let page = page.unwrap_or(1);
@@ -14,37 +19,18 @@ pub(super) async fn list_rooms(
.rooms
.metadata
.iter_ids()
.filter_map(|room_id| {
room_id
.ok()
.filter(|room_id| {
if exclude_disabled
&& self
.services
.rooms
.metadata
.is_disabled(room_id)
.unwrap_or(false)
{
return false;
}
if exclude_banned
&& self
.services
.rooms
.metadata
.is_banned(room_id)
.unwrap_or(false)
{
return false;
}
true
})
.map(|room_id| get_room_info(self.services, &room_id))
.filter_map(|room_id| async move {
(!exclude_disabled || !self.services.rooms.metadata.is_disabled(room_id).await)
.then_some(room_id)
})
.collect::<Vec<_>>();
.filter_map(|room_id| async move {
(!exclude_banned || !self.services.rooms.metadata.is_banned(room_id).await)
.then_some(room_id)
})
.then(|room_id| get_room_info(self.services, room_id))
.collect::<Vec<_>>()
.await;
rooms.sort_by_key(|r| r.1);
rooms.reverse();
@@ -74,3 +60,10 @@ pub(super) async fn list_rooms(
Ok(RoomMessageEventContent::notice_markdown(output_plain))
}
#[admin_command]
pub(super) async fn exists(&self, room_id: OwnedRoomId) -> Result<RoomMessageEventContent> {
let result = self.services.rooms.metadata.exists(&room_id).await;
Ok(RoomMessageEventContent::notice_markdown(format!("{result}")))
}
+34 -46
View File
@@ -1,10 +1,9 @@
use std::fmt::Write;
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, RoomId};
use conduwuit::Result;
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, RoomId};
use crate::{escape_html, get_room_info, Command, PAGE_SIZE};
use crate::{get_room_info, Command, PAGE_SIZE};
#[derive(Debug, Subcommand)]
pub(crate) enum RoomDirectoryCommand {
@@ -26,72 +25,61 @@ pub(crate) enum RoomDirectoryCommand {
},
}
pub(super) async fn process(command: RoomDirectoryCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(command: RoomDirectoryCommand, context: &Command<'_>) -> Result {
let c = reprocess(command, context).await?;
context.write_str(c.body()).await?;
Ok(())
}
pub(super) async fn reprocess(
command: RoomDirectoryCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match command {
RoomDirectoryCommand::Publish {
room_id,
} => match services.rooms.directory.set_public(&room_id) {
Ok(()) => Ok(RoomMessageEventContent::text_plain("Room published")),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to update room: {err}"))),
| RoomDirectoryCommand::Publish { room_id } => {
services.rooms.directory.set_public(&room_id);
Ok(RoomMessageEventContent::notice_plain("Room published"))
},
RoomDirectoryCommand::Unpublish {
room_id,
} => match services.rooms.directory.set_not_public(&room_id) {
Ok(()) => Ok(RoomMessageEventContent::text_plain("Room unpublished")),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to update room: {err}"))),
| RoomDirectoryCommand::Unpublish { room_id } => {
services.rooms.directory.set_not_public(&room_id);
Ok(RoomMessageEventContent::notice_plain("Room unpublished"))
},
RoomDirectoryCommand::List {
page,
} => {
| RoomDirectoryCommand::List { page } => {
// TODO: i know there's a way to do this with clap, but i can't seem to find it
let page = page.unwrap_or(1);
let mut rooms = services
let mut rooms: Vec<_> = services
.rooms
.directory
.public_rooms()
.filter_map(Result::ok)
.map(|id: OwnedRoomId| get_room_info(services, &id))
.collect::<Vec<_>>();
.then(|room_id| get_room_info(services, room_id))
.collect()
.await;
rooms.sort_by_key(|r| r.1);
rooms.reverse();
let rooms = rooms
let rooms: Vec<_> = rooms
.into_iter()
.skip(page.saturating_sub(1).saturating_mul(PAGE_SIZE))
.take(PAGE_SIZE)
.collect::<Vec<_>>();
.collect();
if rooms.is_empty() {
return Ok(RoomMessageEventContent::text_plain("No more rooms."));
};
let output_plain = format!(
"Rooms:\n{}",
let output = format!(
"Rooms (page {page}):\n```\n{}\n```",
rooms
.iter()
.map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}"))
.map(|(id, members, name)| format!(
"{id} | Members: {members} | Name: {name}"
))
.collect::<Vec<_>>()
.join("\n")
);
let output_html = format!(
"<table><caption>Room directory - page \
{page}</caption>\n<tr><th>id</th>\t<th>members</th>\t<th>name</th></tr>\n{}</table>",
rooms
.iter()
.fold(String::new(), |mut output, (id, members, name)| {
writeln!(
output,
"<tr><td>{}</td>\t<td>{}</td>\t<td>{}</td></tr>",
escape_html(id.as_ref()),
members,
escape_html(name.as_ref())
)
.expect("should be able to write to string buffer");
output
})
);
Ok(RoomMessageEventContent::text_html(output_plain, output_html))
Ok(RoomMessageEventContent::text_markdown(output))
},
}
}
+33 -21
View File
@@ -1,5 +1,6 @@
use clap::Subcommand;
use conduit::Result;
use conduwuit::{utils::ReadyExt, Result};
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, RoomId};
use crate::{admin_command, admin_command_dispatch};
@@ -10,6 +11,10 @@ pub(crate) enum RoomInfoCommand {
/// - List joined members in a room
ListJoinedMembers {
room_id: Box<RoomId>,
/// Lists only our local users in the specified room
#[arg(long)]
local_only: bool,
},
/// - Displays room topic
@@ -22,44 +27,50 @@ pub(crate) enum RoomInfoCommand {
}
#[admin_command]
async fn list_joined_members(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
async fn list_joined_members(
&self,
room_id: Box<RoomId>,
local_only: bool,
) -> Result<RoomMessageEventContent> {
let room_name = self
.services
.rooms
.state_accessor
.get_name(&room_id)
.ok()
.flatten()
.unwrap_or_else(|| room_id.to_string());
.await
.unwrap_or_else(|_| room_id.to_string());
let members = self
let member_info: Vec<_> = self
.services
.rooms
.state_cache
.room_members(&room_id)
.filter_map(Result::ok);
let member_info = members
.into_iter()
.map(|user_id| {
(
user_id.clone(),
.ready_filter(|user_id| {
local_only
.then(|| self.services.globals.user_is_local(user_id))
.unwrap_or(true)
})
.map(ToOwned::to_owned)
.filter_map(|user_id| async move {
Some((
self.services
.users
.displayname(&user_id)
.unwrap_or(None)
.unwrap_or_else(|| user_id.to_string()),
)
.await
.unwrap_or_else(|_| user_id.to_string()),
user_id,
))
})
.collect::<Vec<_>>();
.collect()
.await;
let output_plain = format!(
"{} Members in Room \"{}\":\n```\n{}\n```",
member_info.len(),
room_name,
member_info
.iter()
.map(|(mxid, displayname)| format!("{mxid} | {displayname}"))
.into_iter()
.map(|(displayname, mxid)| format!("{mxid} | {displayname}"))
.collect::<Vec<_>>()
.join("\n")
);
@@ -69,11 +80,12 @@ async fn list_joined_members(&self, room_id: Box<RoomId>) -> Result<RoomMessageE
#[admin_command]
async fn view_room_topic(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
let Some(room_topic) = self
let Ok(room_topic) = self
.services
.rooms
.state_accessor
.get_room_topic(&room_id)?
.get_room_topic(&room_id)
.await
else {
return Ok(RoomMessageEventContent::text_plain("Room does not have a room topic set."));
};
+9 -2
View File
@@ -5,10 +5,12 @@ mod info;
mod moderation;
use clap::Subcommand;
use conduit::Result;
use conduwuit::Result;
use ruma::OwnedRoomId;
use self::{
alias::RoomAliasCommand, directory::RoomDirectoryCommand, info::RoomInfoCommand, moderation::RoomModerationCommand,
alias::RoomAliasCommand, directory::RoomDirectoryCommand, info::RoomInfoCommand,
moderation::RoomModerationCommand,
};
use crate::admin_command_dispatch;
@@ -49,4 +51,9 @@ pub(super) enum RoomCommand {
#[command(subcommand)]
/// - Manage the room directory
Directory(RoomDirectoryCommand),
/// - Check if we know about a room
Exists {
room_id: OwnedRoomId,
},
}
+286 -260
View File
@@ -1,7 +1,15 @@
use api::client::leave_room;
use clap::Subcommand;
use conduit::{debug, error, info, warn, Result};
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, RoomAliasId, RoomId, RoomOrAliasId};
use conduwuit::{
debug, error, info,
utils::{IterStream, ReadyExt},
warn, Result,
};
use futures::StreamExt;
use ruma::{
events::room::message::RoomMessageEventContent, OwnedRoomId, RoomAliasId, RoomId,
RoomOrAliasId,
};
use crate::{admin_command, admin_command_dispatch, get_room_info};
@@ -70,13 +78,16 @@ pub(crate) enum RoomModerationCommand {
#[admin_command]
async fn ban_room(
&self, force: bool, disable_federation: bool, room: Box<RoomOrAliasId>,
&self,
force: bool,
disable_federation: bool,
room: Box<RoomOrAliasId>,
) -> Result<RoomMessageEventContent> {
debug!("Got room alias or ID: {}", room);
let admin_room_alias = &self.services.globals.admin_alias;
if let Some(admin_room_id) = self.services.admin.get_admin_room()? {
if let Ok(admin_room_id) = self.services.admin.get_admin_room().await {
if room.to_string().eq(&admin_room_id) || room.to_string().eq(admin_room_alias) {
return Ok(RoomMessageEventContent::text_plain("Not allowed to ban the admin room."));
}
@@ -84,129 +95,128 @@ async fn ban_room(
let room_id = if room.is_room_id() {
let room_id = match RoomId::parse(&room) {
Ok(room_id) => room_id,
Err(e) => {
| Ok(room_id) => room_id,
| Err(e) =>
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to parse room ID {room}. Please note that this requires a full room ID \
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
)))
},
"Failed to parse room ID {room}. Please note that this requires a full room \
ID (`!awIh6gGInaS5wLQJwa:example.com`) or a room alias \
(`#roomalias:example.com`): {e}"
))),
};
debug!("Room specified is a room ID, banning room ID");
self.services.rooms.metadata.ban_room(room_id, true);
self.services.rooms.metadata.ban_room(&room_id, true)?;
room_id
room_id.to_owned()
} else if room.is_room_alias_id() {
let room_alias = match RoomAliasId::parse(&room) {
Ok(room_alias) => room_alias,
Err(e) => {
| Ok(room_alias) => room_alias,
| Err(e) =>
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to parse room ID {room}. Please note that this requires a full room ID \
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
)))
},
"Failed to parse room ID {room}. Please note that this requires a full room \
ID (`!awIh6gGInaS5wLQJwa:example.com`) or a room alias \
(`#roomalias:example.com`): {e}"
))),
};
debug!(
"Room specified is not a room ID, attempting to resolve room alias to a room ID locally, if not using \
get_alias_helper to fetch room ID remotely"
"Room specified is not a room ID, attempting to resolve room alias to a room ID \
locally, if not using get_alias_helper to fetch room ID remotely"
);
let room_id = if let Some(room_id) = self.services.rooms.alias.resolve_local_alias(&room_alias)? {
let room_id = if let Ok(room_id) = self
.services
.rooms
.alias
.resolve_local_alias(room_alias)
.await
{
room_id
} else {
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
debug!(
"We don't have this room alias to a room ID locally, attempting to fetch room \
ID over federation"
);
match self
.services
.rooms
.alias
.resolve_alias(&room_alias, None)
.resolve_alias(room_alias, None)
.await
{
Ok((room_id, servers)) => {
debug!(?room_id, ?servers, "Got federation response fetching room ID for {room}");
| Ok((room_id, servers)) => {
debug!(
?room_id,
?servers,
"Got federation response fetching room ID for {room_id}"
);
room_id
},
Err(e) => {
| Err(e) => {
return Ok(RoomMessageEventContent::notice_plain(format!(
"Failed to resolve room alias {room} to a room ID: {e}"
"Failed to resolve room alias {room_alias} to a room ID: {e}"
)));
},
}
};
self.services.rooms.metadata.ban_room(&room_id, true)?;
self.services.rooms.metadata.ban_room(&room_id, true);
room_id
} else {
return Ok(RoomMessageEventContent::text_plain(
"Room specified is not a room ID or room alias. Please note that this requires a full room ID \
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`)",
"Room specified is not a room ID or room alias. Please note that this requires a \
full room ID (`!awIh6gGInaS5wLQJwa:example.com`) or a room alias \
(`#roomalias:example.com`)",
));
};
debug!("Making all users leave the room {}", &room);
if force {
for local_user in self
let mut users = self
.services
.rooms
.state_cache
.room_members(&room_id)
.filter_map(|user| {
user.ok().filter(|local_user| {
self.services.globals.user_is_local(local_user)
// additional wrapped check here is to avoid adding remote users
// who are in the admin room to the list of local users (would
// fail auth check)
&& (self.services.globals.user_is_local(local_user)
// since this is a force operation, assume user is an admin
// if somehow this fails
&& self.services
.users
.is_admin(local_user)
.unwrap_or(true))
})
}) {
.ready_filter(|user| self.services.globals.user_is_local(user))
.boxed();
while let Some(local_user) = users.next().await {
debug!(
"Attempting leave for user {} in room {} (forced, ignoring all errors, evicting admins too)",
&local_user, &room_id
"Attempting leave for user {local_user} in room {room_id} (forced, ignoring all \
errors, evicting admins too)",
);
if let Err(e) = leave_room(self.services, &local_user, &room_id, None).await {
if let Err(e) = leave_room(self.services, local_user, &room_id, None).await {
warn!(%e, "Failed to leave room");
}
}
} else {
for local_user in self
let mut users = self
.services
.rooms
.state_cache
.room_members(&room_id)
.filter_map(|user| {
user.ok().filter(|local_user| {
local_user.server_name() == self.services.globals.server_name()
// additional wrapped check here is to avoid adding remote users
// who are in the admin room to the list of local users (would fail auth check)
&& (local_user.server_name()
== self.services.globals.server_name()
&& !self.services
.users
.is_admin(local_user)
.unwrap_or(false))
})
}) {
.ready_filter(|user| self.services.globals.user_is_local(user))
.boxed();
while let Some(local_user) = users.next().await {
if self.services.users.is_admin(local_user).await {
continue;
}
debug!("Attempting leave for user {} in room {}", &local_user, &room_id);
if let Err(e) = leave_room(self.services, &local_user, &room_id, None).await {
if let Err(e) = leave_room(self.services, local_user, &room_id, None).await {
error!(
"Error attempting to make local user {} leave room {} during room banning: {}",
"Error attempting to make local user {} leave room {} during room banning: \
{}",
&local_user, &room_id, e
);
return Ok(RoomMessageEventContent::text_plain(format!(
"Error attempting to make local user {} leave room {} during room banning (room is still banned \
but not removing any more users): {}\nIf you would like to ignore errors, use --force",
"Error attempting to make local user {} leave room {} during room banning \
(room is still banned but not removing any more users): {}\nIf you would \
like to ignore errors, use --force",
&local_user, &room_id, e
)));
}
@@ -214,12 +224,14 @@ async fn ban_room(
}
// remove any local aliases, ignore errors
for ref local_alias in self
for local_alias in &self
.services
.rooms
.alias
.local_aliases_for_room(&room_id)
.filter_map(Result::ok)
.map(ToOwned::to_owned)
.collect::<Vec<_>>()
.await
{
_ = self
.services
@@ -230,24 +242,31 @@ async fn ban_room(
}
// unpublish from room directory, ignore errors
_ = self.services.rooms.directory.set_not_public(&room_id);
self.services.rooms.directory.set_not_public(&room_id);
if disable_federation {
self.services.rooms.metadata.disable_room(&room_id, true)?;
self.services.rooms.metadata.disable_room(&room_id, true);
return Ok(RoomMessageEventContent::text_plain(
"Room banned, removed all our local users, and disabled incoming federation with room.",
"Room banned, removed all our local users, and disabled incoming federation with \
room.",
));
}
Ok(RoomMessageEventContent::text_plain(
"Room banned and removed all our local users, use `!admin federation disable-room` to stop receiving new \
inbound federation events as well if needed.",
"Room banned and removed all our local users, use `!admin federation disable-room` to \
stop receiving new inbound federation events as well if needed.",
))
}
#[admin_command]
async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
async fn ban_list_of_rooms(
&self,
force: bool,
disable_federation: bool,
) -> Result<RoomMessageEventContent> {
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
@@ -267,9 +286,10 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
for &room in &rooms_s {
match <&RoomOrAliasId>::try_from(room) {
Ok(room_alias_or_id) => {
if let Some(admin_room_id) = self.services.admin.get_admin_room()? {
if room.to_owned().eq(&admin_room_id) || room.to_owned().eq(admin_room_alias) {
| Ok(room_alias_or_id) => {
if let Ok(admin_room_id) = self.services.admin.get_admin_room().await {
if room.to_owned().eq(&admin_room_id) || room.to_owned().eq(admin_room_alias)
{
info!("User specified admin room in bulk ban list, ignoring");
continue;
}
@@ -277,175 +297,167 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
if room_alias_or_id.is_room_id() {
let room_id = match RoomId::parse(room_alias_or_id) {
Ok(room_id) => room_id,
Err(e) => {
| Ok(room_id) => room_id,
| Err(e) => {
if force {
// ignore rooms we failed to parse if we're force banning
warn!(
"Error parsing room \"{room}\" during bulk room banning, ignoring error and \
logging here: {e}"
"Error parsing room \"{room}\" during bulk room banning, \
ignoring error and logging here: {e}"
);
continue;
}
return Ok(RoomMessageEventContent::text_plain(format!(
"{room} is not a valid room ID or room alias, please fix the list and try again: {e}"
"{room} is not a valid room ID or room alias, please fix the \
list and try again: {e}"
)));
},
};
room_ids.push(room_id);
room_ids.push(room_id.to_owned());
}
if room_alias_or_id.is_room_alias_id() {
match RoomAliasId::parse(room_alias_or_id) {
Ok(room_alias) => {
let room_id =
if let Some(room_id) = self.services.rooms.alias.resolve_local_alias(&room_alias)? {
room_id
} else {
debug!(
"We don't have this room alias to a room ID locally, attempting to fetch room \
ID over federation"
);
| Ok(room_alias) => {
let room_id = if let Ok(room_id) = self
.services
.rooms
.alias
.resolve_local_alias(room_alias)
.await
{
room_id
} else {
debug!(
"We don't have this room alias to a room ID locally, \
attempting to fetch room ID over federation"
);
match self
.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}",
match self
.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) => {
// don't fail if force blocking
if force {
warn!(
"Failed to resolve room alias {room} to a room \
ID: {e}"
);
room_id
},
Err(e) => {
// don't fail if force blocking
if force {
warn!("Failed to resolve room alias {room} to a room ID: {e}");
continue;
}
continue;
}
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to resolve room alias {room} to a room ID: {e}"
)));
},
}
};
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to resolve room alias {room} to a room ID: \
{e}"
)));
},
}
};
room_ids.push(room_id);
},
Err(e) => {
| Err(e) => {
if force {
// ignore rooms we failed to parse if we're force deleting
error!(
"Error parsing room \"{room}\" during bulk room banning, ignoring error and \
logging here: {e}"
"Error parsing room \"{room}\" during bulk room banning, \
ignoring error and logging here: {e}"
);
continue;
}
return Ok(RoomMessageEventContent::text_plain(format!(
"{room} is not a valid room ID or room alias, please fix the list and try again: {e}"
"{room} is not a valid room ID or room alias, please fix the \
list and try again: {e}"
)));
},
}
}
},
Err(e) => {
| Err(e) => {
if force {
// ignore rooms we failed to parse if we're force deleting
error!(
"Error parsing room \"{room}\" during bulk room banning, ignoring error and logging here: {e}"
"Error parsing room \"{room}\" during bulk room banning, ignoring error \
and logging here: {e}"
);
continue;
}
return Ok(RoomMessageEventContent::text_plain(format!(
"{room} is not a valid room ID or room alias, please fix the list and try again: {e}"
"{room} is not a valid room ID or room alias, please fix the list and try \
again: {e}"
)));
},
}
}
for room_id in room_ids {
if self
.services
.rooms
.metadata
.ban_room(&room_id, true)
.is_ok()
{
debug!("Banned {room_id} successfully");
room_ban_count = room_ban_count.saturating_add(1);
}
self.services.rooms.metadata.ban_room(&room_id, true);
debug!("Banned {room_id} successfully");
room_ban_count = room_ban_count.saturating_add(1);
debug!("Making all users leave the room {}", &room_id);
if force {
for local_user in self
let mut users = self
.services
.rooms
.state_cache
.room_members(&room_id)
.filter_map(|user| {
user.ok().filter(|local_user| {
local_user.server_name() == self.services.globals.server_name()
// additional wrapped check here is to avoid adding remote
// users who are in the admin room to the list of local
// users (would fail auth check)
&& (local_user.server_name()
== self.services.globals.server_name()
// since this is a force operation, assume user is an
// admin if somehow this fails
&& self.services
.users
.is_admin(local_user)
.unwrap_or(true))
})
}) {
.ready_filter(|user| self.services.globals.user_is_local(user))
.boxed();
while let Some(local_user) = users.next().await {
debug!(
"Attempting leave for user {} in room {} (forced, ignoring all errors, evicting admins too)",
&local_user, room_id
"Attempting leave for user {local_user} in room {room_id} (forced, ignoring \
all errors, evicting admins too)",
);
if let Err(e) = leave_room(self.services, &local_user, &room_id, None).await {
if let Err(e) = leave_room(self.services, local_user, &room_id, None).await {
warn!(%e, "Failed to leave room");
}
}
} else {
for local_user in self
let mut users = self
.services
.rooms
.state_cache
.room_members(&room_id)
.filter_map(|user| {
user.ok().filter(|local_user| {
local_user.server_name() == self.services.globals.server_name()
// additional wrapped check here is to avoid adding remote
// users who are in the admin room to the list of local
// users (would fail auth check)
&& (local_user.server_name()
== self.services.globals.server_name()
&& !self.services
.users
.is_admin(local_user)
.unwrap_or(false))
})
}) {
debug!("Attempting leave for user {} in room {}", &local_user, &room_id);
if let Err(e) = leave_room(self.services, &local_user, &room_id, None).await {
.ready_filter(|user| self.services.globals.user_is_local(user))
.boxed();
while let Some(local_user) = users.next().await {
if self.services.users.is_admin(local_user).await {
continue;
}
debug!("Attempting leave for user {local_user} in room {room_id}");
if let Err(e) = leave_room(self.services, local_user, &room_id, None).await {
error!(
"Error attempting to make local user {} leave room {} during bulk room banning: {}",
&local_user, &room_id, e
"Error attempting to make local user {local_user} leave room {room_id} \
during bulk room banning: {e}",
);
return Ok(RoomMessageEventContent::text_plain(format!(
"Error attempting to make local user {} leave room {} during room banning (room is still \
banned but not removing any more users and not banning any more rooms): {}\nIf you would \
like to ignore errors, use --force",
"Error attempting to make local user {} leave room {} during room \
banning (room is still banned but not removing any more users and not \
banning any more rooms): {}\nIf you would like to ignore errors, use \
--force",
&local_user, &room_id, e
)));
}
@@ -453,33 +465,33 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
}
// remove any local aliases, ignore errors
for ref local_alias in self
.services
self.services
.rooms
.alias
.local_aliases_for_room(&room_id)
.filter_map(Result::ok)
{
_ = self
.services
.rooms
.alias
.remove_alias(local_alias, &self.services.globals.server_user)
.await;
}
.map(ToOwned::to_owned)
.for_each(|local_alias| async move {
self.services
.rooms
.alias
.remove_alias(&local_alias, &self.services.globals.server_user)
.await
.ok();
})
.await;
// unpublish from room directory, ignore errors
_ = self.services.rooms.directory.set_not_public(&room_id);
self.services.rooms.directory.set_not_public(&room_id);
if disable_federation {
self.services.rooms.metadata.disable_room(&room_id, true)?;
self.services.rooms.metadata.disable_room(&room_id, true);
}
}
if disable_federation {
Ok(RoomMessageEventContent::text_plain(format!(
"Finished bulk room ban, banned {room_ban_count} total rooms, evicted all users, and disabled incoming \
federation with the room."
"Finished bulk room ban, banned {room_ban_count} total rooms, evicted all users, \
and disabled incoming federation with the room."
)))
} else {
Ok(RoomMessageEventContent::text_plain(format!(
@@ -489,56 +501,72 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
}
#[admin_command]
async fn unban_room(&self, enable_federation: bool, room: Box<RoomOrAliasId>) -> Result<RoomMessageEventContent> {
async fn unban_room(
&self,
enable_federation: bool,
room: Box<RoomOrAliasId>,
) -> Result<RoomMessageEventContent> {
let room_id = if room.is_room_id() {
let room_id = match RoomId::parse(&room) {
Ok(room_id) => room_id,
Err(e) => {
| Ok(room_id) => room_id,
| Err(e) =>
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to parse room ID {room}. Please note that this requires a full room ID \
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
)))
},
"Failed to parse room ID {room}. Please note that this requires a full room \
ID (`!awIh6gGInaS5wLQJwa:example.com`) or a room alias \
(`#roomalias:example.com`): {e}"
))),
};
debug!("Room specified is a room ID, unbanning room ID");
self.services.rooms.metadata.ban_room(room_id, false);
self.services.rooms.metadata.ban_room(&room_id, false)?;
room_id
room_id.to_owned()
} else if room.is_room_alias_id() {
let room_alias = match RoomAliasId::parse(&room) {
Ok(room_alias) => room_alias,
Err(e) => {
| Ok(room_alias) => room_alias,
| Err(e) =>
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to parse room ID {room}. Please note that this requires a full room ID \
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
)))
},
"Failed to parse room ID {room}. Please note that this requires a full room \
ID (`!awIh6gGInaS5wLQJwa:example.com`) or a room alias \
(`#roomalias:example.com`): {e}"
))),
};
debug!(
"Room specified is not a room ID, attempting to resolve room alias to a room ID locally, if not using \
get_alias_helper to fetch room ID remotely"
"Room specified is not a room ID, attempting to resolve room alias to a room ID \
locally, if not using get_alias_helper to fetch room ID remotely"
);
let room_id = if let Some(room_id) = self.services.rooms.alias.resolve_local_alias(&room_alias)? {
let room_id = if let Ok(room_id) = self
.services
.rooms
.alias
.resolve_local_alias(room_alias)
.await
{
room_id
} else {
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
debug!(
"We don't have this room alias to a room ID locally, attempting to fetch room \
ID over federation"
);
match self
.services
.rooms
.alias
.resolve_alias(&room_alias, None)
.resolve_alias(room_alias, None)
.await
{
Ok((room_id, servers)) => {
debug!(?room_id, ?servers, "Got federation response fetching room ID for room {room}");
| Ok((room_id, servers)) => {
debug!(
?room_id,
?servers,
"Got federation response fetching room ID for room {room}"
);
room_id
},
Err(e) => {
| Err(e) => {
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to resolve room alias {room} to a room ID: {e}"
)));
@@ -546,68 +574,66 @@ async fn unban_room(&self, enable_federation: bool, room: Box<RoomOrAliasId>) ->
}
};
self.services.rooms.metadata.ban_room(&room_id, false)?;
self.services.rooms.metadata.ban_room(&room_id, false);
room_id
} else {
return Ok(RoomMessageEventContent::text_plain(
"Room specified is not a room ID or room alias. Please note that this requires a full room ID \
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`)",
"Room specified is not a room ID or room alias. Please note that this requires a \
full room ID (`!awIh6gGInaS5wLQJwa:example.com`) or a room alias \
(`#roomalias:example.com`)",
));
};
if enable_federation {
self.services.rooms.metadata.disable_room(&room_id, false)?;
self.services.rooms.metadata.disable_room(&room_id, false);
return Ok(RoomMessageEventContent::text_plain("Room unbanned."));
}
Ok(RoomMessageEventContent::text_plain(
"Room unbanned, you may need to re-enable federation with the room using enable-room if this is a remote room \
to make it fully functional.",
"Room unbanned, you may need to re-enable federation with the room using enable-room if \
this is a remote room to make it fully functional.",
))
}
#[admin_command]
async fn list_banned_rooms(&self, no_details: bool) -> Result<RoomMessageEventContent> {
let rooms = self
let room_ids: Vec<OwnedRoomId> = self
.services
.rooms
.metadata
.list_banned_rooms()
.collect::<Result<Vec<_>, _>>();
.map(Into::into)
.collect()
.await;
match rooms {
Ok(room_ids) => {
if room_ids.is_empty() {
return Ok(RoomMessageEventContent::text_plain("No rooms are banned."));
}
let mut rooms = room_ids
.into_iter()
.map(|room_id| get_room_info(self.services, &room_id))
.collect::<Vec<_>>();
rooms.sort_by_key(|r| r.1);
rooms.reverse();
let output_plain = format!(
"Rooms Banned ({}):\n```\n{}\n```",
rooms.len(),
rooms
.iter()
.map(|(id, members, name)| if no_details {
format!("{id}")
} else {
format!("{id}\tMembers: {members}\tName: {name}")
})
.collect::<Vec<_>>()
.join("\n")
);
Ok(RoomMessageEventContent::notice_markdown(output_plain))
},
Err(e) => {
error!("Failed to list banned rooms: {e}");
Ok(RoomMessageEventContent::text_plain(format!("Unable to list banned rooms: {e}")))
},
if room_ids.is_empty() {
return Ok(RoomMessageEventContent::text_plain("No rooms are banned."));
}
let mut rooms = room_ids
.iter()
.stream()
.then(|room_id| get_room_info(self.services, room_id))
.collect::<Vec<_>>()
.await;
rooms.sort_by_key(|r| r.1);
rooms.reverse();
let output_plain = format!(
"Rooms Banned ({}):\n```\n{}\n```",
rooms.len(),
rooms
.iter()
.map(|(id, members, name)| if no_details {
format!("{id}")
} else {
format!("{id}\tMembers: {members}\tName: {name}")
})
.collect::<Vec<_>>()
.join("\n")
);
Ok(RoomMessageEventContent::notice_markdown(output_plain))
}
+35 -36
View File
@@ -1,6 +1,6 @@
use std::{fmt::Write, sync::Arc};
use std::{fmt::Write, path::PathBuf, sync::Arc};
use conduit::{info, utils::time, warn, Err, Result};
use conduwuit::{info, utils::time, warn, Err, Result};
use ruma::events::room::message::RoomMessageEventContent;
use crate::admin_command;
@@ -21,18 +21,31 @@ pub(super) async fn uptime(&self) -> Result<RoomMessageEventContent> {
#[admin_command]
pub(super) async fn show_config(&self) -> Result<RoomMessageEventContent> {
// Construct and send the response
Ok(RoomMessageEventContent::text_plain(format!("{}", self.services.globals.config)))
Ok(RoomMessageEventContent::text_markdown(format!(
"{}",
*self.services.server.config
)))
}
#[admin_command]
pub(super) async fn reload_config(
&self,
path: Option<PathBuf>,
) -> Result<RoomMessageEventContent> {
let path = path.as_deref().into_iter();
self.services.config.reload(path)?;
Ok(RoomMessageEventContent::text_plain("Successfully reconfigured."))
}
#[admin_command]
pub(super) async fn list_features(
&self, available: bool, enabled: bool, comma: bool,
&self,
available: bool,
enabled: bool,
comma: bool,
) -> Result<RoomMessageEventContent> {
let delim = if comma {
","
} else {
" "
};
let delim = if comma { "," } else { " " };
if enabled && !available {
let features = info::rustc::features().join(delim);
let out = format!("`\n{features}\n`");
@@ -50,16 +63,8 @@ pub(super) async fn list_features(
let available = info::cargo::features();
for feature in available {
let active = enabled.contains(&feature.as_str());
let emoji = if active {
""
} else {
""
};
let remark = if active {
"[enabled]"
} else {
""
};
let emoji = if active { "" } else { "" };
let remark = if active { "[enabled]" } else { "" };
writeln!(features, "{emoji} {feature} {remark}")?;
}
@@ -70,7 +75,8 @@ pub(super) async fn list_features(
pub(super) async fn memory_usage(&self) -> Result<RoomMessageEventContent> {
let services_usage = self.services.memory_usage().await?;
let database_usage = self.services.db.db.memory_usage()?;
let allocator_usage = conduit::alloc::memory_usage().map_or(String::new(), |s| format!("\nAllocator:\n{s}"));
let allocator_usage =
conduwuit::alloc::memory_usage().map_or(String::new(), |s| format!("\nAllocator:\n{s}"));
Ok(RoomMessageEventContent::text_plain(format!(
"Services:\n{services_usage}\nDatabase:\n{database_usage}{allocator_usage}",
@@ -86,7 +92,7 @@ pub(super) async fn clear_caches(&self) -> Result<RoomMessageEventContent> {
#[admin_command]
pub(super) async fn list_backups(&self) -> Result<RoomMessageEventContent> {
let result = self.services.globals.db.backup_list()?;
let result = self.services.db.db.backup_list()?;
if result.is_empty() {
Ok(RoomMessageEventContent::text_plain("No backups found."))
@@ -97,31 +103,24 @@ pub(super) async fn list_backups(&self) -> Result<RoomMessageEventContent> {
#[admin_command]
pub(super) async fn backup_database(&self) -> Result<RoomMessageEventContent> {
let globals = Arc::clone(&self.services.globals);
let db = Arc::clone(&self.services.db);
let mut result = self
.services
.server
.runtime()
.spawn_blocking(move || match globals.db.backup() {
Ok(()) => String::new(),
Err(e) => (*e).to_string(),
.spawn_blocking(move || match db.db.backup() {
| Ok(()) => String::new(),
| Err(e) => e.to_string(),
})
.await?;
if result.is_empty() {
result = self.services.globals.db.backup_list()?;
result = self.services.db.db.backup_list()?;
}
Ok(RoomMessageEventContent::notice_markdown(result))
}
#[admin_command]
pub(super) async fn list_database_files(&self) -> Result<RoomMessageEventContent> {
let result = self.services.globals.db.file_list()?;
Ok(RoomMessageEventContent::notice_markdown(result))
}
#[admin_command]
pub(super) async fn admin_notice(&self, message: Vec<String>) -> Result<RoomMessageEventContent> {
let message = message.join(" ");
@@ -140,12 +139,12 @@ pub(super) async fn reload_mods(&self) -> Result<RoomMessageEventContent> {
#[admin_command]
#[cfg(unix)]
pub(super) async fn restart(&self, force: bool) -> Result<RoomMessageEventContent> {
use conduit::utils::sys::current_exe_deleted;
use conduwuit::utils::sys::current_exe_deleted;
if !force && current_exe_deleted() {
return Err!(
"The server cannot be restarted because the executable changed. If this is expected use --force to \
override."
"The server cannot be restarted because the executable changed. If this is expected \
use --force to override."
);
}
+8 -4
View File
@@ -1,7 +1,9 @@
mod commands;
use std::path::PathBuf;
use clap::Subcommand;
use conduit::Result;
use conduwuit::Result;
use crate::admin_command_dispatch;
@@ -14,6 +16,11 @@ pub(super) enum ServerCommand {
/// - Show configuration values
ShowConfig,
/// - Reload configuration values
ReloadConfig {
path: Option<PathBuf>,
},
/// - List the features built into the server
ListFeatures {
#[arg(short, long)]
@@ -39,9 +46,6 @@ pub(super) enum ServerCommand {
/// - List database backups
ListBackups,
/// - List database files
ListDatabaseFiles,
/// - Send a message to the admin room.
AdminNotice {
message: Vec<String>,
+573 -176
View File
File diff suppressed because it is too large Load Diff
+37 -1
View File
@@ -1,7 +1,7 @@
mod commands;
use clap::Subcommand;
use conduit::Result;
use conduwuit::Result;
use ruma::{EventId, OwnedRoomOrAliasId, RoomId};
use crate::admin_command_dispatch;
@@ -22,6 +22,8 @@ pub(super) enum UserCommand {
ResetPassword {
/// Username of the user for whom the password should be reset
username: String,
/// New password for the user, if unspecified one is generated
password: Option<String>,
},
/// - Deactivate a user
@@ -79,6 +81,13 @@ pub(super) enum UserCommand {
room_id: OwnedRoomOrAliasId,
},
/// - Forces the specified user to drop their power levels to the room
/// default, if their permissions allow and the auth check permits
ForceDemote {
user_id: String,
room_id: OwnedRoomOrAliasId,
},
/// - Grant server-admin privileges to a user.
MakeUserAdmin {
user_id: String,
@@ -117,4 +126,31 @@ pub(super) enum UserCommand {
RedactEvent {
event_id: Box<EventId>,
},
/// - Force joins a specified list of local users to join the specified
/// room.
///
/// Specify a codeblock of usernames.
///
/// At least 1 server admin must be in the room to reduce abuse.
///
/// Requires the `--yes-i-want-to-do-this` flag.
ForceJoinListOfLocalUsers {
room_id: OwnedRoomOrAliasId,
#[arg(long)]
yes_i_want_to_do_this: bool,
},
/// - Force joins all local users to the specified room.
///
/// At least 1 server admin must be in the room to reduce abuse.
///
/// Requires the `--yes-i-want-to-do-this` flag.
ForceJoinAllLocalUsers {
room_id: OwnedRoomOrAliasId,
#[arg(long)]
yes_i_want_to_do_this: bool,
},
}
+17 -13
View File
@@ -1,4 +1,4 @@
use conduit_core::{err, Err, Result};
use conduwuit_core::{err, Err, Result};
use ruma::{OwnedRoomId, OwnedUserId, RoomId, UserId};
use service::Services;
@@ -8,23 +8,24 @@ pub(crate) fn escape_html(s: &str) -> String {
.replace('>', "&gt;")
}
pub(crate) fn get_room_info(services: &Services, id: &RoomId) -> (OwnedRoomId, u64, String) {
pub(crate) async fn get_room_info(
services: &Services,
room_id: &RoomId,
) -> (OwnedRoomId, u64, String) {
(
id.into(),
room_id.into(),
services
.rooms
.state_cache
.room_joined_count(id)
.ok()
.flatten()
.room_joined_count(room_id)
.await
.unwrap_or(0),
services
.rooms
.state_accessor
.get_name(id)
.ok()
.flatten()
.unwrap_or_else(|| id.to_string()),
.get_name(room_id)
.await
.unwrap_or_else(|_| room_id.to_string()),
)
}
@@ -46,14 +47,17 @@ pub(crate) fn parse_local_user_id(services: &Services, user_id: &str) -> Result<
}
/// Parses user ID that is an active (not guest or deactivated) local user
pub(crate) fn parse_active_local_user_id(services: &Services, user_id: &str) -> Result<OwnedUserId> {
pub(crate) async fn parse_active_local_user_id(
services: &Services,
user_id: &str,
) -> Result<OwnedUserId> {
let user_id = parse_local_user_id(services, user_id)?;
if !services.users.exists(&user_id)? {
if !services.users.exists(&user_id).await {
return Err!("User {user_id:?} does not exist on this server.");
}
if services.users.is_deactivated(&user_id)? {
if services.users.is_deactivated(&user_id).await? {
return Err!("User {user_id:?} is deactivated.");
}
+7 -8
View File
@@ -1,5 +1,5 @@
[package]
name = "conduit_api"
name = "conduwuit_api"
categories.workspace = true
description.workspace = true
edition.workspace = true
@@ -18,7 +18,6 @@ crate-type = [
[features]
element_hacks = []
#dev_release_log_level = []
release_max_log_level = [
"tracing/max_level_trace",
"tracing/release_max_level_info",
@@ -41,17 +40,17 @@ axum-extra.workspace = true
axum.workspace = true
base64.workspace = true
bytes.workspace = true
conduit-core.workspace = true
conduit-database.workspace = true
conduit-service.workspace = true
conduwuit-core.workspace = true
conduwuit-database.workspace = true
conduwuit-service.workspace = true
const-str.workspace = true
futures-util.workspace = true
futures.workspace = true
hmac.workspace = true
http.workspace = true
http-body-util.workspace = true
hyper.workspace = true
ipaddress.workspace = true
jsonwebtoken.workspace = true
itertools.workspace = true
log.workspace = true
rand.workspace = true
reqwest.workspace = true
@@ -59,7 +58,7 @@ ruma.workspace = true
serde_html_form.workspace = true
serde_json.workspace = true
serde.workspace = true
sha-1.workspace = true
sha1.workspace = true
tokio.workspace = true
tracing.workspace = true
+355 -172
View File
@@ -2,22 +2,33 @@ use std::fmt::Write;
use axum::extract::State;
use axum_client_ip::InsecureClientIp;
use conduit::{debug_info, error, info, utils, warn, Error, Result};
use conduwuit::{
debug_info, error, info, is_equal_to, utils, utils::ReadyExt, warn, Error, PduBuilder, Result,
};
use futures::{FutureExt, StreamExt};
use register::RegistrationKind;
use ruma::{
api::client::{
account::{
change_password, check_registration_token_validity, deactivate, get_3pids, get_username_availability,
change_password, check_registration_token_validity, deactivate, get_3pids,
get_username_availability,
register::{self, LoginType},
request_3pid_management_token_via_email, request_3pid_management_token_via_msisdn, whoami,
ThirdPartyIdRemovalStatus,
request_3pid_management_token_via_email, request_3pid_management_token_via_msisdn,
whoami, ThirdPartyIdRemovalStatus,
},
error::ErrorKind,
uiaa::{AuthFlow, AuthType, UiaaInfo},
},
events::{room::message::RoomMessageEventContent, GlobalAccountDataEventType},
events::{
room::{
message::RoomMessageEventContent,
power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent},
},
GlobalAccountDataEventType, StateEventType,
},
push, OwnedRoomId, UserId,
};
use service::Services;
use super::{join_room_by_id_helper, DEVICE_ID_LENGTH, SESSION_ID_LENGTH, TOKEN_LENGTH};
use crate::Ruma;
@@ -37,17 +48,35 @@ const RANDOM_USER_ID_LENGTH: usize = 10;
/// invalid when trying to register
#[tracing::instrument(skip_all, fields(%client), name = "register_available")]
pub(crate) async fn get_register_available_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_username_availability::v3::Request>,
) -> Result<get_username_availability::v3::Response> {
// workaround for https://github.com/matrix-org/matrix-appservice-irc/issues/1780 due to inactivity of fixing the issue
let is_matrix_appservice_irc = body.appservice_info.as_ref().is_some_and(|appservice| {
appservice.registration.id == "irc"
|| appservice.registration.id.contains("matrix-appservice-irc")
|| appservice.registration.id.contains("matrix_appservice_irc")
});
// don't force the username lowercase if it's from matrix-appservice-irc
let body_username = if is_matrix_appservice_irc {
body.username.clone()
} else {
body.username.to_lowercase()
};
// Validate user id
let user_id = UserId::parse_with_server_name(body.username.to_lowercase(), services.globals.server_name())
let user_id = UserId::parse_with_server_name(body_username, services.globals.server_name())
.ok()
.filter(|user_id| !user_id.is_historical() && services.globals.user_is_local(user_id))
.filter(|user_id| {
(!user_id.is_historical() || is_matrix_appservice_irc)
&& services.globals.user_is_local(user_id)
})
.ok_or(Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
// Check if username is creative enough
if services.users.exists(&user_id)? {
if services.users.exists(&user_id).await {
return Err(Error::BadRequest(ErrorKind::UserInUse, "Desired user ID is already taken."));
}
@@ -62,9 +91,7 @@ pub(crate) async fn get_register_available_route(
// TODO add check for appservice namespaces
// If no if check is true we have an username that's available to be used.
Ok(get_username_availability::v3::Response {
available: true,
})
Ok(get_username_availability::v3::Response { available: true })
}
/// # `POST /_matrix/client/v3/register`
@@ -87,13 +114,15 @@ pub(crate) async fn get_register_available_route(
#[allow(clippy::doc_markdown)]
#[tracing::instrument(skip_all, fields(%client), name = "register")]
pub(crate) async fn register_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp, body: Ruma<register::v3::Request>,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<register::v3::Request>,
) -> Result<register::v3::Response> {
if !services.globals.allow_registration() && body.appservice_info.is_none() {
info!(
"Registration disabled and request not from known appservice, rejecting registration attempt for username \
{:?}",
body.username
"Registration disabled and request not from known appservice, rejecting \
registration attempt for username \"{}\"",
body.username.as_deref().unwrap_or("")
);
return Err(Error::BadRequest(ErrorKind::forbidden(), "Registration has been disabled."));
}
@@ -102,12 +131,13 @@ pub(crate) async fn register_route(
if is_guest
&& (!services.globals.allow_guest_registration()
|| (services.globals.allow_registration() && services.globals.config.registration_token.is_some()))
|| (services.globals.allow_registration()
&& services.globals.registration_token.is_some()))
{
info!(
"Guest registration disabled / registration enabled with token configured, rejecting guest registration \
attempt, initial device name: {:?}",
body.initial_device_display_name
"Guest registration disabled / registration enabled with token configured, \
rejecting guest registration attempt, initial device name: \"{}\"",
body.initial_device_display_name.as_deref().unwrap_or("")
);
return Err(Error::BadRequest(
ErrorKind::GuestAccessForbidden,
@@ -117,25 +147,52 @@ pub(crate) async fn register_route(
// forbid guests from registering if there is not a real admin user yet. give
// generic user error.
if is_guest && services.users.count()? < 2 {
if is_guest && services.users.count().await < 2 {
warn!(
"Guest account attempted to register before a real admin user has been registered, rejecting \
registration. Guest's initial device name: {:?}",
body.initial_device_display_name
"Guest account attempted to register before a real admin user has been registered, \
rejecting registration. Guest's initial device name: \"{}\"",
body.initial_device_display_name.as_deref().unwrap_or("")
);
return Err(Error::BadRequest(ErrorKind::forbidden(), "Registration temporarily disabled."));
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Registration temporarily disabled.",
));
}
let user_id = match (&body.username, is_guest) {
(Some(username), false) => {
let proposed_user_id =
UserId::parse_with_server_name(username.to_lowercase(), services.globals.server_name())
.ok()
.filter(|user_id| !user_id.is_historical() && services.globals.user_is_local(user_id))
.ok_or(Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
| (Some(username), false) => {
// workaround for https://github.com/matrix-org/matrix-appservice-irc/issues/1780 due to inactivity of fixing the issue
let is_matrix_appservice_irc =
body.appservice_info.as_ref().is_some_and(|appservice| {
appservice.registration.id == "irc"
|| appservice.registration.id.contains("matrix-appservice-irc")
|| appservice.registration.id.contains("matrix_appservice_irc")
});
if services.users.exists(&proposed_user_id)? {
return Err(Error::BadRequest(ErrorKind::UserInUse, "Desired user ID is already taken."));
// don't force the username lowercase if it's from matrix-appservice-irc
let body_username = if is_matrix_appservice_irc {
username.clone()
} else {
username.to_lowercase()
};
let proposed_user_id =
UserId::parse_with_server_name(body_username, services.globals.server_name())
.ok()
.filter(|user_id| {
(!user_id.is_historical() || is_matrix_appservice_irc)
&& services.globals.user_is_local(user_id)
})
.ok_or(Error::BadRequest(
ErrorKind::InvalidUsername,
"Username is invalid.",
))?;
if services.users.exists(&proposed_user_id).await {
return Err(Error::BadRequest(
ErrorKind::UserInUse,
"Desired user ID is already taken.",
));
}
if services
@@ -148,13 +205,13 @@ pub(crate) async fn register_route(
proposed_user_id
},
_ => loop {
| _ => loop {
let proposed_user_id = UserId::parse_with_server_name(
utils::random_string(RANDOM_USER_ID_LENGTH).to_lowercase(),
services.globals.server_name(),
)
.unwrap();
if !services.users.exists(&proposed_user_id)? {
if !services.users.exists(&proposed_user_id).await {
break proposed_user_id;
}
},
@@ -174,7 +231,7 @@ pub(crate) async fn register_route(
// UIAA
let mut uiaainfo;
let skip_auth = if services.globals.config.registration_token.is_some() {
let skip_auth = if services.globals.registration_token.is_some() {
// Registration token required
uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
@@ -189,9 +246,7 @@ pub(crate) async fn register_route(
} else {
// No registration token necessary, but clients must still go through the flow
uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Dummy],
}],
flows: vec![AuthFlow { stages: vec![AuthType::Dummy] }],
completed: Vec::new(),
params: Box::default(),
session: None,
@@ -202,12 +257,16 @@ pub(crate) async fn register_route(
if !skip_auth {
if let Some(auth) = &body.auth {
let (worked, uiaainfo) = services.uiaa.try_auth(
&UserId::parse_with_server_name("", services.globals.server_name()).expect("we know this is valid"),
"".into(),
auth,
&uiaainfo,
)?;
let (worked, uiaainfo) = services
.uiaa
.try_auth(
&UserId::parse_with_server_name("", services.globals.server_name())
.expect("we know this is valid"),
"".into(),
auth,
&uiaainfo,
)
.await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
@@ -215,22 +274,19 @@ pub(crate) async fn register_route(
} else if let Some(json) = body.json_body {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services.uiaa.create(
&UserId::parse_with_server_name("", services.globals.server_name()).expect("we know this is valid"),
&UserId::parse_with_server_name("", services.globals.server_name())
.expect("we know this is valid"),
"".into(),
&uiaainfo,
&json,
)?;
);
return Err(Error::Uiaa(uiaainfo));
} else {
return Err(Error::BadRequest(ErrorKind::NotJson, "Not json."));
}
}
let password = if is_guest {
None
} else {
body.password.as_deref()
};
let password = if is_guest { None } else { body.password.as_deref() };
// Create user
services.users.create(&user_id, password)?;
@@ -240,28 +296,32 @@ pub(crate) async fn register_route(
// If `new_user_displayname_suffix` is set, registration will push whatever
// content is set to the user's display name with a space before it
if !services.globals.new_user_displayname_suffix().is_empty() && body.appservice_info.is_none() {
write!(displayname, " {}", services.globals.config.new_user_displayname_suffix)
if !services.globals.new_user_displayname_suffix().is_empty()
&& body.appservice_info.is_none()
{
write!(displayname, " {}", services.server.config.new_user_displayname_suffix)
.expect("should be able to write to string buffer");
}
services
.users
.set_displayname(&user_id, Some(displayname.clone()))
.await?;
.set_displayname(&user_id, Some(displayname.clone()));
// Initial account data
services.account_data.update(
None,
&user_id,
GlobalAccountDataEventType::PushRules.to_string().into(),
&serde_json::to_value(ruma::events::push_rules::PushRulesEvent {
content: ruma::events::push_rules::PushRulesEventContent {
global: push::Ruleset::server_default(&user_id),
},
})
.expect("to json always works"),
)?;
services
.account_data
.update(
None,
&user_id,
GlobalAccountDataEventType::PushRules.to_string().into(),
&serde_json::to_value(ruma::events::push_rules::PushRulesEvent {
content: ruma::events::push_rules::PushRulesEventContent {
global: push::Ruleset::server_default(&user_id),
},
})
.expect("to json always works"),
)
.await?;
// Inhibit login does not work for guests
if !is_guest && body.inhibit_login {
@@ -275,112 +335,144 @@ pub(crate) async fn register_route(
}
// Generate new device id if the user didn't specify one
let device_id = if is_guest {
None
} else {
body.device_id.clone()
}
.unwrap_or_else(|| utils::random_string(DEVICE_ID_LENGTH).into());
let device_id = if is_guest { None } else { body.device_id.clone() }
.unwrap_or_else(|| utils::random_string(DEVICE_ID_LENGTH).into());
// Generate new token for the device
let token = utils::random_string(TOKEN_LENGTH);
// Create device for this account
services.users.create_device(
&user_id,
&device_id,
&token,
body.initial_device_display_name.clone(),
Some(client.to_string()),
)?;
services
.users
.create_device(
&user_id,
&device_id,
&token,
body.initial_device_display_name.clone(),
Some(client.to_string()),
)
.await?;
debug_info!(%user_id, %device_id, "User account was created");
let device_display_name = body.initial_device_display_name.as_deref().unwrap_or("");
// log in conduit admin channel if a non-guest user registered
if body.appservice_info.is_none() && !is_guest {
info!("New user \"{user_id}\" registered on this server.");
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"New user \"{user_id}\" registered on this server from IP {client}."
)))
.await;
if !device_display_name.is_empty() {
info!(
"New user \"{user_id}\" registered on this server with device display name: \
\"{device_display_name}\""
);
if services.server.config.admin_room_notices {
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"New user \"{user_id}\" registered on this server from IP {client} and \
device display name \"{device_display_name}\""
)))
.await
.ok();
}
} else {
info!("New user \"{user_id}\" registered on this server.");
if services.server.config.admin_room_notices {
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"New user \"{user_id}\" registered on this server from IP {client}"
)))
.await
.ok();
}
}
}
// log in conduit admin channel if a guest registered
if body.appservice_info.is_none() && is_guest && services.globals.log_guest_registrations() {
info!("New guest user \"{user_id}\" registered on this server.");
if let Some(device_display_name) = &body.initial_device_display_name {
if body
.initial_device_display_name
.as_ref()
.is_some_and(|device_display_name| !device_display_name.is_empty())
{
if !device_display_name.is_empty() {
if services.server.config.admin_room_notices {
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"Guest user \"{user_id}\" with device display name `{device_display_name}` registered on this \
server from IP {client}."
"Guest user \"{user_id}\" with device display name \
\"{device_display_name}\" registered on this server from IP {client}"
)))
.await;
} else {
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"Guest user \"{user_id}\" with no device display name registered on this server from IP \
{client}.",
)))
.await;
.await
.ok();
}
} else {
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"Guest user \"{user_id}\" with no device display name registered on this server from IP {client}.",
)))
.await;
#[allow(clippy::collapsible_else_if)]
if services.server.config.admin_room_notices {
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"Guest user \"{user_id}\" with no device display name registered on \
this server from IP {client}",
)))
.await
.ok();
}
}
}
// If this is the first real user, grant them admin privileges except for guest
// users Note: the server user, @conduit:servername, is generated first
if !is_guest {
if let Some(admin_room) = services.admin.get_admin_room()? {
if services.rooms.state_cache.room_joined_count(&admin_room)? == Some(1) {
services
.admin
.make_user_admin(&user_id, displayname)
.await?;
if let Ok(admin_room) = services.admin.get_admin_room().await {
if services
.rooms
.state_cache
.room_joined_count(&admin_room)
.await
.is_ok_and(is_equal_to!(1))
{
services.admin.make_user_admin(&user_id).await?;
warn!("Granting {user_id} admin privileges as the first user");
}
}
}
if body.appservice_info.is_none()
&& !services.globals.config.auto_join_rooms.is_empty()
&& !services.server.config.auto_join_rooms.is_empty()
&& (services.globals.allow_guests_auto_join_rooms() || !is_guest)
{
for room in &services.globals.config.auto_join_rooms {
for room in &services.server.config.auto_join_rooms {
let Ok(room_id) = services.rooms.alias.resolve(room).await else {
error!(
"Failed to resolve room alias to room ID when attempting to auto join \
{room}, skipping"
);
continue;
};
if !services
.rooms
.state_cache
.server_in_room(services.globals.server_name(), room)?
.server_in_room(services.globals.server_name(), &room_id)
.await
{
warn!("Skipping room {room} to automatically join as we have never joined before.");
warn!(
"Skipping room {room} to automatically join as we have never joined before."
);
continue;
}
if let Some(room_id_server_name) = room.server_name() {
if let Some(room_server_name) = room.server_name() {
if let Err(e) = join_room_by_id_helper(
&services,
&user_id,
room,
&room_id,
Some("Automatically joining this room upon registration".to_owned()),
&[room_id_server_name.to_owned(), services.globals.server_name().to_owned()],
&[services.globals.server_name().to_owned(), room_server_name.to_owned()],
None,
&body.appservice_info,
)
.boxed()
.await
{
// don't return this error so we don't fail registrations
@@ -420,7 +512,8 @@ pub(crate) async fn register_route(
/// - Triggers device list updates
#[tracing::instrument(skip_all, fields(%client), name = "change_password")]
pub(crate) async fn change_password_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<change_password::v3::Request>,
) -> Result<change_password::v3::Response> {
// Authentication for this endpoint was made optional, but we need
@@ -432,9 +525,7 @@ pub(crate) async fn change_password_route(
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Password],
}],
flows: vec![AuthFlow { stages: vec![AuthType::Password] }],
completed: Vec::new(),
params: Box::default(),
session: None,
@@ -444,16 +535,20 @@ pub(crate) async fn change_password_route(
if let Some(auth) = &body.auth {
let (worked, uiaainfo) = services
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
.try_auth(sender_user, sender_device, auth, &uiaainfo)
.await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
// Success!
// Success!
} else if let Some(json) = body.json_body {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services
.uiaa
.create(sender_user, sender_device, &uiaainfo, &json)?;
.create(sender_user, sender_device, &uiaainfo, &json);
return Err(Error::Uiaa(uiaainfo));
} else {
return Err(Error::BadRequest(ErrorKind::NotJson, "Not json."));
@@ -465,23 +560,25 @@ pub(crate) async fn change_password_route(
if body.logout_devices {
// Logout all devices except the current one
for id in services
services
.users
.all_device_ids(sender_user)
.filter_map(Result::ok)
.filter(|id| id != sender_device)
{
services.users.remove_device(sender_user, &id)?;
}
.ready_filter(|id| id != sender_device)
.for_each(|id| services.users.remove_device(sender_user, id))
.await;
}
info!("User {sender_user} changed their password.");
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"User {sender_user} changed their password."
)))
.await;
if services.server.config.admin_room_notices {
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"User {sender_user} changed their password."
)))
.await
.ok();
}
Ok(change_password::v3::Response {})
}
@@ -492,7 +589,8 @@ pub(crate) async fn change_password_route(
///
/// Note: Also works for Application Services
pub(crate) async fn whoami_route(
State(services): State<crate::State>, body: Ruma<whoami::v3::Request>,
State(services): State<crate::State>,
body: Ruma<whoami::v3::Request>,
) -> Result<whoami::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let device_id = body.sender_device.clone();
@@ -500,7 +598,8 @@ pub(crate) async fn whoami_route(
Ok(whoami::v3::Response {
user_id: sender_user.clone(),
device_id,
is_guest: services.users.is_deactivated(sender_user)? && body.appservice_info.is_none(),
is_guest: services.users.is_deactivated(sender_user).await?
&& body.appservice_info.is_none(),
})
}
@@ -517,7 +616,8 @@ pub(crate) async fn whoami_route(
/// - Removes ability to log in again
#[tracing::instrument(skip_all, fields(%client), name = "deactivate")]
pub(crate) async fn deactivate_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<deactivate::v3::Request>,
) -> Result<deactivate::v3::Response> {
// Authentication for this endpoint was made optional, but we need
@@ -529,9 +629,7 @@ pub(crate) async fn deactivate_route(
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Password],
}],
flows: vec![AuthFlow { stages: vec![AuthType::Password] }],
completed: Vec::new(),
params: Box::default(),
session: None,
@@ -541,7 +639,9 @@ pub(crate) async fn deactivate_route(
if let Some(auth) = &body.auth {
let (worked, uiaainfo) = services
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
.try_auth(sender_user, sender_device, auth, &uiaainfo)
.await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
@@ -550,35 +650,38 @@ pub(crate) async fn deactivate_route(
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services
.uiaa
.create(sender_user, sender_device, &uiaainfo, &json)?;
.create(sender_user, sender_device, &uiaainfo, &json);
return Err(Error::Uiaa(uiaainfo));
} else {
return Err(Error::BadRequest(ErrorKind::NotJson, "Not json."));
}
// Remove devices and mark account as deactivated
services.users.deactivate_account(sender_user)?;
// Remove profile pictures and display name
let all_joined_rooms: Vec<OwnedRoomId> = services
.rooms
.state_cache
.rooms_joined(sender_user)
.filter_map(Result::ok)
.collect();
super::update_displayname(&services, sender_user.clone(), None, all_joined_rooms.clone()).await?;
super::update_avatar_url(&services, sender_user.clone(), None, None, all_joined_rooms).await?;
.map(Into::into)
.collect()
.await;
// Make the user leave all rooms before deactivation
super::leave_all_rooms(&services, sender_user).await;
super::update_displayname(&services, sender_user, None, &all_joined_rooms).await;
super::update_avatar_url(&services, sender_user, None, None, &all_joined_rooms).await;
full_user_deactivate(&services, sender_user, &all_joined_rooms).await?;
info!("User {sender_user} deactivated their account.");
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"User {sender_user} deactivated their account."
)))
.await;
if services.server.config.admin_room_notices {
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"User {sender_user} deactivated their account."
)))
.await
.ok();
}
Ok(deactivate::v3::Response {
id_server_unbind_result: ThirdPartyIdRemovalStatus::NoSupport,
@@ -590,7 +693,9 @@ pub(crate) async fn deactivate_route(
/// Get a list of third party identifiers associated with this account.
///
/// - Currently always returns empty list
pub(crate) async fn third_party_route(body: Ruma<get_3pids::v3::Request>) -> Result<get_3pids::v3::Response> {
pub(crate) async fn third_party_route(
body: Ruma<get_3pids::v3::Request>,
) -> Result<get_3pids::v3::Response> {
let _sender_user = body.sender_user.as_ref().expect("user is authenticated");
Ok(get_3pids::v3::Response::new(Vec::new()))
@@ -635,16 +740,94 @@ pub(crate) async fn request_3pid_management_token_via_msisdn_route(
/// Currently does not have any ratelimiting, and this isn't very practical as
/// there is only one registration token allowed.
pub(crate) async fn check_registration_token_validity(
State(services): State<crate::State>, body: Ruma<check_registration_token_validity::v1::Request>,
State(services): State<crate::State>,
body: Ruma<check_registration_token_validity::v1::Request>,
) -> Result<check_registration_token_validity::v1::Response> {
let Some(reg_token) = services.globals.config.registration_token.clone() else {
let Some(reg_token) = services.globals.registration_token.clone() else {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server does not allow token registration.",
));
};
Ok(check_registration_token_validity::v1::Response {
valid: reg_token == body.token,
})
Ok(check_registration_token_validity::v1::Response { valid: reg_token == body.token })
}
/// Runs through all the deactivation steps:
///
/// - Mark as deactivated
/// - Removing display name
/// - Removing avatar URL and blurhash
/// - Removing all profile data
/// - Leaving all rooms (and forgets all of them)
pub async fn full_user_deactivate(
services: &Services,
user_id: &UserId,
all_joined_rooms: &[OwnedRoomId],
) -> Result<()> {
services.users.deactivate_account(user_id).await.ok();
super::update_displayname(services, user_id, None, all_joined_rooms).await;
super::update_avatar_url(services, user_id, None, None, all_joined_rooms).await;
services
.users
.all_profile_keys(user_id)
.ready_for_each(|(profile_key, _)| {
services.users.set_profile_key(user_id, &profile_key, None);
})
.await;
for room_id in all_joined_rooms {
let state_lock = services.rooms.state.mutex.lock(room_id).await;
let room_power_levels = services
.rooms
.state_accessor
.room_state_get_content::<RoomPowerLevelsEventContent>(
room_id,
&StateEventType::RoomPowerLevels,
"",
)
.await
.ok();
let user_can_demote_self =
room_power_levels
.as_ref()
.is_some_and(|power_levels_content| {
RoomPowerLevels::from(power_levels_content.clone())
.user_can_change_user_power_level(user_id, user_id)
}) || services
.rooms
.state_accessor
.room_state_get(room_id, &StateEventType::RoomCreate, "")
.await
.is_ok_and(|event| event.sender == user_id);
if user_can_demote_self {
let mut power_levels_content = room_power_levels.unwrap_or_default();
power_levels_content.users.remove(user_id);
// ignore errors so deactivation doesn't fail
if let Err(e) = services
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(String::new(), &power_levels_content),
user_id,
room_id,
&state_lock,
)
.await
{
warn!(%room_id, %user_id, "Failed to demote user's own power level: {e}");
} else {
info!("Demoted {user_id} in {room_id} as part of account deactivation");
}
}
}
super::leave_all_rooms(services, user_id).await;
Ok(())
}
+159
View File
@@ -0,0 +1,159 @@
use axum::extract::State;
use conduwuit::{err, Err};
use ruma::{
api::client::config::{
get_global_account_data, get_room_account_data, set_global_account_data,
set_room_account_data,
},
events::{
AnyGlobalAccountDataEventContent, AnyRoomAccountDataEventContent,
GlobalAccountDataEventType, RoomAccountDataEventType,
},
serde::Raw,
RoomId, UserId,
};
use serde::Deserialize;
use serde_json::{json, value::RawValue as RawJsonValue};
use crate::{service::Services, Result, Ruma};
/// # `PUT /_matrix/client/r0/user/{userId}/account_data/{type}`
///
/// Sets some account data for the sender user.
pub(crate) async fn set_global_account_data_route(
State(services): State<crate::State>,
body: Ruma<set_global_account_data::v3::Request>,
) -> Result<set_global_account_data::v3::Response> {
let sender_user = body.sender_user();
if sender_user != body.user_id && body.appservice_info.is_none() {
return Err!(Request(Forbidden("You cannot set account data for other users.")));
}
set_account_data(
&services,
None,
&body.user_id,
&body.event_type.to_string(),
body.data.json(),
)
.await?;
Ok(set_global_account_data::v3::Response {})
}
/// # `PUT /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}`
///
/// Sets some room account data for the sender user.
pub(crate) async fn set_room_account_data_route(
State(services): State<crate::State>,
body: Ruma<set_room_account_data::v3::Request>,
) -> Result<set_room_account_data::v3::Response> {
let sender_user = body.sender_user();
if sender_user != body.user_id && body.appservice_info.is_none() {
return Err!(Request(Forbidden("You cannot set account data for other users.")));
}
set_account_data(
&services,
Some(&body.room_id),
&body.user_id,
&body.event_type.to_string(),
body.data.json(),
)
.await?;
Ok(set_room_account_data::v3::Response {})
}
/// # `GET /_matrix/client/r0/user/{userId}/account_data/{type}`
///
/// Gets some account data for the sender user.
pub(crate) async fn get_global_account_data_route(
State(services): State<crate::State>,
body: Ruma<get_global_account_data::v3::Request>,
) -> Result<get_global_account_data::v3::Response> {
let sender_user = body.sender_user();
if sender_user != body.user_id && body.appservice_info.is_none() {
return Err!(Request(Forbidden("You cannot get account data of other users.")));
}
let account_data: ExtractGlobalEventContent = services
.account_data
.get_global(&body.user_id, body.event_type.clone())
.await
.map_err(|_| err!(Request(NotFound("Data not found."))))?;
Ok(get_global_account_data::v3::Response { account_data: account_data.content })
}
/// # `GET /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}`
///
/// Gets some room account data for the sender user.
pub(crate) async fn get_room_account_data_route(
State(services): State<crate::State>,
body: Ruma<get_room_account_data::v3::Request>,
) -> Result<get_room_account_data::v3::Response> {
let sender_user = body.sender_user();
if sender_user != body.user_id && body.appservice_info.is_none() {
return Err!(Request(Forbidden("You cannot get account data of other users.")));
}
let account_data: ExtractRoomEventContent = services
.account_data
.get_room(&body.room_id, &body.user_id, body.event_type.clone())
.await
.map_err(|_| err!(Request(NotFound("Data not found."))))?;
Ok(get_room_account_data::v3::Response { account_data: account_data.content })
}
async fn set_account_data(
services: &Services,
room_id: Option<&RoomId>,
sender_user: &UserId,
event_type_s: &str,
data: &RawJsonValue,
) -> Result {
if event_type_s == RoomAccountDataEventType::FullyRead.to_cow_str() {
return Err!(Request(BadJson(
"This endpoint cannot be used for marking a room as fully read (setting \
m.fully_read)"
)));
}
if event_type_s == GlobalAccountDataEventType::PushRules.to_cow_str() {
return Err!(Request(BadJson(
"This endpoint cannot be used for setting/configuring push rules."
)));
}
let data: serde_json::Value = serde_json::from_str(data.get())
.map_err(|e| err!(Request(BadJson(warn!("Invalid JSON provided: {e}")))))?;
services
.account_data
.update(
room_id,
sender_user,
event_type_s.into(),
&json!({
"type": event_type_s,
"content": data,
}),
)
.await
}
#[derive(Deserialize)]
struct ExtractRoomEventContent {
content: Raw<AnyRoomAccountDataEventContent>,
}
#[derive(Deserialize)]
struct ExtractGlobalEventContent {
content: Raw<AnyGlobalAccountDataEventContent>,
}

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