Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot] 0f57e2d734 chore(deps): update rust crate tikv-jemalloc-sys to v0.6.0 2024-07-26 03:13:24 +00:00
564 changed files with 35881 additions and 66997 deletions
-27
View File
@@ -1,27 +0,0 @@
[advisories]
ignore = ["RUSTSEC-2024-0436", "RUSTSEC-2025-0014"] # advisory IDs to ignore e.g. ["RUSTSEC-2019-0001", ...]
informational_warnings = [] # warn for categories of informational advisories
severity_threshold = "none" # CVSS severity ("none", "low", "medium", "high", "critical")
# Advisory Database Configuration
[database]
path = "~/.cargo/advisory-db" # Path where advisory git repo will be cloned
url = "https://github.com/RustSec/advisory-db.git" # URL to git repo
fetch = true # Perform a `git fetch` before auditing (default: true)
stale = false # Allow stale advisory DB (i.e. no commits for 90 days, default: false)
# Output Configuration
[output]
deny = ["warnings", "unmaintained", "unsound", "yanked"] # exit on error if unmaintained dependencies are found
format = "terminal" # "terminal" (human readable report) or "json"
quiet = false # Only print information on error
show_tree = true # Show inverse dependency trees along with advisories (default: true)
# Target Configuration
[target]
arch = ["x86_64", "aarch64"] # Ignore advisories for CPU architectures other than these
os = ["linux", "windows", "macos"] # Ignore advisories for operating systems other than these
[yanked]
enabled = true # Warn for yanked crates in Cargo.lock (default: true)
update_index = true # Auto-update the crates.io index (default: true)
-4
View File
@@ -18,7 +18,3 @@ max_line_length = 80
[*.nix] [*.nix]
indent_size = 2 indent_size = 2
[*.rs]
indent_style = tab
max_line_length = 98
-87
View File
@@ -1,87 +0,0 @@
# 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
@@ -0,0 +1,8 @@
<!-- 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
@@ -0,0 +1,264 @@
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/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
+321 -411
View File
@@ -3,14 +3,20 @@ name: CI and Artifacts
on: on:
pull_request: pull_request:
push: push:
# documentation workflow deals with this or is not relevant for this workflow
paths-ignore: paths-ignore:
- '*.md'
- 'conduwuit-example.toml'
- 'book.toml'
- '.gitlab-ci.yml' - '.gitlab-ci.yml'
- '.gitignore' - '.gitignore'
- 'renovate.json' - 'renovate.json'
- 'docs/**'
- 'debian/**' - 'debian/**'
- 'docker/**' - 'docker/**'
branches: branches:
- main - main
- change-ci-cache
tags: tags:
- '*' - '*'
# Allows you to run this workflow manually from the Actions tab # Allows you to run this workflow manually from the Actions tab
@@ -21,6 +27,16 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
env: env:
# sccache
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
SCCACHE_BUCKET: "sccache"
SCCACHE_S3_USE_SSL: ${{ vars.SCCACHE_S3_USE_SSL }}
SCCACHE_REGION: ${{ vars.SCCACHE_REGION }}
SCCACHE_ENDPOINT: ${{ vars.SCCACHE_ENDPOINT }}
SCCACHE_CACHE_MULTIARCH: ${{ vars.SCCACHE_CACHE_MULTIARCH }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# Required to make some things output color # Required to make some things output color
TERM: ansi TERM: ansi
# Publishing to my nix binary cache # Publishing to my nix binary cache
@@ -35,58 +51,25 @@ env:
# Get error output from nix that we can actually use, and use our binary caches for the earlier CI steps # Get error output from nix that we can actually use, and use our binary caches for the earlier CI steps
NIX_CONFIG: | NIX_CONFIG: |
show-trace = true show-trace = true
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 https://nix-community.cachix.org https://crane.cachix.org 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= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg= nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= crane.cachix.org-1:8Scfpmn9w+hGdXH/Q9tTLiYAE/2dnJYRJP7kl80GuRk= 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
WEB_UPLOAD_SSH_USERNAME: ${{ secrets.WEB_UPLOAD_SSH_USERNAME }}
GH_REF_NAME: ${{ github.ref_name }}
WEBSERVER_DIR_NAME: ${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
permissions: {} permissions:
packages: write
contents: read
jobs: jobs:
tests: tests:
name: Test name: Test
runs-on: self-hosted runs-on: ubuntu-latest
steps:
- name: Setup SSH web publish
env: env:
web_upload_ssh_private_key: ${{ secrets.WEB_UPLOAD_SSH_PRIVATE_KEY }} CARGO_PROFILE: "test"
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' || (github.event.pull_request.draft != true)) && (env.web_upload_ssh_private_key != '') && github.event.pull_request.user.login != 'renovate[bot]' steps:
run: | - name: Free Disk Space (Ubuntu)
mkdir -p -v ~/.ssh uses: jlumbroso/free-disk-space@main
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 "Checking connection"
ssh -q website "echo test" || ssh -q website "echo test"
echo "Creating commit rev directory on web server"
ssh -q website "rm -rf /var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/" || ssh -q website "rm -rf /var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/"
ssh -q website "mkdir -v /var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/" || ssh -q website "mkdir -v /var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/"
echo "SSH_WEBSITE=1" >> "$GITHUB_ENV"
- name: Sync repository - name: Sync repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
persist-credentials: false
- name: Tag comparison check - name: Tag comparison check
if: ${{ startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') }} if: ${{ startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') }}
@@ -94,44 +77,97 @@ jobs:
# Tag mismatch with latest repo tag check to prevent potential downgrades # Tag mismatch with latest repo tag check to prevent potential downgrades
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`) LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
if [ ${LATEST_TAG} != ${GH_REF_NAME} ]; then if [ $LATEST_TAG != ${{ github.ref_name }} ]; then
echo '# WARNING: Attempting to run this workflow for a tag that is not the latest repo tag. Aborting.' echo '# WARNING: Attempting to run this workflow for a tag that is not the latest repo tag. Aborting.'
echo '# WARNING: Attempting to run this workflow for a tag that is not the latest repo tag. Aborting.' >> $GITHUB_STEP_SUMMARY echo '# WARNING: Attempting to run this workflow for a tag that is not the latest repo tag. Aborting.' >> $GITHUB_STEP_SUMMARY
exit 1 exit 1
fi fi
- 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
- name: Restore and cache Nix store
uses: nix-community/cache-nix-action@v5.1.0
with:
# restore and save a cache using this key
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/.lock') }}
# if there's no cache hit, restore a cache by this prefix
restore-prefixes-first-match: nix-${{ runner.os }}-
# collect garbage until Nix store size (in bytes) is at most this number
# before trying to save a new cache
gc-max-store-size-linux: 2073741824
# do purge caches
purge: true
# purge all versions of the cache
purge-prefixes: nix-${{ runner.os }}-
# created more than this number of seconds ago relative to the start of the `Post Restore` phase
purge-last-accessed: 86400
# except the version with the `primary-key`, if it exists
purge-primary-key: never
# always save the cache
save-always: true
- name: Apply Nix binary cache configuration
run: |
sudo tee -a "${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf" > /dev/null <<EOF
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit https://cache.lix.systems https://conduwuit.cachix.org
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
EOF
- 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 }}
EOF
- name: Prepare build environment - name: Prepare build environment
run: | run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc" echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow direnv allow
nix develop .#all-features --command true nix develop .#all-features --command true
- name: Cache CI dependencies - name: Cache CI dependencies
run: | 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 bin/nix-build-and-cache ci
bin/nix-build-and-cache just '.#devShells.x86_64-linux.default' if [[ $? == 0 ]]; then
bin/nix-build-and-cache just '.#devShells.x86_64-linux.all-features' SUCCESS=true
bin/nix-build-and-cache just '.#devShells.x86_64-linux.dynamic' break
else
sleep 3
fi
done
if [[ $SUCCESS == "false" ]]; then
exit 1
fi
# use sccache for Rust
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@main
# use rust-cache # use rust-cache
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
# 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/') }}
with: with:
cache-all-crates: "true" cache-all-crates: "true"
cache-on-failure: "true"
cache-targets: "true"
- name: Run CI tests - name: Run CI tests
env:
CARGO_PROFILE: "test"
run: | run: |
direnv exec . engage > >(tee -a test_output.log) direnv exec . engage > >(tee -a test_output.log)
- name: Run Complement tests - name: Run Complement tests
env:
CARGO_PROFILE: "test"
run: | run: |
# the nix devshell sets $COMPLEMENT_SRC, so "/dev/null" is no-op # the nix devshell sets $COMPLEMENT_SRC, so "/dev/null" is no-op
direnv exec . bin/complement "/dev/null" complement_test_logs.jsonl complement_test_results.jsonl > >(tee -a test_output.log) direnv exec . bin/complement "/dev/null" complement_test_logs.jsonl complement_test_results.jsonl > >(tee -a test_output.log)
@@ -143,7 +179,6 @@ jobs:
name: complement_oci_image.tar.gz name: complement_oci_image.tar.gz
path: complement_oci_image.tar.gz path: complement_oci_image.tar.gz
if-no-files-found: error if-no-files-found: error
compression-level: 0
- name: Upload Complement logs - name: Upload Complement logs
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -164,152 +199,173 @@ jobs:
diff -u --color=always tests/test_results/complement/test_results.jsonl complement_test_results.jsonl > >(tee -a complement_diff_output.log) diff -u --color=always tests/test_results/complement/test_results.jsonl complement_test_results.jsonl > >(tee -a complement_diff_output.log)
- name: Update Job Summary - name: Update Job Summary
env:
GH_JOB_STATUS: ${{ job.status }}
if: success() || failure() if: success() || failure()
run: | run: |
if [ ${GH_JOB_STATUS} == 'success' ]; then if [ ${{ job.status }} == 'success' ]; then
echo '# ✅ CI completed suwuccessfully' >> $GITHUB_STEP_SUMMARY echo '# ✅ completed suwuccessfully' >> $GITHUB_STEP_SUMMARY
else else
echo '# CI failed (last 100 lines of output)' >> $GITHUB_STEP_SUMMARY echo '# CI failure' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY
tail -n 100 test_output.log | sed 's/\x1b\[[0-9;]*m//g' >> $GITHUB_STEP_SUMMARY tail -n 40 test_output.log | sed 's/\x1b\[[0-9;]*m//g' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY
echo '# Complement diff results (last 100 lines)' >> $GITHUB_STEP_SUMMARY echo '# Complement diff results' >> $GITHUB_STEP_SUMMARY
echo '```diff' >> $GITHUB_STEP_SUMMARY echo '```diff' >> $GITHUB_STEP_SUMMARY
tail -n 100 complement_diff_output.log | sed 's/\x1b\[[0-9;]*m//g' >> $GITHUB_STEP_SUMMARY tail -n 100 complement_diff_output.log | sed 's/\x1b\[[0-9;]*m//g' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY
fi fi
- name: Run cargo clean test artifacts
run: |
cargo clean --profile test
build: build:
name: Build name: Build
runs-on: self-hosted runs-on: ubuntu-latest
needs: tests
strategy: strategy:
matrix: matrix:
include: include:
- target: aarch64-linux-musl - target: aarch64-unknown-linux-musl
- target: x86_64-linux-musl - target: x86_64-unknown-linux-musl
steps: steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
- name: Sync repository - name: Sync repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup SSH web publish - uses: nixbuild/nix-quick-install-action@v28
env:
web_upload_ssh_private_key: ${{ secrets.WEB_UPLOAD_SSH_PRIVATE_KEY }} - name: Enable Cachix binary cache
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' || (github.event.pull_request.draft != true)) && (env.web_upload_ssh_private_key != '') && github.event.pull_request.user.login != 'renovate[bot]'
run: | run: |
mkdir -p -v ~/.ssh nix profile install nixpkgs#cachix
cachix use crane
cachix use nix-community
echo "${{ secrets.WEB_UPLOAD_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts - name: Restore and cache Nix store
echo "${{ secrets.WEB_UPLOAD_SSH_PRIVATE_KEY }}" >> ~/.ssh/id_ed25519 uses: nix-community/cache-nix-action@v5.1.0
with:
# restore and save a cache using this key
primary-key: nix-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('**/*.nix', '**/.lock') }}
# if there's no cache hit, restore a cache by this prefix
restore-prefixes-first-match: nix-${{ runner.os }}-
# collect garbage until Nix store size (in bytes) is at most this number
# before trying to save a new cache
gc-max-store-size-linux: 2073741824
# do purge caches
purge: true
# purge all versions of the cache
purge-prefixes: nix-${{ runner.os }}-
# created more than this number of seconds ago relative to the start of the `Post Restore` phase
purge-last-accessed: 86400
# except the version with the `primary-key`, if it exists
purge-primary-key: never
# always save the cache
save-always: true
chmod 600 ~/.ssh/id_ed25519 - 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-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
EOF
cat >>~/.ssh/config <<END - name: Use alternative Nix binary caches if specified
Host website if: ${{ (env.ATTIC_ENDPOINT != '') && (env.ATTIC_PUBLIC_KEY != '') }}
HostName ${{ secrets.WEB_UPLOAD_SSH_HOSTNAME }} run: |
User ${{ secrets.WEB_UPLOAD_SSH_USERNAME }} sudo tee -a "${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf" > /dev/null <<EOF
IdentityFile ~/.ssh/id_ed25519 extra-substituters = ${{ env.ATTIC_ENDPOINT }}
StrictHostKeyChecking yes extra-trusted-public-keys = ${{ env.ATTIC_PUBLIC_KEY }}
AddKeysToAgent no EOF
ForwardX11 no
BatchMode yes
END
echo "Checking connection"
ssh -q website "echo test" || ssh -q website "echo test"
echo "SSH_WEBSITE=1" >> "$GITHUB_ENV"
- name: Prepare build environment - name: Prepare build environment
run: | run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc" echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow direnv allow
nix develop .#all-features --command true --impure nix develop .#all-features --command true
# use sccache for Rust
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@main
# use rust-cache # use rust-cache
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
# 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/') }}
with: with:
cache-all-crates: "true" cache-all-crates: "true"
cache-on-failure: "true"
cache-targets: "true"
- name: Build static ${{ matrix.target }}-all-features - name: Build static ${{ matrix.target }}
run: | run: |
if [[ ${{ matrix.target }} == "x86_64-linux-musl" ]] CARGO_DEB_TARGET_TUPLE=$(echo ${{ matrix.target }} | grep -o -E '^([^-]*-){3}[^-]*')
then
CARGO_DEB_TARGET_TUPLE="x86_64-unknown-linux-musl"
elif [[ ${{ matrix.target }} == "aarch64-linux-musl" ]]
then
CARGO_DEB_TARGET_TUPLE="aarch64-unknown-linux-musl"
fi
SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
# 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 .#static-${{ matrix.target }}-all-features bin/nix-build-and-cache just .#static-${{ matrix.target }}-all-features
if [[ $? == 0 ]]; then
SUCCESS=true
break
else
sleep 3
fi
done
if [[ $SUCCESS == "false" ]]; then
exit 1
fi
mkdir -v -p target/release/ mkdir -v -p target/release/
mkdir -v -p target/$CARGO_DEB_TARGET_TUPLE/release/ mkdir -v -p target/$CARGO_DEB_TARGET_TUPLE/release/
cp -v -f result/bin/conduwuit target/release/conduwuit cp -v -f result/bin/conduit target/release/conduwuit
cp -v -f result/bin/conduwuit target/$CARGO_DEB_TARGET_TUPLE/release/conduwuit cp -v -f result/bin/conduit target/$CARGO_DEB_TARGET_TUPLE/release/conduwuit
direnv exec . cargo deb --verbose --no-build --no-strip -p conduwuit --target=$CARGO_DEB_TARGET_TUPLE --output target/release/${{ matrix.target }}.deb # -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/conduwuit static-${{ matrix.target }}
mv -v target/release/${{ matrix.target }}.deb ${{ matrix.target }}.deb mv -v target/release/${{ matrix.target }}.deb ${{ matrix.target }}.deb
- name: Build static x86_64-linux-musl-all-features-x86_64-haswell-optimised
if: ${{ matrix.target == 'x86_64-linux-musl' }}
run: |
CARGO_DEB_TARGET_TUPLE="x86_64-unknown-linux-musl"
SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
bin/nix-build-and-cache just .#static-x86_64-linux-musl-all-features-x86_64-haswell-optimised
mkdir -v -p target/release/
mkdir -v -p target/$CARGO_DEB_TARGET_TUPLE/release/
cp -v -f result/bin/conduwuit target/release/conduwuit
cp -v -f result/bin/conduwuit target/$CARGO_DEB_TARGET_TUPLE/release/conduwuit
direnv exec . cargo deb --verbose --no-build --no-strip -p conduwuit --target=$CARGO_DEB_TARGET_TUPLE --output target/release/x86_64-linux-musl-x86_64-haswell-optimised.deb
mv -v target/release/conduwuit static-x86_64-linux-musl-x86_64-haswell-optimised
mv -v target/release/x86_64-linux-musl-x86_64-haswell-optimised.deb x86_64-linux-musl-x86_64-haswell-optimised.deb
# quick smoke test of the x86_64 static release binary # quick smoke test of the x86_64 static release binary
- name: Quick smoke test the x86_64 static release binary - name: Run x86_64 static release binary
if: ${{ matrix.target == 'x86_64-linux-musl' }}
run: | run: |
# GH actions default runners are x86_64 only # GH actions default runners are x86_64 only
if file result/bin/conduwuit | grep x86-64; then if file result/bin/conduit | grep x86-64; then
result/bin/conduwuit --version result/bin/conduit --version
result/bin/conduwuit --help
result/bin/conduwuit -Oserver_name="'$(date -u +%s).local'" -Odatabase_path="'/tmp/$(date -u +%s)'" --execute "server admin-notice awawawawawawawawawawa" --execute "server memory-usage" --execute "server shutdown"
fi fi
- name: Build static debug ${{ matrix.target }}-all-features - name: Build static debug ${{ matrix.target }}
run: | run: |
if [[ ${{ matrix.target }} == "x86_64-linux-musl" ]] CARGO_DEB_TARGET_TUPLE=$(echo ${{ matrix.target }} | grep -o -E '^([^-]*-){3}[^-]*')
then
CARGO_DEB_TARGET_TUPLE="x86_64-unknown-linux-musl"
elif [[ ${{ matrix.target }} == "aarch64-linux-musl" ]]
then
CARGO_DEB_TARGET_TUPLE="aarch64-unknown-linux-musl"
fi
SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
# 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 .#static-${{ matrix.target }}-all-features-debug bin/nix-build-and-cache just .#static-${{ matrix.target }}-all-features-debug
if [[ $? == 0 ]]; then
SUCCESS=true
break
else
sleep 3
fi
done
if [[ $SUCCESS == "false" ]]; then
exit 1
fi
# > warning: dev profile is not supported and will be a hard error in the future. cargo-deb is for making releases, and it doesn't make sense to use it with dev profiles. # > warning: dev profile is not supported and will be a hard error in the future. cargo-deb is for making releases, and it doesn't make sense to use it with dev profiles.
# so we need to coerce cargo-deb into thinking this is a release binary # so we need to coerce cargo-deb into thinking this is a release binary
mkdir -v -p target/release/ mkdir -v -p target/release/
mkdir -v -p target/$CARGO_DEB_TARGET_TUPLE/release/ mkdir -v -p target/$CARGO_DEB_TARGET_TUPLE/release/
cp -v -f result/bin/conduwuit target/release/conduwuit cp -v -f result/bin/conduit target/release/conduwuit
cp -v -f result/bin/conduwuit target/$CARGO_DEB_TARGET_TUPLE/release/conduwuit cp -v -f result/bin/conduit target/$CARGO_DEB_TARGET_TUPLE/release/conduwuit
direnv exec . cargo deb --verbose --no-build --no-strip -p conduwuit --target=$CARGO_DEB_TARGET_TUPLE --output target/release/${{ matrix.target }}-debug.deb # -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 }}-debug.deb
mv -v target/release/conduwuit static-${{ matrix.target }}-debug mv -v target/release/conduwuit static-${{ matrix.target }}-debug
mv -v target/release/${{ matrix.target }}-debug.deb ${{ matrix.target }}-debug.deb mv -v target/release/${{ matrix.target }}-debug.deb ${{ matrix.target }}-debug.deb
@@ -317,8 +373,8 @@ jobs:
- name: Run x86_64 static debug binary - name: Run x86_64 static debug binary
run: | run: |
# GH actions default runners are x86_64 only # GH actions default runners are x86_64 only
if file result/bin/conduwuit | grep x86-64; then if file result/bin/conduit | grep x86-64; then
result/bin/conduwuit --version result/bin/conduit --version
fi fi
# check validity of produced deb package, invalid debs will error on these commands # check validity of produced deb package, invalid debs will error on these commands
@@ -331,22 +387,14 @@ jobs:
dpkg-deb --info ${{ matrix.target }}.deb dpkg-deb --info ${{ matrix.target }}.deb
dpkg-deb --info ${{ matrix.target }}-debug.deb dpkg-deb --info ${{ matrix.target }}-debug.deb
- name: Upload static-x86_64-linux-musl-all-features-x86_64-haswell-optimised to GitHub - name: Upload static-${{ matrix.target }}
uses: actions/upload-artifact@v4
if: ${{ matrix.target == 'x86_64-linux-musl' }}
with:
name: static-x86_64-linux-musl-x86_64-haswell-optimised
path: static-x86_64-linux-musl-x86_64-haswell-optimised
if-no-files-found: error
- name: Upload static-${{ matrix.target }}-all-features to GitHub
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: static-${{ matrix.target }} name: static-${{ matrix.target }}
path: static-${{ matrix.target }} path: static-${{ matrix.target }}
if-no-files-found: error if-no-files-found: error
- name: Upload static deb ${{ matrix.target }}-all-features to GitHub - name: Upload deb ${{ matrix.target }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: deb-${{ matrix.target }} name: deb-${{ matrix.target }}
@@ -354,42 +402,14 @@ jobs:
if-no-files-found: error if-no-files-found: error
compression-level: 0 compression-level: 0
- name: Upload static-x86_64-linux-musl-all-features-x86_64-haswell-optimised to webserver - name: Upload static-${{ matrix.target }}-debug
if: ${{ matrix.target == 'x86_64-linux-musl' }}
run: |
if [ ! -z $SSH_WEBSITE ]; then
chmod +x static-x86_64-linux-musl-x86_64-haswell-optimised
scp static-x86_64-linux-musl-x86_64-haswell-optimised website:/var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/static-x86_64-linux-musl-x86_64-haswell-optimised
fi
- name: Upload static-${{ matrix.target }}-all-features to webserver
run: |
if [ ! -z $SSH_WEBSITE ]; then
chmod +x static-${{ matrix.target }}
scp static-${{ matrix.target }} website:/var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/static-${{ matrix.target }}
fi
- name: Upload static deb x86_64-linux-musl-all-features-x86_64-haswell-optimised to webserver
if: ${{ matrix.target == 'x86_64-linux-musl' }}
run: |
if [ ! -z $SSH_WEBSITE ]; then
scp x86_64-linux-musl-x86_64-haswell-optimised.deb website:/var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/x86_64-linux-musl-x86_64-haswell-optimised.deb
fi
- name: Upload static deb ${{ matrix.target }}-all-features to webserver
run: |
if [ ! -z $SSH_WEBSITE ]; then
scp ${{ matrix.target }}.deb website:/var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/${{ matrix.target }}.deb
fi
- name: Upload static-${{ matrix.target }}-debug-all-features to GitHub
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: static-${{ matrix.target }}-debug name: static-${{ matrix.target }}-debug
path: static-${{ matrix.target }}-debug path: static-${{ matrix.target }}-debug
if-no-files-found: error if-no-files-found: error
- name: Upload static deb ${{ matrix.target }}-debug-all-features to GitHub - name: Upload deb ${{ matrix.target }}-debug
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: deb-${{ matrix.target }}-debug name: deb-${{ matrix.target }}-debug
@@ -397,46 +417,51 @@ jobs:
if-no-files-found: error if-no-files-found: error
compression-level: 0 compression-level: 0
- name: Upload static-${{ matrix.target }}-debug-all-features to webserver - name: Build OCI image ${{ matrix.target }}
run: |
if [ ! -z $SSH_WEBSITE ]; then
scp static-${{ matrix.target }}-debug website:/var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/static-${{ matrix.target }}-debug
fi
- name: Upload static deb ${{ matrix.target }}-debug-all-features to webserver
run: |
if [ ! -z $SSH_WEBSITE ]; then
scp ${{ matrix.target }}-debug.deb website:/var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/${{ matrix.target }}-debug.deb
fi
- name: Build OCI image ${{ matrix.target }}-all-features
run: | 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 .#oci-image-${{ matrix.target }}-all-features bin/nix-build-and-cache just .#oci-image-${{ matrix.target }}-all-features
if [[ $? == 0 ]]; then
SUCCESS=true
break
else
sleep 3
fi
done
if [[ $SUCCESS == "false" ]]; then
exit 1
fi
cp -v -f result oci-image-${{ matrix.target }}.tar.gz cp -v -f result oci-image-${{ matrix.target }}.tar.gz
- name: Build OCI image x86_64-linux-musl-all-features-x86_64-haswell-optimised - name: Build debug OCI image ${{ matrix.target }}
if: ${{ matrix.target == 'x86_64-linux-musl' }}
run: |
bin/nix-build-and-cache just .#oci-image-x86_64-linux-musl-all-features-x86_64-haswell-optimised
cp -v -f result oci-image-x86_64-linux-musl-all-features-x86_64-haswell-optimised.tar.gz
- name: Build debug OCI image ${{ matrix.target }}-all-features
run: | 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 .#oci-image-${{ matrix.target }}-all-features-debug bin/nix-build-and-cache just .#oci-image-${{ matrix.target }}-all-features-debug
if [[ $? == 0 ]]; then
SUCCESS=true
break
else
sleep 3
fi
done
if [[ $SUCCESS == "false" ]]; then
exit 1
fi
cp -v -f result oci-image-${{ matrix.target }}-debug.tar.gz cp -v -f result oci-image-${{ matrix.target }}-debug.tar.gz
- name: Upload OCI image x86_64-linux-musl-all-features-x86_64-haswell-optimised to GitHub - name: Upload OCI image ${{ matrix.target }}
if: ${{ matrix.target == 'x86_64-linux-musl' }}
uses: actions/upload-artifact@v4
with:
name: oci-image-x86_64-linux-musl-all-features-x86_64-haswell-optimised
path: oci-image-x86_64-linux-musl-all-features-x86_64-haswell-optimised.tar.gz
if-no-files-found: error
compression-level: 0
- name: Upload OCI image ${{ matrix.target }}-all-features to GitHub
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: oci-image-${{ matrix.target }} name: oci-image-${{ matrix.target }}
@@ -444,7 +469,7 @@ jobs:
if-no-files-found: error if-no-files-found: error
compression-level: 0 compression-level: 0
- name: Upload OCI image ${{ matrix.target }}-debug-all-features to GitHub - name: Upload OCI image ${{ matrix.target }}-debug
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: oci-image-${{ matrix.target }}-debug name: oci-image-${{ matrix.target }}-debug
@@ -452,54 +477,27 @@ jobs:
if-no-files-found: error if-no-files-found: error
compression-level: 0 compression-level: 0
- name: Upload OCI image x86_64-linux-musl-all-features-x86_64-haswell-optimised.tar.gz to webserver
if: ${{ matrix.target == 'x86_64-linux-musl' }}
run: |
if [ ! -z $SSH_WEBSITE ]; then
scp oci-image-x86_64-linux-musl-all-features-x86_64-haswell-optimised.tar.gz website:/var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/oci-image-x86_64-linux-musl-all-features-x86_64-haswell-optimised.tar.gz
fi
- name: Upload OCI image ${{ matrix.target }}-all-features to webserver
run: |
if [ ! -z $SSH_WEBSITE ]; then
scp oci-image-${{ matrix.target }}.tar.gz website:/var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/oci-image-${{ matrix.target }}.tar.gz
fi
- name: Upload OCI image ${{ matrix.target }}-debug-all-features to webserver
run: |
if [ ! -z $SSH_WEBSITE ]; then
scp oci-image-${{ matrix.target }}-debug.tar.gz website:/var/www/girlboss.ceo/~strawberry/conduwuit/ci-bins/${WEBSERVER_DIR_NAME}/oci-image-${{ matrix.target }}-debug.tar.gz
fi
variables:
outputs:
github_repository: ${{ steps.var.outputs.github_repository }}
runs-on: self-hosted
steps:
- name: Setting global variables
uses: actions/github-script@v7
id: var
with:
script: |
core.setOutput('github_repository', '${{ github.repository }}'.toLowerCase())
docker: docker:
name: Docker publish name: Docker publish
runs-on: self-hosted runs-on: ubuntu-latest
needs: [build, variables, tests] needs: build
permissions: if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' || (github.event.pull_request.draft != true)) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && github.event.pull_request.user.login != 'renovate[bot]'
packages: write
contents: read
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]'
env: env:
DOCKER_HUB_REPO: docker.io/${{ needs.variables.outputs.github_repository }} DOCKER_ARM64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
GHCR_REPO: ghcr.io/${{ needs.variables.outputs.github_repository }} DOCKER_AMD64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
GLCR_REPO: registry.gitlab.com/conduwuit/conduwuit DOCKER_TAG: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
UNIQUE_TAG: ${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }} DOCKER_BRANCH: docker.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
BRANCH_TAG: ${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }} GHCR_ARM64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
GHCR_AMD64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
GHCR_TAG: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
GHCR_BRANCH: ghcr.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
GLCR_ARM64: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
GLCR_AMD64: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
GLCR_TAG: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
GLCR_BRANCH: registry.gitlab.com/conduwuit/conduwuit:${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
GHCR_ENABLED: "${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) && 'true' || 'false' }}"
steps: steps:
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
@@ -526,192 +524,104 @@ jobs:
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with:
pattern: "oci*"
- name: Move OCI images into position - name: Move OCI images into position
run: | run: |
mv -v oci-image-x86_64-linux-musl-all-features-x86_64-haswell-optimised/*.tar.gz oci-image-amd64-haswell-optimised.tar.gz mv -v oci-image-x86_64-unknown-linux-musl/*.tar.gz oci-image-amd64.tar.gz
mv -v oci-image-x86_64-linux-musl/*.tar.gz oci-image-amd64.tar.gz mv -v oci-image-aarch64-unknown-linux-musl/*.tar.gz oci-image-arm64v8.tar.gz
mv -v oci-image-aarch64-linux-musl/*.tar.gz oci-image-arm64v8.tar.gz mv -v oci-image-x86_64-unknown-linux-musl-debug/*.tar.gz oci-image-amd64-debug.tar.gz
mv -v oci-image-x86_64-linux-musl-debug/*.tar.gz oci-image-amd64-debug.tar.gz mv -v oci-image-aarch64-unknown-linux-musl-debug/*.tar.gz oci-image-arm64v8-debug.tar.gz
mv -v oci-image-aarch64-linux-musl-debug/*.tar.gz oci-image-arm64v8-debug.tar.gz
- name: Load and push amd64 haswell image
run: |
docker load -i oci-image-amd64-haswell-optimised.tar.gz
if [ ! -z $DOCKERHUB_TOKEN ]; then
docker tag $(docker images -q conduwuit:main) ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-haswell
docker push ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-haswell
fi
if [ $GHCR_ENABLED = "true" ]; then
docker tag $(docker images -q conduwuit:main) ${GHCR_REPO}:${UNIQUE_TAG}-haswell
docker push ${GHCR_REPO}:${UNIQUE_TAG}-haswell
fi
if [ ! -z $GITLAB_TOKEN ]; then
docker tag $(docker images -q conduwuit:main) ${GLCR_REPO}:${UNIQUE_TAG}-haswell
docker push ${GLCR_REPO}:${UNIQUE_TAG}-haswell
fi
- name: Load and push amd64 image - name: Load and push amd64 image
if: ${{ (vars.DOCKER_USERNAME != '') && (env.DOCKERHUB_TOKEN != '') }}
run: | run: |
docker load -i oci-image-amd64.tar.gz docker load -i oci-image-amd64.tar.gz
if [ ! -z $DOCKERHUB_TOKEN ]; then docker tag $(docker images -q conduit:main) ${{ env.DOCKER_AMD64 }}
docker tag $(docker images -q conduwuit:main) ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-amd64 docker tag $(docker images -q conduit:main) ${{ env.GHCR_AMD64 }}
docker push ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-amd64 docker tag $(docker images -q conduit:main) ${{ env.GLCR_AMD64 }}
fi docker push ${{ env.DOCKER_AMD64 }}
if [ $GHCR_ENABLED = "true" ]; then docker push ${{ env.GHCR_AMD64 }}
docker tag $(docker images -q conduwuit:main) ${GHCR_REPO}:${UNIQUE_TAG}-amd64 docker push ${{ env.GLCR_AMD64 }}
docker push ${GHCR_REPO}:${UNIQUE_TAG}-amd64
fi
if [ ! -z $GITLAB_TOKEN ]; then
docker tag $(docker images -q conduwuit:main) ${GLCR_REPO}:${UNIQUE_TAG}-amd64
docker push ${GLCR_REPO}:${UNIQUE_TAG}-amd64
fi
- name: Load and push arm64 image - name: Load and push arm64 image
if: ${{ (vars.DOCKER_USERNAME != '') && (env.DOCKERHUB_TOKEN != '') }}
run: | run: |
docker load -i oci-image-arm64v8.tar.gz docker load -i oci-image-arm64v8.tar.gz
if [ ! -z $DOCKERHUB_TOKEN ]; then docker tag $(docker images -q conduit:main) ${{ env.DOCKER_ARM64 }}
docker tag $(docker images -q conduwuit:main) ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-arm64v8 docker tag $(docker images -q conduit:main) ${{ env.GHCR_ARM64 }}
docker push ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-arm64v8 docker tag $(docker images -q conduit:main) ${{ env.GLCR_ARM64 }}
fi docker push ${{ env.DOCKER_ARM64 }}
if [ $GHCR_ENABLED = "true" ]; then docker push ${{ env.GHCR_ARM64 }}
docker tag $(docker images -q conduwuit:main) ${GHCR_REPO}:${UNIQUE_TAG}-arm64v8 docker push ${{ env.GLCR_ARM64 }}
docker push ${GHCR_REPO}:${UNIQUE_TAG}-arm64v8
fi
if [ ! -z $GITLAB_TOKEN ]; then
docker tag $(docker images -q conduwuit:main) ${GLCR_REPO}:${UNIQUE_TAG}-arm64v8
docker push ${GLCR_REPO}:${UNIQUE_TAG}-arm64v8
fi
- name: Load and push amd64 debug image - name: Load and push amd64 debug image
if: ${{ (vars.DOCKER_USERNAME != '') && (env.DOCKERHUB_TOKEN != '') }}
run: | run: |
docker load -i oci-image-amd64-debug.tar.gz docker load -i oci-image-amd64-debug.tar.gz
if [ ! -z $DOCKERHUB_TOKEN ]; then docker tag $(docker images -q conduit:main) ${{ env.DOCKER_AMD64 }}-debug
docker tag $(docker images -q conduwuit:main) ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-amd64-debug docker tag $(docker images -q conduit:main) ${{ env.GHCR_AMD64 }}-debug
docker push ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-amd64-debug docker tag $(docker images -q conduit:main) ${{ env.GLCR_AMD64 }}-debug
fi docker push ${{ env.DOCKER_AMD64 }}-debug
if [ $GHCR_ENABLED = "true" ]; then docker push ${{ env.GHCR_AMD64 }}-debug
docker tag $(docker images -q conduwuit:main) ${GHCR_REPO}:${UNIQUE_TAG}-amd64-debug docker push ${{ env.GLCR_AMD64 }}-debug
docker push ${GHCR_REPO}:${UNIQUE_TAG}-amd64-debug
fi
if [ ! -z $GITLAB_TOKEN ]; then
docker tag $(docker images -q conduwuit:main) ${GLCR_REPO}:${UNIQUE_TAG}-amd64-debug
docker push ${GLCR_REPO}:${UNIQUE_TAG}-amd64-debug
fi
- name: Load and push arm64 debug image - name: Load and push arm64 debug image
if: ${{ (vars.DOCKER_USERNAME != '') && (env.DOCKERHUB_TOKEN != '') }}
run: | run: |
docker load -i oci-image-arm64v8-debug.tar.gz docker load -i oci-image-arm64v8-debug.tar.gz
if [ ! -z $DOCKERHUB_TOKEN ]; then docker tag $(docker images -q conduit:main) ${{ env.DOCKER_ARM64 }}-debug
docker tag $(docker images -q conduwuit:main) ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-arm64v8-debug docker tag $(docker images -q conduit:main) ${{ env.GHCR_ARM64 }}-debug
docker push ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-arm64v8-debug docker tag $(docker images -q conduit:main) ${{ env.GLCR_ARM64 }}-debug
fi docker push ${{ env.DOCKER_ARM64 }}-debug
if [ $GHCR_ENABLED = "true" ]; then docker push ${{ env.GHCR_ARM64 }}-debug
docker tag $(docker images -q conduwuit:main) ${GHCR_REPO}:${UNIQUE_TAG}-arm64v8-debug docker push ${{ env.GLCR_ARM64 }}-debug
docker push ${GHCR_REPO}:${UNIQUE_TAG}-arm64v8-debug
fi
if [ ! -z $GITLAB_TOKEN ]; then
docker tag $(docker images -q conduwuit:main) ${GLCR_REPO}:${UNIQUE_TAG}-arm64v8-debug
docker push ${GLCR_REPO}:${UNIQUE_TAG}-arm64v8-debug
fi
- name: Create Docker haswell manifests
run: |
# Dockerhub Container Registry
if [ ! -z $DOCKERHUB_TOKEN ]; then
docker manifest create ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-haswell --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-haswell
docker manifest create ${DOCKER_HUB_REPO}:${BRANCH_TAG}-haswell --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-haswell
fi
# GitHub Container Registry
if [ $GHCR_ENABLED = "true" ]; then
docker manifest create ${GHCR_REPO}:${UNIQUE_TAG}-haswell --amend ${GHCR_REPO}:${UNIQUE_TAG}-haswell
docker manifest create ${GHCR_REPO}:${BRANCH_TAG}-haswell --amend ${GHCR_REPO}:${UNIQUE_TAG}-haswell
fi
# GitLab Container Registry
if [ ! -z $GITLAB_TOKEN ]; then
docker manifest create ${GLCR_REPO}:${UNIQUE_TAG}-haswell --amend ${GLCR_REPO}:${UNIQUE_TAG}-haswell
docker manifest create ${GLCR_REPO}:${BRANCH_TAG}-haswell --amend ${GLCR_REPO}:${UNIQUE_TAG}-haswell
fi
- name: Create Docker combined manifests - name: Create Docker combined manifests
run: | run: |
# Dockerhub Container Registry # Dockerhub Container Registry
if [ ! -z $DOCKERHUB_TOKEN ]; then docker manifest create ${{ env.DOCKER_TAG }} --amend ${{ env.DOCKER_ARM64 }} --amend ${{ env.DOCKER_AMD64 }}
docker manifest create ${DOCKER_HUB_REPO}:${UNIQUE_TAG} --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-arm64v8 --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-amd64 docker manifest create ${{ env.DOCKER_BRANCH }} --amend ${{ env.DOCKER_ARM64 }} --amend ${{ env.DOCKER_AMD64 }}
docker manifest create ${DOCKER_HUB_REPO}:${BRANCH_TAG} --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-arm64v8 --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-amd64
fi
# GitHub Container Registry # GitHub Container Registry
if [ $GHCR_ENABLED = "true" ]; then docker manifest create ${{ env.GHCR_TAG }} --amend ${{ env.GHCR_ARM64 }} --amend ${{ env.GHCR_AMD64 }}
docker manifest create ${GHCR_REPO}:${UNIQUE_TAG} --amend ${GHCR_REPO}:${UNIQUE_TAG}-arm64v8 --amend ${GHCR_REPO}:${UNIQUE_TAG}-amd64 docker manifest create ${{ env.GHCR_BRANCH }} --amend ${{ env.GHCR_ARM64 }} --amend ${{ env.GHCR_AMD64 }}
docker manifest create ${GHCR_REPO}:${BRANCH_TAG} --amend ${GHCR_REPO}:${UNIQUE_TAG}-arm64v8 --amend ${GHCR_REPO}:${UNIQUE_TAG}-amd64
fi
# GitLab Container Registry # GitLab Container Registry
if [ ! -z $GITLAB_TOKEN ]; then docker manifest create ${{ env.GLCR_TAG }} --amend ${{ env.GLCR_ARM64 }} --amend ${{ env.GLCR_AMD64 }}
docker manifest create ${GLCR_REPO}:${UNIQUE_TAG} --amend ${GLCR_REPO}:${UNIQUE_TAG}-arm64v8 --amend ${GLCR_REPO}:${UNIQUE_TAG}-amd64 docker manifest create ${{ env.GLCR_BRANCH }} --amend ${{ env.GLCR_ARM64 }} --amend ${{ env.GLCR_AMD64 }}
docker manifest create ${GLCR_REPO}:${BRANCH_TAG} --amend ${GLCR_REPO}:${UNIQUE_TAG}-arm64v8 --amend ${GLCR_REPO}:${UNIQUE_TAG}-amd64
fi
- name: Create Docker combined debug manifests - name: Create Docker combined debug manifests
run: | run: |
# Dockerhub Container Registry # Dockerhub Container Registry
if [ ! -z $DOCKERHUB_TOKEN ]; then docker manifest create ${{ env.DOCKER_TAG }}-debug --amend ${{ env.DOCKER_ARM64 }}-debug --amend ${{ env.DOCKER_AMD64 }}-debug
docker manifest create ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-debug --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-arm64v8-debug --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-amd64-debug docker manifest create ${{ env.DOCKER_BRANCH }}-debug --amend ${{ env.DOCKER_ARM64 }}-debug --amend ${{ env.DOCKER_AMD64 }}-debug
docker manifest create ${DOCKER_HUB_REPO}:${BRANCH_TAG}-debug --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-arm64v8-debug --amend ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-amd64-debug
fi
# GitHub Container Registry # GitHub Container Registry
if [ $GHCR_ENABLED = "true" ]; then docker manifest create ${{ env.GHCR_TAG }}-debug --amend ${{ env.GHCR_ARM64 }}-debug --amend ${{ env.GHCR_AMD64 }}-debug
docker manifest create ${GHCR_REPO}:${UNIQUE_TAG}-debug --amend ${GHCR_REPO}:${UNIQUE_TAG}-arm64v8-debug --amend ${GHCR_REPO}:${UNIQUE_TAG}-amd64-debug docker manifest create ${{ env.GHCR_BRANCH }}-debug --amend ${{ env.GHCR_ARM64 }}-debug --amend ${{ env.GHCR_AMD64 }}-debug
docker manifest create ${GHCR_REPO}:${BRANCH_TAG}-debug --amend ${GHCR_REPO}:${UNIQUE_TAG}-arm64v8-debug --amend ${GHCR_REPO}:${UNIQUE_TAG}-amd64-debug
fi
# GitLab Container Registry # GitLab Container Registry
if [ ! -z $GITLAB_TOKEN ]; then docker manifest create ${{ env.GLCR_TAG }}-debug --amend ${{ env.GLCR_ARM64 }}-debug --amend ${{ env.GLCR_AMD64 }}-debug
docker manifest create ${GLCR_REPO}:${UNIQUE_TAG}-debug --amend ${GLCR_REPO}:${UNIQUE_TAG}-arm64v8-debug --amend ${GLCR_REPO}:${UNIQUE_TAG}-amd64-debug docker manifest create ${{ env.GLCR_BRANCH }}-debug --amend ${{ env.GLCR_ARM64 }}-debug --amend ${{ env.GLCR_AMD64 }}-debug
docker manifest create ${GLCR_REPO}:${BRANCH_TAG}-debug --amend ${GLCR_REPO}:${UNIQUE_TAG}-arm64v8-debug --amend ${GLCR_REPO}:${UNIQUE_TAG}-amd64-debug
fi
- name: Push manifests to Docker registries - name: Push manifests to Docker registries
if: ${{ (vars.DOCKER_USERNAME != '') && (env.DOCKERHUB_TOKEN != '') }}
run: | run: |
if [ ! -z $DOCKERHUB_TOKEN ]; then docker manifest push ${{ env.DOCKER_TAG }}
docker manifest push ${DOCKER_HUB_REPO}:${UNIQUE_TAG} docker manifest push ${{ env.DOCKER_BRANCH }}
docker manifest push ${DOCKER_HUB_REPO}:${BRANCH_TAG} docker manifest push ${{ env.GHCR_TAG }}
docker manifest push ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-debug docker manifest push ${{ env.GHCR_BRANCH }}
docker manifest push ${DOCKER_HUB_REPO}:${BRANCH_TAG}-debug docker manifest push ${{ env.GLCR_TAG }}
docker manifest push ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-haswell docker manifest push ${{ env.GLCR_BRANCH }}
docker manifest push ${DOCKER_HUB_REPO}:${BRANCH_TAG}-haswell docker manifest push ${{ env.DOCKER_TAG }}-debug
fi docker manifest push ${{ env.DOCKER_BRANCH }}-debug
if [ $GHCR_ENABLED = "true" ]; then docker manifest push ${{ env.GHCR_TAG }}-debug
docker manifest push ${GHCR_REPO}:${UNIQUE_TAG} docker manifest push ${{ env.GHCR_BRANCH }}-debug
docker manifest push ${GHCR_REPO}:${BRANCH_TAG} docker manifest push ${{ env.GLCR_TAG }}-debug
docker manifest push ${GHCR_REPO}:${UNIQUE_TAG}-debug docker manifest push ${{ env.GLCR_BRANCH }}-debug
docker manifest push ${GHCR_REPO}:${BRANCH_TAG}-debug
docker manifest push ${GHCR_REPO}:${UNIQUE_TAG}-haswell
docker manifest push ${GHCR_REPO}:${BRANCH_TAG}-haswell
fi
if [ ! -z $GITLAB_TOKEN ]; then
docker manifest push ${GLCR_REPO}:${UNIQUE_TAG}
docker manifest push ${GLCR_REPO}:${BRANCH_TAG}
docker manifest push ${GLCR_REPO}:${UNIQUE_TAG}-debug
docker manifest push ${GLCR_REPO}:${BRANCH_TAG}-debug
docker manifest push ${GLCR_REPO}:${UNIQUE_TAG}-haswell
docker manifest push ${GLCR_REPO}:${BRANCH_TAG}-haswell
fi
- name: Add Image Links to Job Summary - name: Add Image Links to Job Summary
if: ${{ (vars.DOCKER_USERNAME != '') && (env.DOCKERHUB_TOKEN != '') }}
run: | run: |
if [ ! -z $DOCKERHUB_TOKEN ]; then echo "- \`docker pull ${{ env.DOCKER_TAG }}\`" >> $GITHUB_STEP_SUMMARY
echo "- \`docker pull ${DOCKER_HUB_REPO}:${UNIQUE_TAG}\`" >> $GITHUB_STEP_SUMMARY echo "- \`docker pull ${{ env.GHCR_TAG }}\`" >> $GITHUB_STEP_SUMMARY
echo "- \`docker pull ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-debug\`" >> $GITHUB_STEP_SUMMARY echo "- \`docker pull ${{ env.GLCR_TAG }}\`" >> $GITHUB_STEP_SUMMARY
echo "- \`docker pull ${DOCKER_HUB_REPO}:${UNIQUE_TAG}-haswell\`" >> $GITHUB_STEP_SUMMARY echo "- \`docker pull ${{ env.DOCKER_TAG }}-debug\`" >> $GITHUB_STEP_SUMMARY
fi echo "- \`docker pull ${{ env.GHCR_TAG }}-debug\`" >> $GITHUB_STEP_SUMMARY
if [ $GHCR_ENABLED = "true" ]; then echo "- \`docker pull ${{ env.GLCR_TAG }}-debug\`" >> $GITHUB_STEP_SUMMARY
echo "- \`docker pull ${GHCR_REPO}:${UNIQUE_TAG}\`" >> $GITHUB_STEP_SUMMARY
echo "- \`docker pull ${GHCR_REPO}:${UNIQUE_TAG}-debug\`" >> $GITHUB_STEP_SUMMARY
echo "- \`docker pull ${GHCR_REPO}:${UNIQUE_TAG}-haswell\`" >> $GITHUB_STEP_SUMMARY
fi
if [ ! -z $GITLAB_TOKEN ]; then
echo "- \`docker pull ${GLCR_REPO}:${UNIQUE_TAG}\`" >> $GITHUB_STEP_SUMMARY
echo "- \`docker pull ${GLCR_REPO}:${UNIQUE_TAG}-debug\`" >> $GITHUB_STEP_SUMMARY
echo "- \`docker pull ${GLCR_REPO}:${UNIQUE_TAG}-haswell\`" >> $GITHUB_STEP_SUMMARY
fi
@@ -1,41 +0,0 @@
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
+86 -14
View File
@@ -24,11 +24,8 @@ env:
# Get error output from nix that we can actually use, and use our binary caches for the earlier CI steps # Get error output from nix that we can actually use, and use our binary caches for the earlier CI steps
NIX_CONFIG: | NIX_CONFIG: |
show-trace = true show-trace = true
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 https://nix-community.cachix.org https://crane.cachix.org 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= nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= crane.cachix.org-1:8Scfpmn9w+hGdXH/Q9tTLiYAE/2dnJYRJP7kl80GuRk= 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. # 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. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
@@ -36,12 +33,10 @@ concurrency:
group: "pages" group: "pages"
cancel-in-progress: false cancel-in-progress: false
permissions: {}
jobs: jobs:
docs: docs:
name: Documentation and GitHub Pages name: Documentation and GitHub Pages
runs-on: self-hosted runs-on: ubuntu-latest
permissions: permissions:
pages: write pages: write
@@ -52,24 +47,86 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }} url: ${{ steps.deployment.outputs.page_url }}
steps: steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
- name: Sync repository - name: Sync repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup GitHub Pages - name: Setup GitHub Pages
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') && (github.event_name != 'pull_request') if: github.event_name != 'pull_request'
uses: actions/configure-pages@v5 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
- name: Restore and cache Nix store
uses: nix-community/cache-nix-action@v5.1.0
with:
# restore and save a cache using this key
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/.lock') }}
# if there's no cache hit, restore a cache by this prefix
restore-prefixes-first-match: nix-${{ runner.os }}-
# collect garbage until Nix store size (in bytes) is at most this number
# before trying to save a new cache
gc-max-store-size-linux: 2073741824
# do purge caches
purge: true
# purge all versions of the cache
purge-prefixes: nix-${{ runner.os }}-
# created more than this number of seconds ago relative to the start of the `Post Restore` phase
purge-last-accessed: 86400
# except the version with the `primary-key`, if it exists
purge-primary-key: never
# always save the cache
save-always: true
- name: Apply Nix binary cache configuration
run: |
sudo tee -a "${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf" > /dev/null <<EOF
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit https://cache.lix.systems https://conduwuit.cachix.org
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
EOF
- 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 }}
EOF
- name: Prepare build environment - name: Prepare build environment
run: | run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc" echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow direnv allow
nix develop --command true nix develop --command true
- name: Cache CI dependencies - name: Cache CI dependencies
run: | 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 bin/nix-build-and-cache ci
if [[ $? == 0 ]]; then
SUCCESS=true
break
else
sleep 3
fi
done
if [[ $SUCCESS == "false" ]]; then
exit 1
fi
- name: Run lychee and markdownlint - name: Run lychee and markdownlint
run: | run: |
@@ -78,10 +135,25 @@ jobs:
- name: Build documentation (book) - name: Build documentation (book)
run: | 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 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
cp -r --dereference result public cp -r --dereference result public
chmod u+w -R public
- name: Upload generated documentation (book) as normal artifact - name: Upload generated documentation (book) as normal artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -93,12 +165,12 @@ jobs:
compression-level: 0 compression-level: 0
- name: Upload generated documentation (book) as GitHub Pages artifact - name: Upload generated documentation (book) as GitHub Pages artifact
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') && (github.event_name != 'pull_request') if: github.event_name != 'pull_request'
uses: actions/upload-pages-artifact@v3 uses: actions/upload-pages-artifact@v3
with: with:
path: public path: public
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
if: (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') && (github.event_name != 'pull_request') if: github.event_name != 'pull_request'
id: deployment id: deployment
uses: actions/deploy-pages@v4 uses: actions/deploy-pages@v4
-118
View File
@@ -1,118 +0,0 @@
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
@@ -0,0 +1,42 @@
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* .nfs*
# Rust # Rust
/target /target/
### vscode ### ### vscode ###
.vscode/* .vscode/*
+16 -24
View File
@@ -10,13 +10,6 @@ variables:
FF_USE_FASTZIP: true FF_USE_FASTZIP: true
# Print progress reports for cache and artifact transfers # Print progress reports for cache and artifact transfers
TRANSFER_METER_FREQUENCY: 5s 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 # Avoid duplicate pipelines
# See: https://docs.gitlab.com/ee/ci/yaml/workflow.html#switch-between-branch-pipelines-and-merge-request-pipelines # See: https://docs.gitlab.com/ee/ci/yaml/workflow.html#switch-between-branch-pipelines-and-merge-request-pipelines
@@ -30,9 +23,6 @@ workflow:
before_script: before_script:
# Enable nix-command and flakes # 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 "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 # 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 - if command -v nix > /dev/null; then echo "extra-substituters = https://attic.kennel.juneis.dog/conduwuit" >> /etc/nix/nix.conf; fi
@@ -45,6 +35,10 @@ 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_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 - 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 # 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-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 - 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
@@ -53,8 +47,6 @@ 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-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-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 # Install direnv and nix-direnv
- if command -v nix > /dev/null; then nix-env -iA nixpkgs.direnv nixpkgs.nix-direnv; fi - if command -v nix > /dev/null; then nix-env -iA nixpkgs.direnv nixpkgs.nix-direnv; fi
@@ -66,7 +58,7 @@ before_script:
ci: ci:
stage: ci stage: ci
image: nixos/nix:2.24.9 image: nixos/nix:2.23.3
script: script:
# Cache CI dependencies # Cache CI dependencies
- ./bin/nix-build-and-cache ci - ./bin/nix-build-and-cache ci
@@ -91,31 +83,31 @@ ci:
artifacts: artifacts:
stage: artifacts stage: artifacts
image: nixos/nix:2.24.9 image: nixos/nix:2.23.3
script: script:
- ./bin/nix-build-and-cache just .#static-x86_64-linux-musl - ./bin/nix-build-and-cache just .#static-x86_64-unknown-linux-musl
- cp result/bin/conduit x86_64-linux-musl - cp result/bin/conduit x86_64-unknown-linux-musl
- mkdir -p target/release - mkdir -p target/release
- cp result/bin/conduit target/release - cp result/bin/conduit target/release
- direnv exec . cargo deb --no-build --no-strip - direnv exec . cargo deb --no-build --no-strip
- mv target/debian/*.deb x86_64-linux-musl.deb - mv target/debian/*.deb x86_64-unknown-linux-musl.deb
# Since the OCI image package is based on the binary package, this has the # 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 # 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 # deploying with Nix can leverage this fact by adding our binary cache to
# their systems. # their systems.
# #
# Note that although we have an `oci-image-x86_64-linux-musl` # Note that although we have an `oci-image-x86_64-unknown-linux-musl`
# output, we don't build it because it would be largely redundant to this # output, we don't build it because it would be largely redundant to this
# one since it's all containerized anyway. # one since it's all containerized anyway.
- ./bin/nix-build-and-cache just .#oci-image - ./bin/nix-build-and-cache just .#oci-image
- cp result oci-image-amd64.tar.gz - cp result oci-image-amd64.tar.gz
- ./bin/nix-build-and-cache just .#static-aarch64-linux-musl - ./bin/nix-build-and-cache just .#static-aarch64-unknown-linux-musl
- cp result/bin/conduit aarch64-linux-musl - cp result/bin/conduit aarch64-unknown-linux-musl
- ./bin/nix-build-and-cache just .#oci-image-aarch64-linux-musl - ./bin/nix-build-and-cache just .#oci-image-aarch64-unknown-linux-musl
- cp result oci-image-arm64v8.tar.gz - cp result oci-image-arm64v8.tar.gz
- ./bin/nix-build-and-cache just .#book - ./bin/nix-build-and-cache just .#book
@@ -123,9 +115,9 @@ artifacts:
- cp -r --dereference result public - cp -r --dereference result public
artifacts: artifacts:
paths: paths:
- x86_64-linux-musl - x86_64-unknown-linux-musl
- aarch64-linux-musl - aarch64-unknown-linux-musl
- x86_64-linux-musl.deb - x86_64-unknown-linux-musl.deb
- oci-image-amd64.tar.gz - oci-image-amd64.tar.gz
- oci-image-arm64v8.tar.gz - oci-image-arm64v8.tar.gz
- public - public
+20 -73
View File
@@ -1,46 +1,29 @@
# Contributing guide # Contributing guide
This page is for about contributing to conduwuit. The 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 If you would like to work on an [issue][issues] that is not assigned, preferably ask in the Matrix room first at [#conduwuit:puppygock.gay][conduwuit-matrix], and comment on it.
ask in the Matrix room first at [#conduwuit:puppygock.gay][conduwuit-matrix],
and comment on it.
### Linting and Formatting ### Linting and Formatting
It is mandatory all your changes satisfy the lints (clippy, rustc, rustdoc, etc) It is mandatory all your changes satisfy the lints (clippy, rustc, rustdoc, etc) and your code is formatted via the **nightly** `cargo fmt`. A lot of the `rustfmt.toml` features depend on nightly toolchain. It would be ideal if they weren't nightly-exclusive features, but they currently still are. CI's rustfmt uses nightly.
and your code is formatted via the **nightly** `cargo fmt`. A lot of the
`rustfmt.toml` features depend on nightly toolchain. It would be ideal if they
weren't nightly-exclusive features, but they currently still are. CI's rustfmt
uses nightly.
If you need to allow a lint, please make sure it's either obvious as to why If you need to allow a lint, please make sure it's either obvious as to why (e.g. clippy saying redundant clone but it's actually required) or it has a comment saying why. Do not write inefficient code for the sake of satisfying lints. If a lint is wrong and provides a more inefficient solution or suggestion, allow the lint and mention that in a comment.
(e.g. clippy saying redundant clone but it's actually required) or it has a
comment saying why. Do not write inefficient code for the sake of satisfying
lints. If a lint is wrong and provides a more inefficient solution or
suggestion, allow the lint and mention that in a comment.
### Running CI tests locally ### Running CI tests locally
conduwuit's CI for tests, linting, formatting, audit, etc use conduwuit's CI for tests, linting, formatting, audit, etc use [`engage`][engage]. engage can be installed from nixpkgs or `cargo install engage`. conduwuit's Nix flake devshell has the nixpkgs engage with `direnv`. Use `engage --help` for more usage details.
[`engage`][engage]. engage can be installed from nixpkgs or `cargo install
engage`. conduwuit's Nix flake devshell has the nixpkgs engage with `direnv`.
Use `engage --help` for more usage details.
To test, format, lint, etc that CI would do, install engage, allow the `.envrc` To test, format, lint, etc that CI would do, install engage, allow the `.envrc` file using `direnv allow`, and run `engage`.
file using `direnv allow`, and run `engage`.
All of the tasks are defined at the [engage.toml][engage.toml] file. You can All of the tasks are defined at the [engage.toml][engage.toml] file. You can view all of them neatly by running `engage list`
view all of them neatly by running `engage list`
If you would like to run only a specific engage task group, use `just`: If you would like to run only a specific engage task group, use `just`:
- `engage just <group>` - `engage just <group>`
- Example: `engage just lints` - Example: `engage just lints`
If you would like to run a specific engage task in a specific group, use `just If you would like to run a specific engage task in a specific group, use `just <GROUP> [TASK]`: `engage just lints cargo-fmt`
<GROUP> [TASK]`: `engage just lints cargo-fmt`
The following binaries are used in [`engage.toml`][engage.toml]: The following binaries are used in [`engage.toml`][engage.toml]:
@@ -60,79 +43,43 @@ The following binaries are used in [`engage.toml`][engage.toml]:
### Matrix tests ### Matrix tests
CI runs [Complement][complement], but currently does not fail if results from CI runs [Complement][complement], but currently does not fail if results from the checked-in results differ with the new results. If your changes are done to fix Matrix tests, note that in your pull request. If more Complement tests start failing from your changes, please review the logs (they are uploaded as artifacts) and determine if they're intended or not.
the checked-in results differ with the new results. If your changes are done to
fix Matrix tests, note that in your pull request. If more Complement tests start
failing from your changes, please review the logs (they are uploaded as
artifacts) and determine if they're intended or not.
If you'd like to run Complement locally using Nix, see the 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. [Sytest][sytest] support will come soon.
### Writing documentation ### Writing documentation
conduwuit's website uses [`mdbook`][mdbook] and deployed via CI using GitHub conduwuit's website uses [`mdbook`][mdbook] and deployed via CI using GitHub Pages in the [`documentation.yml`][documentation.yml] workflow file with Nix's mdbook in the devshell. All documentation is in the `docs/` directory at the top level. The compiled mdbook website is also uploaded as an artifact.
Pages in the [`documentation.yml`][documentation.yml] workflow file with Nix's
mdbook in the devshell. All documentation is in the `docs/` directory at the top
level. The compiled mdbook website is also uploaded as an artifact.
To build the documentation using Nix, run: `bin/nix-build-and-cache just .#book` To build the documentation using Nix, run: `bin/nix-build-and-cache just .#book`
The output of the mdbook generation is in `result/`. mdbooks can be opened in The output of the mdbook generation is in `result/`. mdbooks can be opened in your browser from the individual HTML files without any web server needed.
your browser from the individual HTML files without any web server needed.
### Inclusivity and Diversity ### Inclusivity and Diversity
All **MUST** code and write with inclusivity and diversity in mind. See the All **MUST** code and write with inclusivity and diversity in mind. See the [following page by Google on writing inclusive code and documentation](https://developers.google.com/style/inclusive-documentation).
[following page by Google on writing inclusive code and
documentation](https://developers.google.com/style/inclusive-documentation).
This **EXPLICITLY** forbids usage of terms like "blacklist"/"whitelist" and This **EXPLICITLY** forbids usage of terms like "blacklist"/"whitelist" and "master"/"slave", [forbids gender-specific words and phrases](https://developers.google.com/style/pronouns#gender-neutral-pronouns), forbids ableist language like "sanity-check", "cripple", or "insane", and forbids culture-specific language (e.g. US-only holidays or cultures).
"master"/"slave", [forbids gender-specific words and
phrases](https://developers.google.com/style/pronouns#gender-neutral-pronouns),
forbids ableist language like "sanity-check", "cripple", or "insane", and
forbids culture-specific language (e.g. US-only holidays or cultures).
No exceptions are allowed. Dependencies that may use these terms are allowed but No exceptions are allowed. Dependencies that may use these terms are allowed but [do not replicate the name in your functions or variables](https://developers.google.com/style/inclusive-documentation#write-around).
[do not replicate the name in your functions or
variables](https://developers.google.com/style/inclusive-documentation#write-around).
In addition to language, write and code with the user experience in mind. This In addition to language, write and code with the user experience in mind. This is software that intends to be used by everyone, so make it easy and comfortable for everyone to use. 🏳️‍⚧️
is software that intends to be used by everyone, so make it easy and comfortable
for everyone to use. 🏳️‍⚧️
### Variable, comment, function, etc standards ### Variable, comment, function, etc standards
Rust's default style and standards with regards to [function names, variable Rust's default style and standards with regards to [function names, variable names, comments](https://rust-lang.github.io/api-guidelines/naming.html), etc applies here.
names, comments](https://rust-lang.github.io/api-guidelines/naming.html), etc
applies here.
### Creating pull requests ### Creating pull requests
Please try to keep contributions to the GitHub. While the mirrors of conduwuit Please try to keep contributions to the GitHub. While the mirrors of conduwuit allow for pull/merge requests, there is no guarantee I will see them in a timely manner. Additionally, please mark WIP or unfinished or incomplete PRs as drafts. This prevents me from having to ping once in a while to double check the status of it, especially when the CI completed successfully and everything so it *looks* done.
allow for pull/merge requests, there is no guarantee I will see them in a timely
manner. Additionally, please mark WIP or unfinished or incomplete PRs as drafts.
This prevents me from having to ping once in a while to double check the status
of it, especially when the CI completed successfully and everything so it
*looks* done.
If you open a pull request on one of the mirrors, it is your responsibility to If you open a pull request on one of the mirrors, it is your responsibility to inform me about its existence. In the future I may try to solve this with more repo bots in the conduwuit Matrix room. There is no mailing list or email-patch support on the sr.ht mirror, but if you'd like to email me a git patch you can do so at `strawberry@puppygock.gay`.
inform me about its existence. In the future I may try to solve this with more
repo bots in the conduwuit Matrix room. There is no mailing list or email-patch
support on the sr.ht mirror, but if you'd like to email me a git patch you can
do so at `strawberry@puppygock.gay`.
Direct all PRs/MRs to the `main` branch. Direct all PRs/MRs to the `main` branch.
By sending a pull request or patch, you are agreeing that your changes are 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.
allowed to be licenced under the Apache-2.0 licence and all of your conduct is
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 [issues]: https://github.com/girlbossceo/conduwuit/issues
[conduwuit-matrix]: https://matrix.to/#/#conduwuit:puppygock.gay [conduwuit-matrix]: https://matrix.to/#/#conduwuit:puppygock.gay
Generated
+1085 -2122
View File
File diff suppressed because it is too large Load Diff
+143 -294
View File
@@ -7,70 +7,42 @@ default-members = ["src/*"]
[workspace.package] [workspace.package]
authors = [ authors = [
"June Clementine Strawberry <june@girlboss.ceo>", "strawberry <strawberry@puppygock.gay>",
"strawberry <strawberry@puppygock.gay>", # woof "timokoesters <timo@koesters.xyz>",
"Jason Volk <jason@zemos.net>",
] ]
categories = ["network-programming"] categories = ["network-programming"]
description = "a very cool Matrix chat homeserver written in Rust" description = "a very cool fork of Conduit, a Matrix homeserver written in Rust"
edition = "2024" edition = "2021"
homepage = "https://conduwuit.puppyirl.gay/" homepage = "https://conduwuit.puppyirl.gay/"
keywords = ["chat", "matrix", "networking", "server", "uwu"] keywords = ["chat", "matrix", "server", "uwu"]
license = "Apache-2.0" license = "Apache-2.0"
# See also `rust-toolchain.toml` # See also `rust-toolchain.toml`
readme = "README.md" readme = "README.md"
repository = "https://github.com/girlbossceo/conduwuit" repository = "https://github.com/girlbossceo/conduwuit"
rust-version = "1.86.0" rust-version = "1.80.0"
version = "0.5.0" version = "0.4.6"
[workspace.metadata.crane] [workspace.metadata.crane]
name = "conduwuit" name = "conduit"
[workspace.dependencies.arrayvec]
version = "0.7.6"
features = ["serde"]
[workspace.dependencies.smallvec]
version = "1.14.0"
features = [
"const_generics",
"const_new",
"serde",
"union",
"write",
]
[workspace.dependencies.smallstr]
version = "0.3"
features = ["ffi", "std", "union"]
[workspace.dependencies.const-str] [workspace.dependencies.const-str]
version = "0.6.2" version = "0.5.7"
[workspace.dependencies.ctor]
version = "0.2.9"
[workspace.dependencies.cargo_toml]
version = "0.21"
default-features = false
features = ["features"]
[workspace.dependencies.toml]
version = "0.8.14"
default-features = false
features = ["parse"]
[workspace.dependencies.sanitize-filename] [workspace.dependencies.sanitize-filename]
version = "0.6.0" version = "0.5.0"
[workspace.dependencies.jsonwebtoken]
version = "9.3.0"
[workspace.dependencies.base64] [workspace.dependencies.base64]
version = "0.22.1" version = "0.22.1"
default-features = false
# used for TURN server authentication # used for TURN server authentication
[workspace.dependencies.hmac] [workspace.dependencies.hmac]
version = "0.12.1" version = "0.12.1"
default-features = false
[workspace.dependencies.sha-1]
version = "0.10.1"
# used for checking if an IP is in specific subnets / CIDR ranges easier # used for checking if an IP is in specific subnets / CIDR ranges easier
[workspace.dependencies.ipaddress] [workspace.dependencies.ipaddress]
@@ -81,19 +53,19 @@ version = "0.8.5"
# Used for the http request / response body type for Ruma endpoints used with reqwest # Used for the http request / response body type for Ruma endpoints used with reqwest
[workspace.dependencies.bytes] [workspace.dependencies.bytes]
version = "1.10.1" version = "1.6.1"
[workspace.dependencies.http-body-util] [workspace.dependencies.http-body-util]
version = "0.1.3" version = "0.1.1"
[workspace.dependencies.http] [workspace.dependencies.http]
version = "1.3.1" version = "1.1.0"
[workspace.dependencies.regex] [workspace.dependencies.regex]
version = "1.11.1" version = "1.10.4"
[workspace.dependencies.axum] [workspace.dependencies.axum]
version = "0.7.9" version = "0.7.5"
default-features = false default-features = false
features = [ features = [
"form", "form",
@@ -106,47 +78,35 @@ features = [
] ]
[workspace.dependencies.axum-extra] [workspace.dependencies.axum-extra]
version = "0.9.6" version = "0.9.3"
default-features = false default-features = false
features = ["typed-header", "tracing"] features = ["typed-header", "tracing"]
[workspace.dependencies.axum-server] [workspace.dependencies.axum-server]
version = "0.7.2" version = "0.6.0"
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] [workspace.dependencies.axum-client-ip]
version = "0.6.1" version = "0.6.0"
[workspace.dependencies.tower] [workspace.dependencies.tower]
version = "0.5.2" version = "0.4.13"
default-features = false
features = ["util"] features = ["util"]
[workspace.dependencies.tower-http] [workspace.dependencies.tower-http]
version = "0.6.2" version = "0.5.2"
default-features = false
features = [ features = [
"add-extension", "add-extension",
"catch-panic",
"cors", "cors",
"sensitive-headers", "sensitive-headers",
"set-header", "set-header",
"timeout",
"trace", "trace",
"util", "util",
"catch-panic",
] ]
[workspace.dependencies.rustls]
version = "0.23.25"
default-features = false
features = ["aws_lc_rs"]
[workspace.dependencies.reqwest] [workspace.dependencies.reqwest]
version = "0.12.15" version = "0.12.4"
default-features = false default-features = false
features = [ features = [
"rustls-tls-native-roots", "rustls-tls-native-roots",
@@ -156,13 +116,11 @@ features = [
] ]
[workspace.dependencies.serde] [workspace.dependencies.serde]
version = "1.0.219" version = "1.0.204"
default-features = false
features = ["rc"] features = ["rc"]
[workspace.dependencies.serde_json] [workspace.dependencies.serde_json]
version = "1.0.140" version = "1.0.120"
default-features = false
features = ["raw_value"] features = ["raw_value"]
# Used for appservice registration files # Used for appservice registration files
@@ -183,9 +141,9 @@ version = "0.5.3"
features = ["alloc", "rand"] features = ["alloc", "rand"]
default-features = false default-features = false
# Used to generate thumbnails for images & blurhashes # Used to generate thumbnails for images
[workspace.dependencies.image] [workspace.dependencies.image]
version = "0.25.5" version = "0.25.1"
default-features = false default-features = false
features = [ features = [
"jpeg", "jpeg",
@@ -194,56 +152,43 @@ features = [
"webp", "webp",
] ]
[workspace.dependencies.blurhash]
version = "0.2.3"
default-features = false
features = [
"fast-linear-to-srgb",
"image",
]
# logging # logging
[workspace.dependencies.log] [workspace.dependencies.log]
version = "0.4.27" version = "0.4.21"
default-features = false default-features = false
[workspace.dependencies.tracing] [workspace.dependencies.tracing]
version = "0.1.41" version = "0.1.40"
default-features = false default-features = false
[workspace.dependencies.tracing-subscriber] [workspace.dependencies.tracing-subscriber]
version = "0.3.19" version = "0.3.18"
default-features = false features = ["env-filter"]
features = ["env-filter", "std", "tracing", "tracing-log", "ansi", "fmt"]
[workspace.dependencies.tracing-core] [workspace.dependencies.tracing-core]
version = "0.1.33" version = "0.1.32"
default-features = false
# for URL previews # for URL previews
[workspace.dependencies.webpage] [workspace.dependencies.webpage]
version = "2.0.1" version = "2.0.1"
default-features = false default-features = false
# used for conduwuit's CLI and admin room command parsing # used for conduit's CLI and admin room command parsing
[workspace.dependencies.clap] [workspace.dependencies.clap]
version = "4.5.35" version = "4.5.9"
default-features = false default-features = false
features = [ features = [
"derive",
"env",
"error-context",
"help",
"std", "std",
"string", "derive",
"help",
"usage", "usage",
"error-context",
"string",
] ]
[workspace.dependencies.futures] [workspace.dependencies.futures-util]
version = "0.3.31" version = "0.3.30"
default-features = false default-features = false
features = ["std", "async-await"]
[workspace.dependencies.tokio] [workspace.dependencies.tokio]
version = "1.44.2" version = "1.39.1"
default-features = false
features = [ features = [
"fs", "fs",
"net", "net",
@@ -253,19 +198,17 @@ features = [
"time", "time",
"rt-multi-thread", "rt-multi-thread",
"io-util", "io-util",
"tracing",
] ]
[workspace.dependencies.tokio-metrics] [workspace.dependencies.tokio-metrics]
version = "0.4.0" version = "0.3.1"
[workspace.dependencies.libloading] [workspace.dependencies.libloading]
version = "0.8.6" version = "0.8.5"
# Validating urls in config, was already a transitive dependency # Validating urls in config, was already a transitive dependency
[workspace.dependencies.url] [workspace.dependencies.url]
version = "2.5.4" version = "2.5.0"
default-features = false
features = ["serde"] features = ["serde"]
# standard date and time tools # standard date and time tools
@@ -275,8 +218,7 @@ features = ["alloc", "std"]
default-features = false default-features = false
[workspace.dependencies.hyper] [workspace.dependencies.hyper]
version = "1.6.0" version = "1.4.1"
default-features = false
features = [ features = [
"server", "server",
"http1", "http1",
@@ -284,64 +226,52 @@ features = [
] ]
[workspace.dependencies.hyper-util] [workspace.dependencies.hyper-util]
version = "0.1.11" version = "0.1.6"
default-features = false
features = [ features = [
"client",
"server-auto", "server-auto",
"server-graceful", "server-graceful",
"service",
"tokio", "tokio",
] ]
# to support multiple variations of setting a config option # to support multiple variations of setting a config option
[workspace.dependencies.either] [workspace.dependencies.either]
version = "1.15.0" version = "1.11.0"
default-features = false
features = ["serde"] features = ["serde"]
# Used for reading the configuration from conduwuit.toml & environment variables # Used for reading the configuration from conduwuit.toml & environment variables
[workspace.dependencies.figment] [workspace.dependencies.figment]
version = "0.10.19" version = "0.10.18"
default-features = false
features = ["env", "toml"] features = ["env", "toml"]
[workspace.dependencies.hickory-resolver] [workspace.dependencies.hickory-resolver]
version = "0.25.1" version = "0.24.1"
default-features = false default-features = false
features = [
"serde",
"system-config",
"tokio",
]
# Used for conduwuit::Error type # Used for conduit::Error type
[workspace.dependencies.thiserror] [workspace.dependencies.thiserror]
version = "2.0.12" version = "1.0.63"
default-features = false
# Used when hashing the state # Used when hashing the state
[workspace.dependencies.ring] [workspace.dependencies.ring]
version = "0.17.14" version = "0.17.8"
default-features = false
# Used to make working with iterators easier, was already a transitive depdendency # Used to make working with iterators easier, was already a transitive depdendency
[workspace.dependencies.itertools] [workspace.dependencies.itertools]
version = "0.14.0" version = "0.13.0"
# to parse user-friendly time durations in admin commands # to parse user-friendly time durations in admin commands
#TODO: overlaps chrono? #TODO: overlaps chrono?
[workspace.dependencies.cyborgtime] [workspace.dependencies.cyborgtime]
version = "2.1.1" version = "2.1.1"
# used for MPSC channels # used to replace the channels of the tokio runtime
[workspace.dependencies.loole] [workspace.dependencies.loole]
version = "0.4.0" version = "0.3.1"
# used for MPMC channels
[workspace.dependencies.async-channel]
version = "2.3.1"
[workspace.dependencies.async-trait] [workspace.dependencies.async-trait]
version = "0.1.88" version = "0.1.81"
[workspace.dependencies.lru-cache] [workspace.dependencies.lru-cache]
version = "0.1.2" version = "0.1.2"
@@ -350,7 +280,7 @@ version = "0.1.2"
[workspace.dependencies.ruma] [workspace.dependencies.ruma]
git = "https://github.com/girlbossceo/ruwuma" git = "https://github.com/girlbossceo/ruwuma"
#branch = "conduwuit-changes" #branch = "conduwuit-changes"
rev = "920148dca1076454ca0ca5d43b5ce1aa708381d4" rev = "c76e2873c1593a3308d4ba3e0e4a1db65acf8536"
features = [ features = [
"compat", "compat",
"rand", "rand",
@@ -359,9 +289,10 @@ features = [
"federation-api", "federation-api",
"markdown", "markdown",
"push-gateway-api-c", "push-gateway-api-c",
"state-res",
"server-util",
"unstable-exhaustive-types", "unstable-exhaustive-types",
"ring-compat", "ring-compat",
"compat-upload-signatures",
"identifiers-validation", "identifiers-validation",
"unstable-unspecified", "unstable-unspecified",
"unstable-msc2448", "unstable-msc2448",
@@ -370,42 +301,32 @@ features = [
"unstable-msc2870", "unstable-msc2870",
"unstable-msc3026", "unstable-msc3026",
"unstable-msc3061", "unstable-msc3061",
"unstable-msc3245",
"unstable-msc3266", "unstable-msc3266",
"unstable-msc3381", # polls
"unstable-msc3489", # beacon / live location
"unstable-msc3575", "unstable-msc3575",
"unstable-msc3930", # polls push rules
"unstable-msc4075",
"unstable-msc4095",
"unstable-msc4121", "unstable-msc4121",
"unstable-msc4125", "unstable-msc4125",
"unstable-msc4186",
"unstable-msc4203", # sending to-device events to appservices
"unstable-msc4210", # remove legacy mentions
"unstable-extensible-events", "unstable-extensible-events",
"unstable-pdu",
] ]
[workspace.dependencies.rust-rocksdb] [workspace.dependencies.rust-rocksdb]
git = "https://github.com/girlbossceo/rust-rocksdb-zaidoon1" path = "deps/rust-rocksdb"
rev = "1c267e0bf0cc7b7702e9a329deccd89de79ef4c3" package = "rust-rocksdb-uwu"
default-features = false
features = [ features = [
"multi-threaded-cf", "multi-threaded-cf",
"mt_static", "mt_static",
"lz4", "lz4",
"zstd", "zstd",
"zlib",
"bzip2", "bzip2",
] ]
# 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.6"
# optional SHA256 media keys feature
[workspace.dependencies.sha2] [workspace.dependencies.sha2]
version = "0.10.8" 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 # optional opentelemetry, performance measurements, flamegraphs, etc for performance measurements and monitoring
[workspace.dependencies.opentelemetry] [workspace.dependencies.opentelemetry]
@@ -427,7 +348,7 @@ features = ["rt-tokio"]
# optional sentry metrics for crash/panic reporting # optional sentry metrics for crash/panic reporting
[workspace.dependencies.sentry] [workspace.dependencies.sentry]
version = "0.37.0" version = "0.34.0"
default-features = false default-features = false
features = [ features = [
"backtrace", "backtrace",
@@ -443,44 +364,34 @@ features = [
] ]
[workspace.dependencies.sentry-tracing] [workspace.dependencies.sentry-tracing]
version = "0.37.0" version = "0.34.0"
[workspace.dependencies.sentry-tower] [workspace.dependencies.sentry-tower]
version = "0.37.0" version = "0.34.0"
# jemalloc usage # jemalloc usage
# locked to 0.5.4 due to static binary linking breakage
[workspace.dependencies.tikv-jemalloc-sys] [workspace.dependencies.tikv-jemalloc-sys]
git = "https://github.com/girlbossceo/jemallocator" version = "=0.6.0"
rev = "82af58d6a13ddd5dcdc7d4e91eae3b63292995b8"
default-features = false default-features = false
features = [ features = ["stats", "unprefixed_malloc_on_supported_platforms"]
"background_threads_runtime_support",
"unprefixed_malloc_on_supported_platforms",
]
[workspace.dependencies.tikv-jemallocator] [workspace.dependencies.tikv-jemallocator]
git = "https://github.com/girlbossceo/jemallocator" version = "=0.5.4"
rev = "82af58d6a13ddd5dcdc7d4e91eae3b63292995b8"
default-features = false default-features = false
features = [ features = ["stats", "unprefixed_malloc_on_supported_platforms"]
"background_threads_runtime_support",
"unprefixed_malloc_on_supported_platforms",
]
[workspace.dependencies.tikv-jemalloc-ctl] [workspace.dependencies.tikv-jemalloc-ctl]
git = "https://github.com/girlbossceo/jemallocator" version = "=0.5.4"
rev = "82af58d6a13ddd5dcdc7d4e91eae3b63292995b8"
default-features = false default-features = false
features = ["use_std"] features = ["use_std"]
[workspace.dependencies.console-subscriber] [workspace.dependencies.console-subscriber]
version = "0.4" version = "0.3"
[workspace.dependencies.nix] [workspace.dependencies.nix]
version = "0.29.0" version = "0.29.0"
default-features = false
features = ["resource"] features = ["resource"]
[workspace.dependencies.sd-notify] [workspace.dependencies.sd-notify]
version = "0.4.5" version = "0.4.1"
default-features = false
[workspace.dependencies.hardened_malloc-rs] [workspace.dependencies.hardened_malloc-rs]
version = "0.1.2" version = "0.1.2"
@@ -492,49 +403,16 @@ features = [
] ]
[workspace.dependencies.rustyline-async] [workspace.dependencies.rustyline-async]
version = "0.4.3" version = "0.4.2"
default-features = false default-features = false
[workspace.dependencies.termimad] [workspace.dependencies.termimad]
version = "0.31.2" version = "0.29.4"
default-features = false default-features = false
[workspace.dependencies.checked_ops] [workspace.dependencies.checked_ops]
version = "0.1" version = "0.1"
[workspace.dependencies.syn]
version = "2.0"
default-features = false
features = ["full", "extra-traits"]
[workspace.dependencies.quote]
version = "1.0"
[workspace.dependencies.proc-macro2]
version = "1.0"
[workspace.dependencies.bytesize]
version = "2.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.26.3"
features = ["std"]
[workspace.dependencies.minicbor-serde]
version = "0.4.1"
features = ["std"]
[workspace.dependencies.maplit]
version = "1.0.2"
# #
# Patches # Patches
@@ -545,87 +423,63 @@ version = "1.0.2"
# https://github.com/girlbossceo/tracing/commit/b348dca742af641c47bc390261f60711c2af573c # https://github.com/girlbossceo/tracing/commit/b348dca742af641c47bc390261f60711c2af573c
[patch.crates-io.tracing-subscriber] [patch.crates-io.tracing-subscriber]
git = "https://github.com/girlbossceo/tracing" git = "https://github.com/girlbossceo/tracing"
rev = "1e64095a8051a1adf0d1faa307f9f030889ec2aa" rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
[patch.crates-io.tracing] [patch.crates-io.tracing]
git = "https://github.com/girlbossceo/tracing" git = "https://github.com/girlbossceo/tracing"
rev = "1e64095a8051a1adf0d1faa307f9f030889ec2aa" rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
[patch.crates-io.tracing-core] [patch.crates-io.tracing-core]
git = "https://github.com/girlbossceo/tracing" git = "https://github.com/girlbossceo/tracing"
rev = "1e64095a8051a1adf0d1faa307f9f030889ec2aa" rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
[patch.crates-io.tracing-log] [patch.crates-io.tracing-log]
git = "https://github.com/girlbossceo/tracing" git = "https://github.com/girlbossceo/tracing"
rev = "1e64095a8051a1adf0d1faa307f9f030889ec2aa" rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
# fixes hyper graceful shutdowns [https://github.com/programatik29/axum-server/issues/114]
# https://github.com/girlbossceo/axum-server/commit/8e3368d899079818934e61cc9c839abcbbcada8a
[patch.crates-io.axum-server]
git = "https://github.com/girlbossceo/axum-server"
rev = "8e3368d899079818934e61cc9c839abcbbcada8a"
# adds a tab completion callback: https://github.com/girlbossceo/rustyline-async/commit/de26100b0db03e419a3d8e1dd26895d170d1fe50 # 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 # adds event for CTRL+\: https://github.com/girlbossceo/rustyline-async/commit/67d8c49aeac03a5ef4e818f663eaa94dd7bf339b
[patch.crates-io.rustyline-async] [patch.crates-io.rustyline-async]
git = "https://github.com/girlbossceo/rustyline-async" git = "https://github.com/girlbossceo/rustyline-async"
rev = "deaeb0694e2083f53d363b648da06e10fc13900c" rev = "de26100b0db03e419a3d8e1dd26895d170d1fe50"
# 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"
# adds affinity masks for selecting more than one core at a time
[patch.crates-io.core_affinity]
git = "https://github.com/girlbossceo/core_affinity_rs"
rev = "9c8e51510c35077df888ee72a36b4b05637147da"
# reverts hyperium#148 conflicting with our delicate federation resolver hooks
[patch.crates-io.hyper-util]
git = "https://github.com/girlbossceo/hyper-util"
rev = "e4ae7628fe4fcdacef9788c4c8415317a4489941"
# allows no-aaaa option in resolv.conf
# bumps rust edition and toolchain to 1.86.0 and 2024
# use sat_add on line number errors
[patch.crates-io.resolv-conf]
git = "https://github.com/girlbossceo/resolv-conf"
rev = "200e958941d522a70c5877e3d846f55b5586c68d"
# #
# Our crates # Our crates
# #
[workspace.dependencies.conduwuit-router] [workspace.dependencies.conduit-router]
package = "conduwuit_router" package = "conduit_router"
path = "src/router" path = "src/router"
default-features = false default-features = false
[workspace.dependencies.conduwuit-admin] [workspace.dependencies.conduit-admin]
package = "conduwuit_admin" package = "conduit_admin"
path = "src/admin" path = "src/admin"
default-features = false default-features = false
[workspace.dependencies.conduwuit-api] [workspace.dependencies.conduit-api]
package = "conduwuit_api" package = "conduit_api"
path = "src/api" path = "src/api"
default-features = false default-features = false
[workspace.dependencies.conduwuit-service] [workspace.dependencies.conduit-service]
package = "conduwuit_service" package = "conduit_service"
path = "src/service" path = "src/service"
default-features = false default-features = false
[workspace.dependencies.conduwuit-database] [workspace.dependencies.conduit-database]
package = "conduwuit_database" package = "conduit_database"
path = "src/database" path = "src/database"
default-features = false default-features = false
[workspace.dependencies.conduwuit-core] [workspace.dependencies.conduit-core]
package = "conduwuit_core" package = "conduit_core"
path = "src/core" path = "src/core"
default-features = false default-features = false
[workspace.dependencies.conduwuit-macros]
package = "conduwuit_macros"
path = "src/macros"
default-features = false
############################################################################### ###############################################################################
# #
# Release profiles # Release profiles
@@ -674,17 +528,7 @@ lto = "fat"
[profile.release-max-perf.build-override] [profile.release-max-perf.build-override]
inherits = "release-max-perf" inherits = "release-max-perf"
opt-level = 0 opt-level = 0
codegen-units = 32
#rustflags = [ #rustflags = [
# '-Crelocation-model=pic',
# '-Ctarget-feature=-crt-static',
# '-Clink-arg=-Wl,--no-gc-sections',
#]
[profile.release-max-perf.package.conduwuit_macros]
inherits = "release-max-perf.build-override"
#rustflags = [
# '-Crelocation-model=pic',
# '-Ctarget-feature=-crt-static', # '-Ctarget-feature=-crt-static',
#] #]
@@ -703,19 +547,20 @@ inherits = "release"
# To enable hot-reloading: # To enable hot-reloading:
# 1. Uncomment all of the rustflags here. # 1. Uncomment all of the rustflags here.
# 2. Uncomment crate-type=dylib in src/*/Cargo.toml # 2. Uncomment crate-type=dylib in src/*/Cargo.toml and deps/rust-rocksdb/Cargo.toml
# #
# opt-level, mir-opt-level, validate-mir are not known to interfere with reloading # opt-level, mir-opt-level, validate-mir are not known to interfere with reloading
# and can be raised if build times are tolerable. # and can be raised if build times are tolerable.
[profile.dev] [profile.dev]
debug = "full" debug = 1
opt-level = 0 opt-level = 0
panic = "unwind" panic = "unwind"
debug-assertions = true debug-assertions = true
incremental = true incremental = true
codegen-units = 64
#rustflags = [ #rustflags = [
# '--cfg', 'conduwuit_mods', # '--cfg', 'conduit_mods',
# '-Ztime-passes', # '-Ztime-passes',
# '-Zmir-opt-level=0', # '-Zmir-opt-level=0',
# '-Zvalidate-mir=false', # '-Zvalidate-mir=false',
@@ -732,11 +577,11 @@ incremental = true
# '-Clink-arg=-Wl,-z,lazy', # '-Clink-arg=-Wl,-z,lazy',
#] #]
[profile.dev.package.conduwuit_core] [profile.dev.package.conduit_core]
inherits = "dev" inherits = "dev"
incremental = false incremental = false
#rustflags = [ #rustflags = [
# '--cfg', 'conduwuit_mods', # '--cfg', 'conduit_mods',
# '-Ztime-passes', # '-Ztime-passes',
# '-Zmir-opt-level=0', # '-Zmir-opt-level=0',
# '-Ztls-model=initial-exec', # '-Ztls-model=initial-exec',
@@ -753,10 +598,11 @@ incremental = false
# '-Clink-arg=-Wl,-z,nodelete', # '-Clink-arg=-Wl,-z,nodelete',
#] #]
[profile.dev.package.conduwuit] [profile.dev.package.conduit]
inherits = "dev" inherits = "dev"
incremental = false
#rustflags = [ #rustflags = [
# '--cfg', 'conduwuit_mods', # '--cfg', 'conduit_mods',
# '-Ztime-passes', # '-Ztime-passes',
# '-Zmir-opt-level=0', # '-Zmir-opt-level=0',
# '-Zvalidate-mir=false', # '-Zvalidate-mir=false',
@@ -771,6 +617,27 @@ inherits = "dev"
# '-Clink-arg=-Wl,-z,lazy', # '-Clink-arg=-Wl,-z,lazy',
#] #]
[profile.dev.package.rust-rocksdb-uwu]
inherits = "dev"
debug = 'limited'
incremental = false
codegen-units = 1
opt-level = 'z'
#rustflags = [
# '--cfg', 'conduit_mods',
# '-Ztls-model=initial-exec',
# '-Cprefer-dynamic=true',
# '-Zstaticlib-prefer-dynamic=true',
# '-Zstaticlib-allow-rdylib-deps=true',
# '-Zpacked-bundled-libs=true',
# '-Zplt=true',
# '-Clink-arg=-Wl,--no-as-needed',
# '-Clink-arg=-Wl,--allow-shlib-undefined',
# '-Clink-arg=-Wl,-z,lazy',
# '-Clink-arg=-Wl,-z,nodlopen',
# '-Clink-arg=-Wl,-z,nodelete',
#]
[profile.dev.package.'*'] [profile.dev.package.'*']
inherits = "dev" inherits = "dev"
debug = 'limited' debug = 'limited'
@@ -778,7 +645,7 @@ incremental = false
codegen-units = 1 codegen-units = 1
opt-level = 'z' opt-level = 'z'
#rustflags = [ #rustflags = [
# '--cfg', 'conduwuit_mods', # '--cfg', 'conduit_mods',
# '-Ztls-model=global-dynamic', # '-Ztls-model=global-dynamic',
# '-Cprefer-dynamic=true', # '-Cprefer-dynamic=true',
# '-Zstaticlib-prefer-dynamic=true', # '-Zstaticlib-prefer-dynamic=true',
@@ -793,16 +660,12 @@ opt-level = 'z'
# primarily used for CI # primarily used for CI
[profile.test] [profile.test]
inherits = "dev" inherits = "dev"
strip = false
opt-level = 0
codegen-units = 16 codegen-units = 16
incremental = false incremental = false
[profile.test.package.'*'] [profile.test.package.'*']
inherits = "dev" inherits = "dev"
debug = 0 debug = 0
strip = false
opt-level = 0
codegen-units = 16 codegen-units = 16
incremental = false incremental = false
@@ -845,7 +708,6 @@ unused-qualifications = "warn"
#unused-results = "warn" # TODO #unused-results = "warn" # TODO
## some sadness ## some sadness
elided_named_lifetimes = "allow" # TODO!
let_underscore_drop = "allow" let_underscore_drop = "allow"
missing_docs = "allow" missing_docs = "allow"
# cfgs cannot be limited to expected cfgs or their de facto non-transitive/opt-in use-case e.g. # cfgs cannot be limited to expected cfgs or their de facto non-transitive/opt-in use-case e.g.
@@ -858,9 +720,6 @@ unused_crate_dependencies = "allow"
unsafe_code = "allow" unsafe_code = "allow"
variant_size_differences = "allow" variant_size_differences = "allow"
# we check nightly clippy lints
unknown_lints = "allow"
####################################### #######################################
# #
# Clippy lints # Clippy lints
@@ -894,22 +753,17 @@ significant_drop_tightening = { level = "allow", priority = 1 } # TODO
pedantic = { level = "warn", priority = -1 } pedantic = { level = "warn", priority = -1 }
## some sadness ## some sadness
too_long_first_doc_paragraph = { level = "allow", priority = 1 }
doc_markdown = { level = "allow", priority = 1 } doc_markdown = { level = "allow", priority = 1 }
enum_glob_use = { level = "allow", priority = 1 } enum_glob_use = { level = "allow", priority = 1 }
if_not_else = { level = "allow", priority = 1 } if_not_else = { level = "allow", priority = 1 }
if_then_some_else_none = { level = "allow", priority = 1 } if_then_some_else_none = { level = "allow", priority = 1 }
inline_always = { 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_docs_in_private_items = { level = "allow", priority = 1 }
missing_errors_doc = { level = "allow", priority = 1 } missing_errors_doc = { level = "allow", priority = 1 }
missing_panics_doc = { level = "allow", priority = 1 } missing_panics_doc = { level = "allow", priority = 1 }
module_name_repetitions = { level = "allow", priority = 1 } module_name_repetitions = { level = "allow", priority = 1 }
needless_continue = { level = "allow", priority = 1 }
no_effect_underscore_binding = { level = "allow", priority = 1 } no_effect_underscore_binding = { level = "allow", priority = 1 }
similar_names = { level = "allow", priority = 1 } similar_names = { level = "allow", priority = 1 }
single_match_else = { level = "allow", priority = 1 }
struct_excessive_bools = { level = "allow", priority = 1 }
struct_field_names = { level = "allow", priority = 1 } struct_field_names = { level = "allow", priority = 1 }
unnecessary_wraps = { level = "allow", priority = 1 } unnecessary_wraps = { level = "allow", priority = 1 }
unused_async = { level = "allow", priority = 1 } unused_async = { level = "allow", priority = 1 }
@@ -920,7 +774,7 @@ perf = { level = "warn", priority = -1 }
################### ###################
#restriction = "warn" #restriction = "warn"
#allow_attributes = "warn" # UNSTABLE allow_attributes = "warn"
arithmetic_side_effects = "warn" arithmetic_side_effects = "warn"
as_conversions = "warn" as_conversions = "warn"
as_underscore = "warn" as_underscore = "warn"
@@ -970,14 +824,9 @@ style = { level = "warn", priority = -1 }
## some sadness ## some sadness
# trivial assertions are quite alright # trivial assertions are quite alright
assertions_on_constants = { level = "allow", priority = 1 } assertions_on_constants = { level = "allow", priority = 1 }
module_inception = { level = "allow", priority = 1 }
obfuscated_if_else = { level = "allow", priority = 1 }
################### ###################
suspicious = { level = "warn", priority = -1 } suspicious = { level = "warn", priority = -1 }
## some sadness ## some sadness
let_underscore_future = { level = "allow", priority = 1 } let_underscore_future = { level = "allow", priority = 1 }
# rust doesnt understand conduwuit's custom log macros
literal_string_with_formatting_args = { level = "allow", priority = 1 }
+22 -128
View File
@@ -1,112 +1,40 @@
# conduwuit # conduwuit
[![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) `main` / stable: [![CI and Artifacts](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml)
[![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)
![GitHub Repo stars](https://img.shields.io/github/stars/girlbossceo/conduwuit?style=flat&color=%23fcba03&link=https%3A%2F%2Fgithub.com%2Fgirlbossceo%2Fconduwuit) ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/girlbossceo/conduwuit?style=flat&color=%2303fcb1&link=https%3A%2F%2Fgithub.com%2Fgirlbossceo%2Fconduwuit%2Fpulse%2Fmonthly) ![GitHub Created At](https://img.shields.io/github/created-at/girlbossceo/conduwuit) ![GitHub Sponsors](https://img.shields.io/github/sponsors/girlbossceo?color=%23fc03ba&link=https%3A%2F%2Fgithub.com%2Fsponsors%2Fgirlbossceo) ![GitHub License](https://img.shields.io/github/license/girlbossceo/conduwuit)
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/girlbossceo/conduwuit/latest?label=image%20size%20(latest)&link=https%3A%2F%2Fhub.docker.com%2Frepository%2Fdocker%2Fgirlbossceo%2Fconduwuit%2Ftags%3Fname%3Dlatest) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main?label=image%20size%20(main)&link=https%3A%2F%2Fhub.docker.com%2Frepository%2Fdocker%2Fgirlbossceo%2Fconduwuit%2Ftags%3Fname%3Dmain)
<!-- ANCHOR: catchphrase --> <!-- 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 --> <!-- ANCHOR_END: catchphrase -->
Visit the [conduwuit documentation](https://conduwuit.puppyirl.gay/) for more Visit the [Conduwuit documentation](https://conduwuit.puppyirl.gay/) for more information.
information and how to deploy/setup conduwuit.
<!-- ANCHOR: body --> <!-- ANCHOR: body -->
#### What is Matrix? #### What is Matrix?
[Matrix](https://matrix.org) is an open, federated, and extensible network for [Matrix](https://matrix.org) is an open network for secure and decentralized
decentralised communication. Users from any Matrix homeserver can chat with users from all communication. Users from every Matrix homeserver can chat with users from all
other homeservers over federation. Matrix is designed to be extensible and built on top of. other Matrix servers. You can even use bridges (also called Matrix Appservices)
You can even use bridges such as Matrix Appservices to communicate with users outside of Matrix, like a community on Discord. to communicate with users outside of Matrix, like a community on Discord.
#### What is the goal? #### What is the goal?
A high-performance, efficient, low-cost, and featureful Matrix homeserver that's An efficient Matrix homeserver that's easy to set up and just works. You can install
easy to set up and just works with minimal configuration needed. it on a mini-computer like the Raspberry Pi to host Matrix for your family,
friends or company.
#### Can I try it out? #### Can I try it out?
An official conduwuit server ran by me is available at transfem.dev An official conduwuit server ran by me is available at transfem.dev ([element.transfem.dev](https://element.transfem.dev) / [cinny.transfem.dev](https://cinny.transfem.dev))
([element.transfem.dev](https://element.transfem.dev) /
[cinny.transfem.dev](https://cinny.transfem.dev))
transfem.dev is a public homeserver that can be used, it is not a "test only transfem.dev is a public homeserver that can be used, it is not a "test only homeserver". This means there are rules, so please read the rules: [https://transfem.dev/homeserver_rules.txt](https://transfem.dev/homeserver_rules.txt)
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 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? #### What is the current status?
conduwuit is technically a hard fork of [Conduit](https://conduit.rs/), which is in beta. conduwuit is a hard fork of Conduit which is in beta, meaning you can join and participate in most
The beta status initially was inherited from Conduit, however the huge amount of Matrix rooms, but not all features are supported and you might run into bugs
codebase divergance, changes, fixes, and improvements have effectively made this from time to time.
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.
#### Where is the differences page?
conduwuit historically had a "differences" page that listed each and every single
different thing about conduwuit from Conduit, as a way to promote and advertise
conduwuit by showing significant amounts of work done. While this was feasible to
maintain back when the project was new in early-2024, this became impossible
very quickly and has unfortunately became heavily outdated, missing tons of things, etc.
It's difficult to list out what we do differently, what are our notable features, etc
when there's so many things and features and bug fixes and performance optimisations,
the list goes on. We simply recommend folks to just try out conduwuit, or ask us
what features you are looking for and if they're implemented in conduwuit.
#### 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 had drop-in migration/replacement support for Conduit for about 12 months before
bugs somewhere along the line broke it. Maintaining this has been difficult and
the majority of Conduit users have already migrated, additionally debugging Conduit
is not one of our interests, and so Conduit migration no longer works. We also
feel that 12 months has been plenty of time for people to seamlessly migrate.
If you are a Conduit user looking to migrate, you will have to wipe and reset
your database. We may fix seamless migration support at some point, but it's not an interest
from us.
#### 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 --> <!-- ANCHOR_END: body -->
@@ -114,49 +42,20 @@ method into conduwuit, however there is no concrete ETA or timeline for this.
#### Contact #### Contact
[`#conduwuit:puppygock.gay`](https://matrix.to/#/#conduwuit:puppygock.gay) If you run into any question, feel free to
is the official project Matrix room. You can get support here, ask questions or
concerns, get assistance setting up conduwuit, etc.
This room should stay relevant and focused on conduwuit. An offtopic general - Ask us in `#conduwuit:puppygock.gay` on Matrix
chatter room can be found in the room topic there as well. - [Open an issue on GitHub](https://github.com/girlbossceo/conduwuit/issues/new)
Please keep the issue trackers focused on *actual* 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)
If you need to contact the primary maintainer, my contact methods are on my website: https://girlboss.ceo
#### Donate #### Donate
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: <https://liberapay.com/girlbossceo> - Liberapay: <https://liberapay.com/girlbossceo>
- GitHub Sponsors: <https://github.com/sponsors/girlbossceo>
- Ko-fi: <https://ko-fi.com/puppygock> - 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.
Note that donations will NOT guarantee you or give you any kind of tangible product,
feature prioritisation, etc. By donating, you are agreeing that conduwuit is NOT
going to provide you any goods or services as part of your donation, and this
donation is purely a generous donation. We will not provide things like paid
personal/direct support, feature request priority, merchandise, etc.
#### Logo #### Logo
Original repo and Matrix room picture was from bran (<3). Current banner image 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).
and logo is directly from [this cohost
post](https://web.archive.org/web/20241126004041/https://cohost.org/RatBaby/post/1028290-finally-a-flag-for).
An SVG logo made by [@nktnet1](https://github.com/nktnet1) is available here: <https://github.com/girlbossceo/conduwuit/blob/main/docs/assets/>
#### Is it conduwuit or Conduwuit? #### Is it conduwuit or Conduwuit?
@@ -164,15 +63,10 @@ Both, but I prefer conduwuit.
#### Mirrors of 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> - GitHub: <https://github.com/girlbossceo/conduwuit>
- GitLab: <https://gitlab.com/conduwuit/conduwuit> - GitLab: <https://gitlab.com/conduwuit/conduwuit>
- git.girlcock.ceo: <https://git.girlcock.ceo/strawberry/conduwuit> - git.girlcock.ceo: <https://git.girlcock.ceo/strawberry/conduwuit>
- git.gay: <https://git.gay/june/conduwuit> - git.gay: <https://git.gay/june/conduwuit>
- mau.dev: <https://mau.dev/june/conduwuit> - Codeberg: <https://codeberg.org/girlbossceo/conduwuit>
- Codeberg: <https://codeberg.org/arf/conduwuit>
- sourcehut: <https://git.sr.ht/~girlbossceo/conduwuit> - sourcehut: <https://git.sr.ht/~girlbossceo/conduwuit>
<!-- ANCHOR_END: footer --> <!-- ANCHOR_END: footer -->
+3 -18
View File
@@ -1,27 +1,12 @@
[Unit] [Unit]
Description=conduwuit Matrix homeserver Description=conduwuit Matrix homeserver
Wants=network-online.target After=network.target
After=network-online.target
Documentation=https://conduwuit.puppyirl.gay/ Documentation=https://conduwuit.puppyirl.gay/
RequiresMountsFor=/var/lib/private/conduwuit RequiresMountsFor=/var/lib/private/conduwuit
Alias=matrix-conduwuit.service
[Service] [Service]
DynamicUser=yes DynamicUser=yes
Type=notify-reload Type=notify
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= AmbientCapabilities=
CapabilityBoundingSet= CapabilityBoundingSet=
@@ -30,7 +15,7 @@ DevicePolicy=closed
LockPersonality=yes LockPersonality=yes
MemoryDenyWriteExecute=yes MemoryDenyWriteExecute=yes
NoNewPrivileges=yes NoNewPrivileges=yes
#ProcSubset=pid ProcSubset=pid
ProtectClock=yes ProtectClock=yes
ProtectControlGroups=yes ProtectControlGroups=yes
ProtectHome=yes ProtectHome=yes
+10 -49
View File
@@ -10,15 +10,15 @@ set -euo pipefail
COMPLEMENT_SRC="${COMPLEMENT_SRC:-$1}" COMPLEMENT_SRC="${COMPLEMENT_SRC:-$1}"
# A `.jsonl` file to write test logs to # A `.jsonl` file to write test logs to
LOG_FILE="${2:-complement_test_logs.jsonl}" LOG_FILE="$2"
# A `.jsonl` file to write test results to # A `.jsonl` file to write test results to
RESULTS_FILE="${3:-complement_test_results.jsonl}" RESULTS_FILE="$3"
COMPLEMENT_BASE_IMAGE="${COMPLEMENT_BASE_IMAGE:-complement-conduwuit:main}" OCI_IMAGE="complement-conduit:main"
# Complement tests that are skipped due to flakiness/reliability issues or we don't implement such features and won't for a long time # Complement tests that are skipped due to flakiness/reliability issues
SKIPPED_COMPLEMENT_TESTS='TestPartialStateJoin.*|TestRoomDeleteAlias/Parallel/Regular_users_can_add_and_delete_aliases_when_m.*|TestRoomDeleteAlias/Parallel/Can_delete_canonical_alias|TestUnbanViaInvite.*|TestRoomState/Parallel/GET_/publicRooms_lists.*"|TestRoomDeleteAlias/Parallel/Users_with_sufficient_power-level_can_delete_other.*' SKIPPED_COMPLEMENT_TESTS='-skip=TestClientSpacesSummary.*|TestJoinFederatedRoomFromApplicationServiceBridgeUser.*|TestJumpToDateEndpoint.*'
# $COMPLEMENT_SRC needs to be a directory to Complement source code # $COMPLEMENT_SRC needs to be a directory to Complement source code
if [ -f "$COMPLEMENT_SRC" ]; then if [ -f "$COMPLEMENT_SRC" ]; then
@@ -34,41 +34,17 @@ toplevel="$(git rev-parse --show-toplevel)"
pushd "$toplevel" > /dev/null pushd "$toplevel" > /dev/null
if [ ! -f "complement_oci_image.tar.gz" ]; then bin/nix-build-and-cache just .#static-complement
echo "building complement conduwuit image"
# if using macOS, use linux-complement docker load < result
#bin/nix-build-and-cache just .#linux-complement popd > /dev/null
bin/nix-build-and-cache just .#complement
#nix build -L .#complement
echo "complement conduwuit image tar.gz built at \"result\""
echo "loading into docker"
docker load < result
popd > /dev/null
else
echo "skipping building a complement conduwuit image as complement_oci_image.tar.gz was already found, loading this"
docker load < complement_oci_image.tar.gz
popd > /dev/null
fi
echo ""
echo "running go test with:"
echo "\$COMPLEMENT_SRC: $COMPLEMENT_SRC"
echo "\$COMPLEMENT_BASE_IMAGE: $COMPLEMENT_BASE_IMAGE"
echo "\$RESULTS_FILE: $RESULTS_FILE"
echo "\$LOG_FILE: $LOG_FILE"
echo ""
# It's okay (likely, even) that `go test` exits nonzero # It's okay (likely, even) that `go test` exits nonzero
# `COMPLEMENT_ENABLE_DIRTY_RUNS=1` reuses the same complement container for faster complement, at the possible expense of test environment pollution
set +o pipefail set +o pipefail
env \ env \
-C "$COMPLEMENT_SRC" \ -C "$COMPLEMENT_SRC" \
COMPLEMENT_BASE_IMAGE="$COMPLEMENT_BASE_IMAGE" \ COMPLEMENT_BASE_IMAGE="$OCI_IMAGE" \
go test -tags="conduwuit_blacklist" -skip="$SKIPPED_COMPLEMENT_TESTS" -v -timeout 1h -json ./tests/... | tee "$LOG_FILE" go test -tags="conduwuit_blacklist" "$SKIPPED_COMPLEMENT_TESTS" -v -timeout 1h -json ./tests | tee "$LOG_FILE"
set -o pipefail set -o pipefail
# Post-process the results into an easy-to-compare format, sorted by Test name for reproducible results # Post-process the results into an easy-to-compare format, sorted by Test name for reproducible results
@@ -78,18 +54,3 @@ cat "$LOG_FILE" | jq -s -c 'sort_by(.Test)[]' | jq -c '
and .Test != null and .Test != null
) | {Action: .Action, Test: .Test} ) | {Action: .Action, Test: .Test}
' > "$RESULTS_FILE" ' > "$RESULTS_FILE"
#if command -v gotestfmt &> /dev/null; then
# echo "using gotestfmt on $LOG_FILE"
# grep '{"Time":' "$LOG_FILE" | gotestfmt > "complement_test_logs_gotestfmt.log"
#fi
echo ""
echo ""
echo "complement logs saved at $LOG_FILE"
echo "complement results saved at $RESULTS_FILE"
#if command -v gotestfmt &> /dev/null; then
# echo "complement logs in gotestfmt pretty format outputted at complement_test_logs_gotestfmt.log (use an editor/terminal/pager that interprets ANSI colours and UTF-8 emojis)"
#fi
echo ""
echo ""
+7 -13
View File
@@ -26,12 +26,7 @@ just() {
"$ATTIC_TOKEN" "$ATTIC_TOKEN"
# Find all output paths of the installables and their build dependencies # 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=() cache=()
for derivation in "${derivations[@]}"; do for derivation in "${derivations[@]}"; do
cache+=( cache+=(
@@ -39,9 +34,6 @@ just() {
) )
done done
withattic() {
nix shell --inputs-from "$toplevel" attic --command xargs attic push "$@" <<< "${cache[*]}"
}
# Upload them to Attic (conduit store) # Upload them to Attic (conduit store)
# #
# Use `xargs` and a here-string because something would probably explode if # Use `xargs` and a here-string because something would probably explode if
@@ -49,7 +41,8 @@ just() {
# store paths include a newline in them. # store paths include a newline in them.
( (
IFS=$'\n' IFS=$'\n'
withattic conduit || withattic conduit || withattic conduit || true nix shell --inputs-from "$toplevel" attic -c xargs \
attic push conduit <<< "${cache[*]}"
) )
# main "conduwuit" store # main "conduwuit" store
@@ -66,7 +59,8 @@ just() {
# store paths include a newline in them. # store paths include a newline in them.
( (
IFS=$'\n' IFS=$'\n'
withattic conduwuit || withattic conduwuit || withattic conduwuit || true nix shell --inputs-from "$toplevel" attic -c xargs \
attic push conduwuit <<< "${cache[*]}"
# push to cachix if available # push to cachix if available
if [ "$CACHIX_AUTH_TOKEN" ]; then if [ "$CACHIX_AUTH_TOKEN" ]; then
@@ -82,8 +76,8 @@ ci() {
--inputs-from "$toplevel" --inputs-from "$toplevel"
# Keep sorted # Keep sorted
#"$toplevel#devShells.x86_64-linux.default" "$toplevel#devShells.x86_64-linux.default"
#"$toplevel#devShells.x86_64-linux.all-features" "$toplevel#devShells.x86_64-linux.all-features"
attic#default attic#default
cachix#default cachix#default
nixpkgs#direnv nixpkgs#direnv
+1 -4
View File
@@ -13,15 +13,12 @@ create-missing = true
extra-watch-dirs = ["debian", "docs"] extra-watch-dirs = ["debian", "docs"]
[rust] [rust]
edition = "2024" edition = "2021"
[output.html] [output.html]
git-repository-url = "https://github.com/girlbossceo/conduwuit" git-repository-url = "https://github.com/girlbossceo/conduwuit"
edit-url-template = "https://github.com/girlbossceo/conduwuit/edit/main/{path}" edit-url-template = "https://github.com/girlbossceo/conduwuit/edit/main/{path}"
git-repository-icon = "fa-github-square" git-repository-icon = "fa-github-square"
[output.html.redirect]
"/differences.html" = "https://conduwuit.puppyirl.gay/#where-is-the-differences-page"
[output.html.search] [output.html.search]
limit-results = 15 limit-results = 15
+2 -15
View File
@@ -2,19 +2,6 @@ array-size-threshold = 4096
cognitive-complexity-threshold = 94 # TODO reduce me ALARA cognitive-complexity-threshold = 94 # TODO reduce me ALARA
excessive-nesting-threshold = 11 # TODO reduce me to 4 or 5 excessive-nesting-threshold = 11 # TODO reduce me to 4 or 5
future-size-threshold = 7745 # TODO reduce me ALARA future-size-threshold = 7745 # TODO reduce me ALARA
stack-size-threshold = 196608 # TODO reduce me ALARA stack-size-threshold = 144000 # reduce me ALARA
too-many-lines-threshold = 780 # TODO reduce me to <= 100 too-many-lines-threshold = 700 # TODO reduce me to <= 100
type-complexity-threshold = 250 # reduce me to ~200 type-complexity-threshold = 250 # reduce me to ~200
large-error-threshold = 256 # TODO reduce me ALARA
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" },
]
+655 -1472
View File
File diff suppressed because it is too large Load Diff
+5 -12
View File
@@ -1,24 +1,17 @@
# conduwuit for Debian # conduwuit for Debian
Information about downloading and deploying the Debian package. This may also be Information about downloading and deploying the Debian package. This may also be referenced for other `apt`-based distros such as Ubuntu.
referenced for other `apt`-based distros such as Ubuntu.
### Installation ### Installation
It is recommended to see the [generic deployment guide](../deploying/generic.md) 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.
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 ### Configuration
When installed, the example config is placed at `/etc/conduwuit/conduwuit.toml` 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.
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 You can tweak more detailed settings by uncommenting and setting the config options
options in `/etc/conduwuit/conduwuit.toml`. in `/etc/conduwuit/conduwuit.toml`.
### Running ### Running
+2 -4
View File
@@ -1,9 +1,7 @@
[Unit] [Unit]
Description=conduwuit Matrix homeserver Description=conduwuit Matrix homeserver
Wants=network-online.target
After=network-online.target
Alias=matrix-conduwuit.service
Documentation=https://conduwuit.puppyirl.gay/ Documentation=https://conduwuit.puppyirl.gay/
After=network-online.target
[Service] [Service]
DynamicUser=yes DynamicUser=yes
@@ -24,7 +22,7 @@ DevicePolicy=closed
LockPersonality=yes LockPersonality=yes
MemoryDenyWriteExecute=yes MemoryDenyWriteExecute=yes
NoNewPrivileges=yes NoNewPrivileges=yes
#ProcSubset=pid ProcSubset=pid
ProtectClock=yes ProtectClock=yes
ProtectControlGroups=yes ProtectControlGroups=yes
ProtectHome=yes ProtectHome=yes
+1
View File
@@ -16,6 +16,7 @@ case "$1" in
--home "$CONDUWUIT_DATABASE_PATH" \ --home "$CONDUWUIT_DATABASE_PATH" \
--disabled-login \ --disabled-login \
--shell "/usr/sbin/nologin" \ --shell "/usr/sbin/nologin" \
--verbose \
conduwuit conduwuit
fi fi
+3 -15
View File
@@ -10,33 +10,21 @@ CONDUWUIT_DATABASE_PATH_SYMLINK=/var/lib/matrix-conduit
case $1 in case $1 in
purge) purge)
# Remove debconf changes from the db # Remove debconf changes from the db
#db_purge db_purge
# Per https://www.debian.org/doc/debian-policy/ch-files.html#behavior # Per https://www.debian.org/doc/debian-policy/ch-files.html#behavior
# "configuration files must be preserved when the package is removed, and # "configuration files must be preserved when the package is removed, and
# only deleted when the package is purged." # only deleted when the package is purged."
#
if [ -d "$CONDUWUIT_CONFIG_PATH" ]; then if [ -d "$CONDUWUIT_CONFIG_PATH" ]; then
if test -L "$CONDUWUIT_CONFIG_PATH"; then
echo "Deleting conduwuit configuration files"
rm -v -r "$CONDUWUIT_CONFIG_PATH" rm -v -r "$CONDUWUIT_CONFIG_PATH"
fi fi
fi
if [ -d "$CONDUWUIT_DATABASE_PATH" ]; then if [ -d "$CONDUWUIT_DATABASE_PATH" ]; then
if test -L "$CONDUWUIT_DATABASE_PATH"; then rm -v -r "$CONDUWUIT_DATABASE_PATH"
echo "Deleting conduwuit database directory"
rm -r "$CONDUWUIT_DATABASE_PATH"
fi
fi fi
if [ -d "$CONDUWUIT_DATABASE_PATH_SYMLINK" ]; then if [ -d "$CONDUWUIT_DATABASE_PATH_SYMLINK" ]; then
if test -L "$CONDUWUIT_DATABASE_SYMLINK"; then rm -v -r "$CONDUWUIT_DATABASE_PATH_SYMLINK"
echo "Removing matrix-conduit symlink"
rm -r "$CONDUWUIT_DATABASE_PATH_SYMLINK"
fi
fi fi
;; ;;
esac esac
+42
View File
@@ -0,0 +1,42 @@
[package]
name = "rust-rocksdb-uwu"
categories.workspace = true
description = "dylib wrapper for rust-rocksdb"
edition = "2021"
keywords.workspace = true
license.workspace = true
readme.workspace = true
repository.workspace = true
version = "0.0.1"
[features]
default = ["lz4", "zstd", "zlib", "bzip2"]
jemalloc = ["rust-rocksdb/jemalloc"]
io-uring = ["rust-rocksdb/io-uring"]
valgrind = ["rust-rocksdb/valgrind"]
snappy = ["rust-rocksdb/snappy"]
lz4 = ["rust-rocksdb/lz4"]
zstd = ["rust-rocksdb/zstd"]
zlib = ["rust-rocksdb/zlib"]
bzip2 = ["rust-rocksdb/bzip2"]
rtti = ["rust-rocksdb/rtti"]
mt_static = ["rust-rocksdb/mt_static"]
multi-threaded-cf = ["rust-rocksdb/multi-threaded-cf"]
serde1 = ["rust-rocksdb/serde1"]
malloc-usable-size = ["rust-rocksdb/malloc-usable-size"]
[dependencies.rust-rocksdb]
git = "https://github.com/zaidoon1/rust-rocksdb"
rev = "4056a3b0f823013fec49f6d0b3e5698856e6476a"
#branch = "master"
default-features = false
[lib]
path = "lib.rs"
crate-type = [
"rlib",
# "dylib"
]
[lints]
workspace = true
+61
View File
@@ -0,0 +1,61 @@
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();
}
-1
View File
@@ -1 +0,0 @@
docs/development.md
+1 -2
View File
@@ -1,16 +1,15 @@
# Summary # Summary
- [Introduction](introduction.md) - [Introduction](introduction.md)
- [Differences from upstream Conduit](differences.md)
- [Configuration](configuration.md) - [Configuration](configuration.md)
- [Examples](configuration/examples.md) - [Examples](configuration/examples.md)
- [Deploying](deploying.md) - [Deploying](deploying.md)
- [Generic](deploying/generic.md) - [Generic](deploying/generic.md)
- [NixOS](deploying/nixos.md) - [NixOS](deploying/nixos.md)
- [Docker](deploying/docker.md) - [Docker](deploying/docker.md)
- [Kubernetes](deploying/kubernetes.md)
- [Arch Linux](deploying/arch-linux.md) - [Arch Linux](deploying/arch-linux.md)
- [Debian](deploying/debian.md) - [Debian](deploying/debian.md)
- [FreeBSD](deploying/freebsd.md)
- [TURN](turn.md) - [TURN](turn.md)
- [Appservices](appservices.md) - [Appservices](appservices.md)
- [Maintenance](maintenance.md) - [Maintenance](maintenance.md)
+3 -5
View File
@@ -2,15 +2,13 @@
## Getting help ## Getting help
If you run into any problems while setting up an Appservice: ask us in If you run into any problems while setting up an Appservice: ask us in [#conduwuit:puppygock.gay](https://matrix.to/#/#conduwuit:puppygock.gay) or [open an issue on GitHub](https://github.com/girlbossceo/conduwuit/issues/new).
[#conduwuit:puppygock.gay](https://matrix.to/#/#conduwuit:puppygock.gay) or
[open an issue on GitHub](https://github.com/girlbossceo/conduwuit/issues/new).
## Set up the appservice - general instructions ## Set up the appservice - general instructions
Follow whatever instructions are given by the appservice. This usually includes Follow whatever instructions are given by the appservice. This usually includes
downloading, changing its config (setting domain, homeserver url, port etc.) and downloading, changing its config (setting domain, homeserver url, port etc.)
later starting it. and later starting it.
At some point the appservice guide should ask you to add a registration yaml At some point the appservice guide should ask you to add a registration yaml
file to the homeserver. In Synapse you would do this by adding the path to the file to the homeserver. In Synapse you would do this by adding the path to the
-36
View File
@@ -1,36 +0,0 @@
<svg
version="1.1"
id="Layer_1"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
width="100%"
viewBox="0 0 864 864"
enableBackground="new 0 0 864 864"
xmlSpace="preserve"
>
<path
fill="#EC008C"
opacity="1.000000"
stroke="none"
d="M0.999997,649.000000 C1.000000,433.052795 1.000000,217.105591 1.000000,1.079198 C288.876801,1.079198 576.753601,1.079198 865.000000,1.079198 C865.000000,73.025414 865.000000,145.051453 864.634888,217.500671 C852.362488,223.837280 840.447632,229.735275 828.549438,235.666794 C782.143677,258.801056 735.743225,281.945923 688.998657,304.980469 C688.122009,304.476532 687.580750,304.087708 687.053894,303.680206 C639.556946,266.944733 573.006775,291.446869 560.804199,350.179443 C560.141357,353.369446 559.717590,356.609131 559.195374,359.748962 C474.522705,359.748962 390.283478,359.748962 306.088135,359.748962 C298.804138,318.894806 265.253357,295.206024 231.834442,293.306793 C201.003021,291.554596 169.912033,310.230042 156.935104,338.792725 C149.905151,354.265930 147.884064,370.379944 151.151794,387.034515 C155.204453,407.689667 166.300507,423.954224 183.344437,436.516663 C181.938263,437.607025 180.887405,438.409576 179.849426,439.228516 C147.141953,465.032562 139.918045,510.888947 163.388611,545.322632 C167.274551,551.023804 172.285187,555.958313 176.587341,561.495728 C125.846893,587.012817 75.302292,612.295532 24.735992,637.534790 C16.874903,641.458496 8.914484,645.183228 0.999997,649.000000 z"
/>
<path
fill="#000000"
opacity="1.000000"
stroke="none"
d="M689.340759,305.086823 C735.743225,281.945923 782.143677,258.801056 828.549438,235.666794 C840.447632,229.735275 852.362488,223.837280 864.634888,217.961929 C865.000000,433.613190 865.000000,649.226379 865.000000,864.919800 C577.000000,864.919800 289.000000,864.919800 1.000000,864.919800 C1.000000,793.225708 1.000000,721.576721 0.999997,649.463867 C8.914484,645.183228 16.874903,641.458496 24.735992,637.534790 C75.302292,612.295532 125.846893,587.012817 176.939667,561.513062 C178.543060,562.085083 179.606812,562.886414 180.667526,563.691833 C225.656799,597.853394 291.232574,574.487244 304.462524,519.579773 C304.989105,517.394409 305.501068,515.205505 305.984619,513.166748 C391.466370,513.166748 476.422729,513.166748 561.331177,513.166748 C573.857727,555.764343 608.978149,572.880920 638.519897,572.672791 C671.048340,572.443665 700.623230,551.730408 711.658752,520.910583 C722.546875,490.502106 715.037842,453.265564 682.776733,429.447052 C683.966064,428.506866 685.119507,427.602356 686.265320,426.688232 C712.934143,405.412262 723.011475,370.684631 711.897339,338.686676 C707.312805,325.487671 699.185303,314.725128 689.340759,305.086823 z"
/>
<path
fill="#FEFBFC"
opacity="1.000000"
stroke="none"
d="M688.998657,304.980469 C699.185303,314.725128 707.312805,325.487671 711.897339,338.686676 C723.011475,370.684631 712.934143,405.412262 686.265320,426.688232 C685.119507,427.602356 683.966064,428.506866 682.776733,429.447052 C715.037842,453.265564 722.546875,490.502106 711.658752,520.910583 C700.623230,551.730408 671.048340,572.443665 638.519897,572.672791 C608.978149,572.880920 573.857727,555.764343 561.331177,513.166748 C476.422729,513.166748 391.466370,513.166748 305.984619,513.166748 C305.501068,515.205505 304.989105,517.394409 304.462524,519.579773 C291.232574,574.487244 225.656799,597.853394 180.667526,563.691833 C179.606812,562.886414 178.543060,562.085083 177.128418,561.264465 C172.285187,555.958313 167.274551,551.023804 163.388611,545.322632 C139.918045,510.888947 147.141953,465.032562 179.849426,439.228516 C180.887405,438.409576 181.938263,437.607025 183.344437,436.516663 C166.300507,423.954224 155.204453,407.689667 151.151794,387.034515 C147.884064,370.379944 149.905151,354.265930 156.935104,338.792725 C169.912033,310.230042 201.003021,291.554596 231.834442,293.306793 C265.253357,295.206024 298.804138,318.894806 306.088135,359.748962 C390.283478,359.748962 474.522705,359.748962 559.195374,359.748962 C559.717590,356.609131 560.141357,353.369446 560.804199,350.179443 C573.006775,291.446869 639.556946,266.944733 687.053894,303.680206 C687.580750,304.087708 688.122009,304.476532 688.998657,304.980469 M703.311279,484.370789 C698.954468,457.053253 681.951416,440.229645 656.413696,429.482330 C673.953552,421.977875 688.014709,412.074219 696.456482,395.642365 C704.862061,379.280853 706.487793,362.316345 700.947998,344.809204 C691.688965,315.548492 664.183716,296.954437 633.103516,298.838257 C618.467957,299.725372 605.538086,305.139557 594.588501,314.780121 C577.473999,329.848511 570.185486,349.121399 571.838501,371.750854 C479.166595,371.750854 387.082886,371.750854 294.582672,371.750854 C293.993011,354.662048 288.485260,339.622314 276.940491,327.118439 C265.392609,314.611176 251.082092,307.205322 234.093262,305.960541 C203.355347,303.708374 176.337585,320.898438 166.089890,348.816620 C159.557541,366.613007 160.527206,384.117401 168.756042,401.172516 C177.054779,418.372589 191.471954,428.832886 207.526581,435.632172 C198.407059,442.272583 188.815598,448.302246 180.383728,455.660675 C171.685028,463.251984 166.849655,473.658661 163.940216,484.838684 C161.021744,496.053375 161.212982,507.259705 164.178833,518.426208 C171.577927,546.284302 197.338104,566.588867 226.001465,567.336853 C240.828415,567.723816 254.357819,563.819092 266.385468,555.199646 C284.811554,541.994751 293.631104,523.530579 294.687347,501.238312 C387.354828,501.238312 479.461304,501.238312 571.531799,501.238312 C577.616638,543.189026 615.312866,566.342102 651.310059,559.044739 C684.973938,552.220398 708.263306,519.393127 703.311279,484.370789 z"
/>
<path
fill="#EC008C"
opacity="1.000000"
stroke="none"
d="M703.401855,484.804718 C708.263306,519.393127 684.973938,552.220398 651.310059,559.044739 C615.312866,566.342102 577.616638,543.189026 571.531799,501.238312 C479.461304,501.238312 387.354828,501.238312 294.687347,501.238312 C293.631104,523.530579 284.811554,541.994751 266.385468,555.199646 C254.357819,563.819092 240.828415,567.723816 226.001465,567.336853 C197.338104,566.588867 171.577927,546.284302 164.178833,518.426208 C161.212982,507.259705 161.021744,496.053375 163.940216,484.838684 C166.849655,473.658661 171.685028,463.251984 180.383728,455.660675 C188.815598,448.302246 198.407059,442.272583 207.526581,435.632172 C191.471954,428.832886 177.054779,418.372589 168.756042,401.172516 C160.527206,384.117401 159.557541,366.613007 166.089890,348.816620 C176.337585,320.898438 203.355347,303.708374 234.093262,305.960541 C251.082092,307.205322 265.392609,314.611176 276.940491,327.118439 C288.485260,339.622314 293.993011,354.662048 294.582672,371.750854 C387.082886,371.750854 479.166595,371.750854 571.838501,371.750854 C570.185486,349.121399 577.473999,329.848511 594.588501,314.780121 C605.538086,305.139557 618.467957,299.725372 633.103516,298.838257 C664.183716,296.954437 691.688965,315.548492 700.947998,344.809204 C706.487793,362.316345 704.862061,379.280853 696.456482,395.642365 C688.014709,412.074219 673.953552,421.977875 656.413696,429.482330 C681.951416,440.229645 698.954468,457.053253 703.401855,484.804718 z"
/>
</svg>

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

+45 -61
View File
@@ -1,93 +1,77 @@
# conduwuit Community Code of Conduct # conduwuit Community Code of Conduct
Welcome to the conduwuit community! Were excited to have you here. conduwuit is Welcome to the conduwuit community! Were excited to have you here. conduwuit is a hard-fork of the Conduit homeserver,
a hard-fork of the Conduit homeserver, aimed at making Matrix more accessible aimed at making Matrix more accessible and inclusive for everyone.
and inclusive for everyone.
This space is dedicated to fostering a positive, supportive, and inclusive This space is dedicated to fostering a positive, supportive, and inclusive environment for everyone. This Code of
environment for everyone. This Code of Conduct applies to all conduwuit spaces, Conduct applies to all conduwuit spaces, including any further community rooms that reference this CoC. Here are our
including any further community rooms that reference this CoC. Here are our
guidelines to help maintain the welcoming atmosphere that sets conduwuit apart. guidelines to help maintain the welcoming atmosphere that sets conduwuit apart.
For the general foundational rules, please refer to the [Contributor's For the foundational rules, please refer to the [Matrix.org Code of Conduct](https://matrix.org/legal/code-of-conduct/)
Covenant](https://github.com/girlbossceo/conduwuit/blob/main/CODE_OF_CONDUCT.md). and the [Contributor's Covenant](https://github.com/girlbossceo/conduwuit/blob/main/CODE_OF_CONDUCT.md). Below are
Below are additional guidelines specific to the conduwuit community. additional guidelines specific to the conduwuit community.
## Our Values and Guidelines ## Our Values and Guidelines
1. **Respect and Inclusivity**: We are committed to maintaining a community 1. **Respect and Inclusivity**: We are committed to maintaining a community where everyone feels safe and respected.
where everyone feels safe and respected. Discrimination, harassment, or hate Discrimination, harassment, or hate speech of any kind will not be tolerated. Recognise that each community member
speech of any kind will not be tolerated. Recognise that each community member experiences the world differently based on their past experiences, background, and identity. Share your own
experiences the world differently based on their past experiences, background, experiences and be open to learning about others' diverse perspectives.
and identity. Share your own experiences and be open to learning about others'
diverse perspectives.
2. **Positivity and Constructiveness**: Engage in constructive discussions and 2. **Positivity and Constructiveness**: Engage in constructive discussions and support each other. If you feel angry,
support each other. If you feel angry, negative, or aggressive, take a break negative, or aggressive, take a break until you can participate in a positive and constructive manner. Process
until you can participate in a positive and constructive manner. Process intense intense feelings with a friend or in a private setting before engaging in community conversations to help maintain
feelings with a friend or in a private setting before engaging in community a supportive and focused environment.
conversations to help maintain a supportive and focused environment.
3. **Clarity and Understanding**: Our community includes neurodivergent 3. **Clarity and Understanding**: Our community includes neurodivergent individuals and those who may not appreciate
individuals and those who may not appreciate sarcasm or subtlety. Communicate sarcasm or subtlety. Communicate clearly and kindly, avoiding sarcasm and ensuring your messages are easily
clearly and kindly, avoiding sarcasm and ensuring your messages are easily understood by all. Additionally, avoid putting the burden of education on marginalized groups by doing your own
understood by all. Additionally, avoid putting the burden of education on research before asking for explanations.
marginalized groups by doing your own research before asking for explanations.
4. **Be Open to Inclusivity**: Actively engage in conversations about making our 4. **Be Open to Inclusivity**: Actively engage in conversations about making our community more inclusive. Report
community more inclusive. Report discriminatory behavior to the moderators discriminatory behavior to the moderators and be open to constructive feedback that aims to improve our community.
and be open to constructive feedback that aims to improve our community. Understand that discussing discrimination and negative experiences can be emotionally taxing, so focus on the
Understand that discussing discrimination and negative experiences can be message rather than critiquing the tone used.
emotionally taxing, so focus on the message rather than critiquing the tone
used.
5. **Commit to Inclusivity**: Building an inclusive community requires time, 5. **Commit to Inclusivity**: Building an inclusive community requires time, energy, and resources. Recognise that
energy, and resources. Recognise that addressing discrimination and bias is addressing discrimination and bias is an ongoing process that necessitates commitment and action from all community
an ongoing process that necessitates commitment and action from all community members.
members.
## Matrix Community ## Matrix Community
This Code of Conduct applies to the entire [conduwuit Matrix This Code of Conduct applies to the entire [conduwuit Matrix Space](https://matrix.to/#/#conduwuit-space:puppygock.gay)
Space](https://matrix.to/#/#conduwuit-space:puppygock.gay) and its rooms, and its rooms, including:
including:
### [#conduwuit:puppygock.gay](https://matrix.to/#/#conduwuit:puppygock.gay) ### [#conduwuit:puppygock.gay](https://matrix.to/#/#conduwuit:puppygock.gay)
This room is for support and discussions about conduwuit. Ask questions, share This room is for support and discussions about conduwuit. Ask questions, share insights, and help each other out.
insights, and help each other out.
### [#conduwuit-offtopic:girlboss.ceo](https://matrix.to/#/#conduwuit-offtopic:girlboss.ceo) ### [#conduwuit-offtopic:girlboss.ceo](https://matrix.to/#/#conduwuit-offtopic:girlboss.ceo)
For off-topic community conversations about any subject. While this room allows For off-topic community conversations about any subject. While this room allows for a wide range of topics, the same
for a wide range of topics, the same CoC applies. Keep discussions respectful CoC applies. Keep discussions respectful and inclusive, and avoid divisive subjects like country/world politics.
and inclusive, and avoid divisive subjects like country/world politics. General General topics, such as world events, are welcome as long as they follow the CoC.
topics, such as world events, are welcome as long as they follow the CoC.
### [#conduwuit-dev:puppygock.gay](https://matrix.to/#/#conduwuit-dev:puppygock.gay) ### [#conduwuit-dev:puppygock.gay](https://matrix.to/#/#conduwuit-dev:puppygock.gay)
This room is dedicated to discussing active development of conduwuit. Posting This room is dedicated to discussing active development of conduwuit. Posting requires an elevated power level, which
requires an elevated power level, which can be requested in one of the other can be requested in one of the other rooms. Use this space to collaborate and innovate.
rooms. Use this space to collaborate and innovate.
## Enforcement ## Enforcement
We have a zero-tolerance policy for violations of this Code of Conduct. If We have a zero-tolerance policy for violations of this Code of Conduct. If someones behavior makes you uncomfortable,
someones behavior makes you uncomfortable, please report it to the moderators. please report it to the moderators. Actions we may take include:
Actions we may take include:
1. **Warning**: A warning given directly in the room or via a private message 1. **Warning**: A warning given directly in the room or via a private message from the moderators, identifying
from the moderators, identifying the violation and requesting corrective the violation and requesting corrective action.
action. 2. **Temporary Mute**: Temporary restriction from participating in discussions for a specified period to allow for
2. **Temporary Mute**: Temporary restriction from participating in discussions reflection and cooling off.
for a specified period to allow for reflection and cooling off. 3. **Kick or Ban**: Egregious behavior may result in an immediate kick or ban to protect other community members.
3. **Kick or Ban**: Egregious behavior may result in an immediate kick or ban to Bans are considered permanent and will only be reversed in exceptional circumstances after proven good behavior.
protect other community members. Bans are considered permanent and will only
be reversed in exceptional circumstances after proven good behavior.
Please highlight issues directly in rooms when possible, but if you don't feel Please highlight issues directly in rooms when possible, but if you don't feel comfortable doing that, then please send
comfortable doing that, then please send a DM to one of the moderators directly. a DM to one of the moderators directly.
Together, lets build a community where everyone feels valued and respected. Together, lets build a community where everyone feels valued and respected.
The conduwuit Moderation Team - The conduwuit Moderation Team
+9 -55
View File
@@ -4,61 +4,15 @@ This chapter describes various ways to configure conduwuit.
## Basics ## Basics
conduwuit uses a config file for the majority of the settings, but also supports Conduwuit uses a config file for the majority of the settings. Please refer to the
setting individual config options via commandline. [example config file](./configuration/examples.md#example-configuration) for all of those settings.
The config file to use can either be specified on the command line when running conduwuit by specifying the
Please refer to the [example config `-c`, `--config` flag. Alternatively, you can use the environment variable `CONDUWUIT_CONFIG` to specify the config
file](./configuration/examples.md#example-configuration) for all of those file to used.
settings.
The config file to use can be specified on the commandline when running
conduwuit by specifying the `-c`, `--config` flag. Alternatively, you can use
the environment variable `CONDUWUIT_CONFIG` to specify the config file to used.
Conduit's environment variables are supported for backwards compatibility.
## Option commandline flag
conduwuit supports setting individual config options in TOML format from the
`-O` / `--option` flag. For example, you can set your server name via `-O
server_name=\"example.com\"`.
Note that the config is parsed as TOML, and shells like bash will remove quotes.
So unfortunately it is required to escape quotes if the config option takes a
string. This does not apply to options that take booleans or numbers:
- `--option allow_registration=true` works ✅
- `-O max_request_size=99999999` works ✅
- `-O server_name=example.com` does not work ❌
- `--option log=\"debug\"` works ✅
- `--option server_name='"example.com'"` works ✅
## Execute commandline flag
conduwuit supports running admin commands on startup using the commandline
argument `--execute`. The most notable use for this is to create an admin user
on first startup.
The syntax of this is a standard admin command without the prefix such as
`./conduwuit --execute "users create_user june"`
An example output of a success is:
```
INFO conduwuit_service::admin::startup: Startup command #0 completed:
Created user with user_id: @june:girlboss.ceo and password: `<redacted>`
```
This commandline argument can be paired with the `--option` flag.
## Environment variables ## Environment variables
All of the settings that are found in the config file can be specified by using All of the settings that are found in the config file can be specified by using environment variables.
environment variables. The environment variable names should be all caps and The environment variable names should be all caps and prefixed with `CONDUWUIT_`.
prefixed with `CONDUWUIT_`. For example, if the setting you are changing is `max_request_size`, then the environment variable to set is
`CONDUWUIT_MAX_REQUEST_SIZE`.
For example, if the setting you are changing is `max_request_size`, then the
environment variable to set is `CONDUWUIT_MAX_REQUEST_SIZE`.
To modify config options not in the `[global]` context such as
`[global.well_known]`, use the `__` suffix split: `CONDUWUIT_WELL_KNOWN__SERVER`
Conduit's environment variables are supported for backwards compatibility (e.g.
`CONDUIT_SERVER_NAME`).
-1
View File
@@ -1 +0,0 @@
../CONTRIBUTING.md
+1
View File
@@ -0,0 +1 @@
{{#include ../CONTRIBUTING.md}}
+4 -10
View File
@@ -2,14 +2,8 @@
Currently conduwuit is only on the Arch User Repository (AUR). Currently conduwuit is only on the Arch User Repository (AUR).
The conduwuit AUR packages are community maintained and are not maintained by The conduwuit AUR packages are community maintained and are not maintained by conduwuit development team, but the AUR package maintainers are in the Matrix room. Please attempt to verify your AUR package's PKGBUILD file looks fine before asking for support.
conduwuit development team, but the AUR package maintainers are in the Matrix
room. Please attempt to verify your AUR package's PKGBUILD file looks fine
before asking for support.
- [conduwuit](https://aur.archlinux.org/packages/conduwuit) - latest tagged - [conduwuit](https://aur.archlinux.org/packages/conduwuit) - latest tagged conduwuit
conduwuit - [conduwuit-git](https://aur.archlinux.org/packages/conduwuit-git) - latest git conduwuit from `main` branch
- [conduwuit-git](https://aur.archlinux.org/packages/conduwuit-git) - latest git - [conduwuit-bin](https://aur.archlinux.org/packages/conduwuit-bin) - latest tagged conduwuit static binary
conduwuit from `main` branch
- [conduwuit-bin](https://aur.archlinux.org/packages/conduwuit-bin) - latest
tagged conduwuit static binary
+13 -20
View File
@@ -12,34 +12,29 @@ services:
networks: networks:
- proxy - proxy
environment: environment:
CONDUWUIT_SERVER_NAME: your.server.name.example # EDIT THIS CONDUWUIT_SERVER_NAME: your.server.name # EDIT THIS
CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit
CONDUWUIT_PORT: 6167 # should match the loadbalancer traefik label CONDUWUIT_DATABASE_BACKEND: rocksdb
CONDUWUIT_MAX_REQUEST_SIZE: 20000000 # in bytes, ~20 MB CONDUWUIT_PORT: 6167
CONDUWUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
CONDUWUIT_ALLOW_REGISTRATION: 'true' 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_FEDERATION: 'true'
CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true' CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true'
CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]' CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]'
#CONDUWUIT_LOG: warn,state_res=warn #CONDUWUIT_LOG: warn,state_res=warn
CONDUWUIT_ADDRESS: 0.0.0.0 CONDUWUIT_ADDRESS: 0.0.0.0
#CONDUWUIT_CONFIG: '/etc/conduwuit.toml' # Uncomment if you mapped config toml above #CONDUWUIT_CONFIG: '/etc/conduwuit.toml' # Uncomment if you mapped config toml above
# We need some way to serve the client and server .well-known json. The simplest way is via the CONDUWUIT_WELL_KNOWN
# variable / config option, there are multiple ways to do this, e.g. in the conduwuit.toml file, and in a seperate
# see the override file for more information about delegation
CONDUWUIT_WELL_KNOWN: |
{
client=https://your.server.name.example,
server=your.server.name.example:443
}
#cpuset: "0-4" # Uncomment to limit to specific CPU cores #cpuset: "0-4" # Uncomment to limit to specific CPU cores
ulimits: # conduwuit uses quite a few file descriptors, and on some systems it defaults to 1024, so you can tell docker to increase it
nofile:
soft: 1048567
hard: 1048567
# We need some way to server the client and server .well-known json. The simplest way is to use a nginx container
# to serve those two as static files. If you want to use a different way, delete or comment the below service, here
# and in the docker compose override file.
well-known:
image: nginx:latest
restart: unless-stopped
volumes:
- ./nginx/matrix.conf:/etc/nginx/conf.d/matrix.conf # the config to serve the .well-known/matrix files
- ./nginx/www:/var/www/ # location of the client and server .well-known-files
### Uncomment if you want to use your own Element-Web App. ### Uncomment if you want to use your own Element-Web App.
### Note: You need to provide a config.json for Element and you also need a second ### Note: You need to provide a config.json for Element and you also need a second
### Domain or Subdomain for the communication between Element and conduwuit ### Domain or Subdomain for the communication between Element and conduwuit
@@ -62,5 +57,3 @@ networks:
# name, don't forget to change it here and in the docker-compose.override.yml # name, don't forget to change it here and in the docker-compose.override.yml
proxy: proxy:
external: true external: true
# vim: ts=2:sw=2:expandtab
+17 -10
View File
@@ -10,18 +10,28 @@ services:
- "traefik.http.routers.to-conduwuit.tls=true" - "traefik.http.routers.to-conduwuit.tls=true"
- "traefik.http.routers.to-conduwuit.tls.certresolver=letsencrypt" - "traefik.http.routers.to-conduwuit.tls.certresolver=letsencrypt"
- "traefik.http.routers.to-conduwuit.middlewares=cors-headers@docker" - "traefik.http.routers.to-conduwuit.middlewares=cors-headers@docker"
- "traefik.http.services.to_conduwuit.loadbalancer.server.port=6167"
- "traefik.http.middlewares.cors-headers.headers.accessControlAllowOriginList=*" - "traefik.http.middlewares.cors-headers.headers.accessControlAllowOriginList=*"
- "traefik.http.middlewares.cors-headers.headers.accessControlAllowHeaders=Origin, X-Requested-With, Content-Type, Accept, Authorization" - "traefik.http.middlewares.cors-headers.headers.accessControlAllowHeaders=Origin, X-Requested-With, Content-Type, Accept, Authorization"
- "traefik.http.middlewares.cors-headers.headers.accessControlAllowMethods=GET, POST, PUT, DELETE, OPTIONS" - "traefik.http.middlewares.cors-headers.headers.accessControlAllowMethods=GET, POST, PUT, DELETE, OPTIONS"
# If you want to have your account on <DOMAIN>, but host conduwuit on a subdomain, # We need some way to server the client and server .well-known json. The simplest way is to use a nginx container
# you can let it only handle the well known file on that domain instead # to serve those two as static files. If you want to use a different way, delete or comment the below service, here
#- "traefik.http.routers.to-matrix-wellknown.rule=Host(`<DOMAIN>`) && PathPrefix(`/.well-known/matrix`)" # and in the docker compose file.
#- "traefik.http.routers.to-matrix-wellknown.tls=true" well-known:
#- "traefik.http.routers.to-matrix-wellknown.tls.certresolver=letsencrypt" labels:
#- "traefik.http.routers.to-matrix-wellknown.middlewares=cors-headers@docker" - "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.to-matrix-wellknown.rule=Host(`<SUBDOMAIN>.<DOMAIN>`) && PathPrefix(`/.well-known/matrix`)"
- "traefik.http.routers.to-matrix-wellknown.tls=true"
- "traefik.http.routers.to-matrix-wellknown.tls.certresolver=letsencrypt"
- "traefik.http.routers.to-matrix-wellknown.middlewares=cors-headers@docker"
- "traefik.http.middlewares.cors-headers.headers.accessControlAllowOriginList=*"
- "traefik.http.middlewares.cors-headers.headers.accessControlAllowHeaders=Origin, X-Requested-With, Content-Type, Accept, Authorization"
- "traefik.http.middlewares.cors-headers.headers.accessControlAllowMethods=GET, POST, PUT, DELETE, OPTIONS"
### Uncomment this if you uncommented Element-Web App in the docker-compose.yml ### Uncomment this if you uncommented Element-Web App in the docker-compose.yml
# element-web: # element-web:
@@ -32,6 +42,3 @@ services:
# - "traefik.http.routers.to-element-web.rule=Host(`<SUBDOMAIN>.<DOMAIN>`)" # Change to the address on which Element-Web is hosted # - "traefik.http.routers.to-element-web.rule=Host(`<SUBDOMAIN>.<DOMAIN>`)" # Change to the address on which Element-Web is hosted
# - "traefik.http.routers.to-element-web.tls=true" # - "traefik.http.routers.to-element-web.tls=true"
# - "traefik.http.routers.to-element-web.tls.certresolver=letsencrypt" # - "traefik.http.routers.to-element-web.tls.certresolver=letsencrypt"
# vim: ts=2:sw=2:expandtab
+2 -3
View File
@@ -30,11 +30,10 @@ services:
environment: environment:
CONDUWUIT_SERVER_NAME: example.com # EDIT THIS CONDUWUIT_SERVER_NAME: example.com # EDIT THIS
CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit
CONDUWUIT_DATABASE_BACKEND: rocksdb
CONDUWUIT_PORT: 6167 CONDUWUIT_PORT: 6167
CONDUWUIT_MAX_REQUEST_SIZE: 20000000 # in bytes, ~20 MB CONDUWUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
CONDUWUIT_ALLOW_REGISTRATION: 'true' 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_FEDERATION: 'true'
CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true' CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true'
CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]' CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]'
+23 -85
View File
@@ -7,46 +7,36 @@ services:
image: girlbossceo/conduwuit:latest image: girlbossceo/conduwuit:latest
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- db:/var/lib/conduwuit - db:/srv/conduwuit/.local/share/conduwuit
#- ./conduwuit.toml:/etc/conduwuit.toml #- ./conduwuit.toml:/etc/conduwuit.toml
networks: networks:
- proxy - proxy
environment: environment:
CONDUWUIT_SERVER_NAME: your.server.name.example # EDIT THIS CONDUWUIT_SERVER_NAME: your.server.name # EDIT THIS
CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]' CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]'
CONDUWUIT_ALLOW_REGISTRATION: 'false' # After setting a secure registration token, you can enable this CONDUWUIT_ALLOW_REGISTRATION : 'true'
CONDUWUIT_REGISTRATION_TOKEN: "" # This is a token you can use to register on the server #CONDUWUIT_CONFIG: '/etc/conduwuit.toml' # Uncomment if you mapped config toml above
#CONDUWUIT_REGISTRATION_TOKEN_FILE: "" # Alternatively you can configure a path to a token file to read ### Uncomment and change values as desired
CONDUWUIT_ADDRESS: 0.0.0.0 # 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_PORT: 6167
CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit
#CONDUWUIT_CONFIG: '/etc/conduit.toml' # Uncomment if you mapped config toml above
### 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_LOG: info # default is: "warn,state_res=warn"
# CONDUWUIT_ALLOW_JAEGER: 'false'
# CONDUWUIT_ALLOW_ENCRYPTION: 'true' # CONDUWUIT_ALLOW_ENCRYPTION: 'true'
# CONDUWUIT_ALLOW_FEDERATION: 'true' # CONDUWUIT_ALLOW_FEDERATION: 'true'
# CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true' # CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true'
# CONDUWUIT_ALLOW_INCOMING_PRESENCE: true # CONDUWUIT_DATABASE_PATH: /srv/conduwuit/.local/share/conduwuit
# CONDUWUIT_ALLOW_OUTGOING_PRESENCE: true
# CONDUWUIT_ALLOW_LOCAL_PRESENCE: true
# CONDUWUIT_WORKERS: 10 # CONDUWUIT_WORKERS: 10
# CONDUWUIT_MAX_REQUEST_SIZE: 20000000 # 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 # We need some way to server the client and server .well-known json. The simplest way is to use a nginx container
# variable / config option, there are multiple ways to do this, e.g. in the conduwuit.toml file, and in a seperate # to serve those two as static files. If you want to use a different way, delete or comment the below service, here
# reverse proxy, but since you do not have a reverse proxy and following this guide, this example is included # and in the docker compose override file.
CONDUWUIT_WELL_KNOWN: | well-known:
{ image: nginx:latest
client=https://your.server.name.example, restart: unless-stopped
server=your.server.name.example:443 volumes:
} - ./nginx/matrix.conf:/etc/nginx/conf.d/matrix.conf # the config to serve the .well-known/matrix files
#cpuset: "0-4" # Uncomment to limit to specific CPU cores - ./nginx/www:/var/www/ # location of the client and server .well-known-files
ulimits: # conduwuit uses quite a few file descriptors, and on some systems it defaults to 1024, so you can tell docker to increase it
nofile:
soft: 1048567
hard: 1048567
### Uncomment if you want to use your own Element-Web App. ### Uncomment if you want to use your own Element-Web App.
### Note: You need to provide a config.json for Element and you also need a second ### Note: You need to provide a config.json for Element and you also need a second
@@ -70,9 +60,9 @@ services:
- "80:80" - "80:80"
- "443:443" - "443:443"
volumes: volumes:
- "/var/run/docker.sock:/var/run/docker.sock:z" - "/var/run/docker.sock:/var/run/docker.sock"
# - "./traefik_config:/etc/traefik"
- "acme:/etc/traefik/acme" - "acme:/etc/traefik/acme"
#- "./traefik_config:/etc/traefik:z"
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
@@ -80,61 +70,11 @@ services:
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
# global redirect to https # global redirect to https
- "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)" - "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.redirs.entrypoints=web" - "traefik.http.routers.redirs.entrypoints=http"
- "traefik.http.routers.redirs.middlewares=redirect-to-https" - "traefik.http.routers.redirs.middlewares=redirect-to-https"
configs: networks:
- source: dynamic.yml - proxy
target: /etc/traefik/dynamic.yml
environment:
TRAEFIK_LOG_LEVEL: DEBUG
TRAEFIK_ENTRYPOINTS_WEB: true
TRAEFIK_ENTRYPOINTS_WEB_ADDRESS: ":80"
TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_TO: websecure
TRAEFIK_ENTRYPOINTS_WEBSECURE: true
TRAEFIK_ENTRYPOINTS_WEBSECURE_ADDRESS: ":443"
TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_TLS_CERTRESOLVER: letsencrypt
#TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_MIDDLEWARES: secureHeaders@file # if you want to enabled STS
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT: true
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_EMAIL: # Set this to the email you want to receive certificate expiration emails for
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_KEYTYPE: EC384
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_HTTPCHALLENGE: true
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_HTTPCHALLENGE_ENTRYPOINT: web
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_STORAGE: "/etc/traefik/acme/acme.json"
TRAEFIK_PROVIDERS_DOCKER: true
TRAEFIK_PROVIDERS_DOCKER_ENDPOINT: "unix:///var/run/docker.sock"
TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT: false
TRAEFIK_PROVIDERS_FILE: true
TRAEFIK_PROVIDERS_FILE_FILENAME: "/etc/traefik/dynamic.yml"
configs:
dynamic.yml:
content: |
# Optionally set STS headers, like in https://hstspreload.org
# http:
# middlewares:
# secureHeaders:
# headers:
# forceSTSHeader: true
# stsIncludeSubdomains: true
# stsPreload: true
# stsSeconds: 31536000
tls:
options:
default:
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
minVersion: VersionTLS12
volumes: volumes:
db: db:
@@ -142,5 +82,3 @@ volumes:
networks: networks:
proxy: proxy:
# vim: ts=2:sw=2:expandtab
+2 -3
View File
@@ -14,11 +14,10 @@ services:
environment: environment:
CONDUWUIT_SERVER_NAME: your.server.name # EDIT THIS CONDUWUIT_SERVER_NAME: your.server.name # EDIT THIS
CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit CONDUWUIT_DATABASE_PATH: /var/lib/conduwuit
CONDUWUIT_DATABASE_BACKEND: rocksdb
CONDUWUIT_PORT: 6167 CONDUWUIT_PORT: 6167
CONDUWUIT_MAX_REQUEST_SIZE: 20000000 # in bytes, ~20 MB CONDUWUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
CONDUWUIT_ALLOW_REGISTRATION: 'true' 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_FEDERATION: 'true'
CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true' CONDUWUIT_ALLOW_CHECK_FOR_UPDATES: 'true'
CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]' CONDUWUIT_TRUSTED_SERVERS: '["matrix.org"]'
+37 -76
View File
@@ -2,8 +2,7 @@
## Docker ## Docker
To run conduwuit with Docker you can either build the image yourself or pull it To run conduwuit with Docker you can either build the image yourself or pull it from a registry.
from a registry.
### Use a registry ### Use a registry
@@ -11,26 +10,23 @@ OCI images for conduwuit are available in the registries listed below.
| Registry | Image | Size | Notes | | Registry | Image | Size | Notes |
| --------------- | --------------------------------------------------------------- | ----------------------------- | ---------------------- | | --------------- | --------------------------------------------------------------- | ----------------------------- | ---------------------- |
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:latest][gh] | ![Image Size][shield-latest] | Stable latest tagged image. | | 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 latest 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 latest tagged image. | | Docker Hub | [docker.io/girlbossceo/conduwuit:latest][dh] | ![Image Size][shield-latest] | Stable tagged image. |
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:main][gh] | ![Image Size][shield-main] | Stable main branch. | | GitHub Registry | [ghcr.io/girlbossceo/conduwuit:main][gh] | ![Image Size][shield-main] | Stable main branch. |
| GitLab Registry | [registry.gitlab.com/conduwuit/conduwuit:main][gl] | ![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. | | Docker Hub | [docker.io/girlbossceo/conduwuit:main][dh] | ![Image Size][shield-main] | Stable main branch. |
[dh]: https://hub.docker.com/r/girlbossceo/conduwuit [dh]: https://hub.docker.com/repository/docker/girlbossceo/conduwuit
[gh]: https://github.com/girlbossceo/conduwuit/pkgs/container/conduwuit [gh]: https://github.com/girlbossceo/conduwuit/pkgs/container/conduwuit
[gl]: https://gitlab.com/conduwuit/conduwuit/container_registry/6369729 [gl]: https://gitlab.com/conduwuit/conduwuit/container_registry/6351657
[shield-latest]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/latest [shield-latest]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/latest
[shield-main]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main [shield-main]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main
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 Use
```bash ```bash
docker image pull $LINK docker image pull <link>
``` ```
to pull it to your machine. to pull it to your machine.
@@ -43,86 +39,57 @@ When you have the image you can simply run it with
docker run -d -p 8448:6167 \ docker run -d -p 8448:6167 \
-v db:/var/lib/conduwuit/ \ -v db:/var/lib/conduwuit/ \
-e CONDUWUIT_SERVER_NAME="your.server.name" \ -e CONDUWUIT_SERVER_NAME="your.server.name" \
-e CONDUWUIT_DATABASE_BACKEND="rocksdb" \
-e CONDUWUIT_ALLOW_REGISTRATION=false \ -e CONDUWUIT_ALLOW_REGISTRATION=false \
--name conduwuit $LINK --name conduit <link>
``` ```
or you can use [docker compose](#docker-compose). or you can use [docker compose](#docker-compose).
The `-d` flag lets the container run in detached mode. You may supply an The `-d` flag lets the container run in detached mode. You may supply an optional `conduwuit.toml` config file, the example config can be found [here](../configuration/examples.md).
optional `conduwuit.toml` config file, the example config can be found You can pass in different env vars to change config values on the fly. You can even configure conduwuit completely by using env vars. For an overview of possible
[here](../configuration/examples.md). You can pass in different env vars to values, please take a look at the [`docker-compose.yml`](docker-compose.yml) file.
change config values on the fly. You can even configure conduwuit completely by
using env vars. For an overview of possible values, please take a look at the
[`docker-compose.yml`](docker-compose.yml) file.
If you just want to test conduwuit for a short time, you can use the `--rm` If you just want to test conduwuit for a short time, you can use the `--rm` flag, which will clean up everything related to your container after you stop it.
flag, which will clean up everything related to your container after you stop
it.
### Docker-compose ### Docker-compose
If the `docker run` command is not for you or your setup, you can also use one If the `docker run` command is not for you or your setup, you can also use one of the provided `docker-compose` files.
of the provided `docker-compose` files.
Depending on your proxy setup, you can use one of the following files; Depending on your proxy setup, you can use one of the following files;
- If you already have a `traefik` instance set up, use - If you already have a `traefik` instance set up, use [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml)
[`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml) - If you don't have a `traefik` instance set up and would like to use it, use [`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)
- If you don't have a `traefik` instance set up and would like to use it, use - If you want a setup that works out of the box with `caddy-docker-proxy`, use [`docker-compose.with-caddy.yml`](docker-compose.with-caddy.yml) and replace all `example.com` placeholders with your own domain
[`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)
- If you want a setup that works out of the box with `caddy-docker-proxy`, use
[`docker-compose.with-caddy.yml`](docker-compose.with-caddy.yml) and replace all
`example.com` placeholders with your own domain
- For any other reverse proxy, use [`docker-compose.yml`](docker-compose.yml) - For any other reverse proxy, use [`docker-compose.yml`](docker-compose.yml)
When picking the traefik-related compose file, rename it so it matches When picking the traefik-related compose file, rename it so it matches `docker-compose.yml`, and
`docker-compose.yml`, and rename the override file to rename the override file to `docker-compose.override.yml`. Edit the latter with the values you want
`docker-compose.override.yml`. Edit the latter with the values you want for your for your server.
server.
When picking the `caddy-docker-proxy` compose file, it's important to first When picking the `caddy-docker-proxy` compose file, it's important to first create the `caddy` network before spinning up the containers:
create the `caddy` network before spinning up the containers:
```bash ```bash
docker network create caddy docker network create caddy
``` ```
After that, you can rename it so it matches `docker-compose.yml` and spin up the After that, you can rename it so it matches `docker-compose.yml` and spin up the containers!
containers!
Additional info about deploying conduwuit can be found [here](generic.md). Additional info about deploying conduwuit can be found [here](generic.md).
### Build ### Build
Official conduwuit images are built using Nix's 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:
[`buildLayeredImage`][nix-buildlayeredimage]. This ensures all OCI images are
repeatable and reproducible by anyone, keeps the images lightweight, and can be
built offline.
This also ensures portability of our images because `buildLayeredImage` builds ```bash
OCI images, not Docker images, and works with other container software. docker compose up
```
The OCI images are OS-less with only a very minimal environment of the `tini` This will also start the container right afterwards, so if want it to run in detached mode, you also should use the `-d` flag.
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 ### Run
If you already have built the image or want to use one from the registries, you If you already have built the image or want to use one from the registries, you can just start the container and everything else in the compose file in detached mode with:
can just start the container and everything else in the compose file in detached
mode with:
```bash ```bash
docker compose up -d docker compose up -d
@@ -132,25 +99,19 @@ docker compose up -d
### Use Traefik as Proxy ### Use Traefik as Proxy
As a container user, you probably know about Traefik. It is a easy to use As a container user, you probably know about Traefik. It is a easy to use reverse proxy for making
reverse proxy for making containerized app and services available through the containerized app and services available through the web. With the two provided files,
web. With the two provided files,
[`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml) (or [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml) (or
[`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)) and [`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)) and
[`docker-compose.override.yml`](docker-compose.override.yml), it is equally easy [`docker-compose.override.yml`](docker-compose.override.yml), it is equally easy to deploy
to deploy and use conduwuit, with a little caveat. If you already took a look at and use conduwuit, with a little caveat. If you already took a look at the files, then you should have
the files, then you should have seen the `well-known` service, and that is the seen the `well-known` service, and that is the little caveat. Traefik is simply a proxy and
little caveat. Traefik is simply a proxy and loadbalancer and is not able to loadbalancer and is not able to serve any kind of content, but for conduwuit to federate, we need to
serve any kind of content, but for conduwuit to federate, we need to either either expose ports `443` and `8448` or serve two endpoints `.well-known/matrix/client` and
expose ports `443` and `8448` or serve two endpoints `.well-known/matrix/client` `.well-known/matrix/server`.
and `.well-known/matrix/server`.
With the service `well-known` we use a single `nginx` container that will serve With the service `well-known` we use a single `nginx` container that will serve those two files.
those two files.
## Voice communication ## Voice communication
See the [TURN](../turn.md) page. 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
-5
View File
@@ -1,5 +0,0 @@
# conduwuit for FreeBSD
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.
Contributions for getting conduwuit packaged are welcome.
+32 -153
View File
@@ -1,71 +1,35 @@
# Generic deployment documentation # Generic deployment documentation
> ### Getting help > ## Getting help
> >
> If you run into any problems while setting up conduwuit, ask us in > If you run into any problems while setting up conduwuit, ask us
> `#conduwuit:puppygock.gay` or [open an issue on > in `#conduwuit:puppygock.gay` or [open an issue on GitHub](https://github.com/girlbossceo/conduwuit/issues/new).
> GitHub](https://github.com/girlbossceo/conduwuit/issues/new).
## Installing conduwuit ## Installing conduwuit
### Static prebuilt binary You may simply download the binary that fits your machine. Run `uname -m` to see what you need.
You may simply download the binary that fits your machine architecture (x86_64 Prebuilt binaries can be downloaded from the latest tagged release [here](https://github.com/girlbossceo/conduwuit/releases/latest).
or aarch64). Run `uname -m` to see what you need.
Prebuilt fully static musl binaries can be downloaded from the latest tagged The latest tagged release also includes the Debian packages.
release [here](https://github.com/girlbossceo/conduwuit/releases/latest) or
`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/> 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.
These can be curl'd directly from. `ci-bins` are CI workflow binaries by commit Otherwise, follow standard Rust project build guides (installing git and cloning the repo, getting the Rust toolchain via rustup, installing LLVM toolchain + libclang, installing liburing for io_uring and RocksDB, etc).
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, 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
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.
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`
## Adding a conduwuit user ## Adding a conduwuit user
While conduwuit can run as any user it is better to use dedicated users for While conduwuit can run as any user it is better to use dedicated users for different services. This also allows
different services. This also allows you to make sure that the file permissions you to make sure that the file permissions are correctly set up.
are correctly set up.
In Debian, you can use this command to create a conduwuit user: In Debian or Fedora/RHEL, you can use this command to create a conduwuit user:
```bash ```bash
sudo adduser --system conduwuit --group --disabled-login --no-create-home sudo adduser --system conduwuit --group --disabled-login --no-create-home
``` ```
For distros without `adduser` (or where it's a symlink to `useradd`): For distros without `adduser`:
```bash ```bash
sudo useradd -r --shell /usr/bin/nologin --no-create-home conduwuit sudo useradd -r --shell /usr/bin/nologin --no-create-home conduwuit
@@ -73,62 +37,23 @@ sudo useradd -r --shell /usr/bin/nologin --no-create-home conduwuit
## Forwarding ports in the firewall or the router ## Forwarding ports in the firewall or the router
Matrix's default federation port is port 8448, and clients must be using port 443. conduwuit uses the ports 443 and 8448 both of which need to be open in the firewall.
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 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.
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 ## Setting up a systemd service
Two example systemd units for conduwuit can be found 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.
[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 ## Creating the conduwuit configuration file
Now we need to create the conduwuit's config file in Now we need to create the conduwuit's config file in `/etc/conduwuit/conduwuit.toml`. The example config can be found at [conduwuit-example.toml](../configuration/examples.md).**Please take a moment to read it. You need to change at least the server name.**
`/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.**
RocksDB is the only supported database backend. RocksDB is the only supported database backend.
## Setting the correct file permissions ## Setting the correct file permissions
If you are using a dedicated user for conduwuit, you will need to allow it to 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:
read the config. To do that you can run this:
```bash ```bash
sudo chown -R root:root /etc/conduwuit sudo chown -R root:root /etc/conduwuit
@@ -145,18 +70,19 @@ sudo chmod 700 /var/lib/conduwuit/
## Setting up the Reverse Proxy ## Setting up the Reverse Proxy
We recommend Caddy as a reverse proxy, as it is trivial to use, handling TLS certificates, reverse proxy headers, etc transparently with proper defaults. 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 is the recommended reverse proxy for new users and is very trivial to use (handles TLS, reverse proxy headers, etc transparently with proper defaults).
For other software, please refer to their respective documentation or online guides.
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.
### Caddy ### Caddy
After installing Caddy via your preferred method, create `/etc/caddy/conf.d/conduwuit_caddyfile` Create `/etc/caddy/conf.d/conduwuit_caddyfile` and enter this (substitute for your server name).
and enter this (substitute for your server name).
```caddyfile ```caddy
your.server.name, your.server.name:8448 { your.server.name, your.server.name:8448 {
# TCP reverse_proxy # TCP
reverse_proxy 127.0.0.1:6167 reverse_proxy 127.0.0.1:6167
# UNIX socket # UNIX socket
#reverse_proxy unix//run/conduwuit/conduwuit.sock #reverse_proxy unix//run/conduwuit/conduwuit.sock
} }
@@ -168,45 +94,6 @@ That's it! Just start and enable the service and you're set.
sudo systemctl enable --now caddy sudo systemctl enable --now caddy
``` ```
### Other Reverse Proxies
As we would prefer our users to use Caddy, we will not provide configuration files for other proxys.
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>
For Apache and Nginx there are many examples available online.
Lighttpd is not supported as it seems to mess with the `X-Matrix` Authorization
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 httpd from messing with the `X-Matrix` header (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're done ## You're done
Now you can start conduwuit with: Now you can start conduwuit with:
@@ -223,26 +110,19 @@ sudo systemctl enable conduwuit
## How do I know it works? ## How do I know it works?
You can open [a Matrix client](https://matrix.org/ecosystem/clients), enter your You can open [a Matrix client](https://matrix.org/ecosystem/clients), enter your homeserver and try to register.
homeserver and try to register.
You can also use these commands as a quick health check (replace You can also use these commands as a quick health check (replace `your.server.name`).
`your.server.name`).
```bash ```bash
curl https://your.server.name/_conduwuit/server_version $ curl https://your.server.name/_conduwuit/server_version
# If using port 8448 # If using port 8448
curl https://your.server.name:8448/_conduwuit/server_version $ 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 - To check if your server can talk with other homeservers, you can use the [Matrix Federation Tester](https://federationtester.matrix.org/).
[Matrix Federation Tester](https://federationtester.matrix.org/). If you can If you can register but cannot join federated rooms check your config again and also check if the port 8448 is open and forwarded correctly.
register but cannot join federated rooms check your config again and also check
if the port 8448 is open and forwarded correctly.
# What's next? # What's next?
@@ -252,5 +132,4 @@ For Audio/Video call functionality see the [TURN Guide](../turn.md).
## Appservices ## Appservices
If you want to set up an appservice, take a look at the [Appservice If you want to set up an appservice, take a look at the [Appservice Guide](../appservices.md).
Guide](../appservices.md).
-8
View File
@@ -1,8 +0,0 @@
# 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.
+8 -76
View File
@@ -1,15 +1,11 @@
# conduwuit for NixOS # conduwuit for NixOS
conduwuit can be acquired by Nix (or [Lix][lix]) from various places: conduwuit can be acquired by [Lix][lix] from various places:
* The `flake.nix` at the root of the repo * The `flake.nix` at the root of the repo
* The `default.nix` at the root of the repo * The `default.nix` at the root of the repo
* From conduwuit's binary cache * 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 A binary cache for conduwuit that the CI/CD publishes to is available at the
following places (both are the same just different names): following places (both are the same just different names):
@@ -21,88 +17,24 @@ https://attic.kennel.juneis.dog/conduwuit
conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE=
``` ```
The binary caches were recreated some months ago due to attic issues. The old public The binary caches have been recreated recently due to attic issues. The old public keys were:
keys were:
``` ```
conduit:Isq8FGyEC6FOXH6nD+BOeAA+bKp6X6UIbupSlGEPuOg= conduit:Isq8FGyEC6FOXH6nD+BOeAA+bKp6X6UIbupSlGEPuOg=
conduwuit:lYPVh7o1hLu1idH4Xt2QHaRa49WRGSAqzcfFd94aOTw= conduwuit:lYPVh7o1hLu1idH4Xt2QHaRa49WRGSAqzcfFd94aOTw=
``` ```
If needed, we have a binary cache on Cachix but it is only limited to 5GB: If specifying a URL in your flake, please use the GitHub remote: `github:girlbossceo/conduwuit`
``` The `flake.nix` and `default.nix` do not (currently) provide a NixOS module, so
https://conduwuit.cachix.org (for now) [`services.matrix-conduit`][module] from Nixpkgs should be used to
conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg= configure conduwuit.
```
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` 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] or `default.nix` and set [`services.matrix-conduit.package`][package]
appropriately to use conduwuit instead of Conduit. appropriately.
### 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/ [lix]: https://lix.systems/
[module]: https://search.nixos.org/options?channel=unstable&query=services.matrix-conduit [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 [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
+9 -118
View File
@@ -1,131 +1,22 @@
# Development # Development
Information about developing the project. If you are only interested in using Information about developing the project. If you are only interested in using
it, you can safely ignore this page. If you plan on contributing, see the it, you can safely ignore this section. If you plan on contributing, see the
[contributor's guide](./contributing.md). [contributor's guide](contributing.md).
## 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, better client/server interop
hacks upstream won't accept, etc
- [facebook/rocksdb][2]: <https://github.com/girlbossceo/rocksdb> - liburing
build fixes and GCC debug build fix
- [tikv/jemallocator][3]: <https://github.com/girlbossceo/jemallocator> - musl
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 conduwuit console CLI
- [rust-rocksdb/rust-rocksdb][5]:
<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
## Debugging with `tokio-console` ## Debugging with `tokio-console`
[`tokio-console`][7] can be a useful tool for debugging and profiling. To make a [`tokio-console`][1] can be a useful tool for debugging and profiling. To make
`tokio-console`-enabled build of conduwuit, enable the `tokio_console` feature, a `tokio-console`-enabled build of conduwuit, enable the `tokio_console` feature,
disable the default `release_max_log_level` feature, and set the `--cfg disable the default `release_max_log_level` feature, and set the
tokio_unstable` flag to enable experimental tokio APIs. A build might look like `--cfg tokio_unstable` flag to enable experimental tokio APIs. A build might
this: look like this:
```bash ```bash
RUSTFLAGS="--cfg tokio_unstable" cargo +nightly build \ RUSTFLAGS="--cfg tokio_unstable" cargo build \
--release \ --release \
--no-default-features \ --no-default-features \
--features=systemd,element_hacks,gzip_compression,brotli_compression,zstd_compression,tokio_console --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 [1]: https://docs.rs/tokio-console/latest/tokio_console/
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/
[4]: https://github.com/zyansheep/rustyline-async/
[5]: https://github.com/rust-rocksdb/rust-rocksdb/
[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
+34 -138
View File
@@ -1,194 +1,90 @@
# Hot Reloading ("Live" Development) # Hot Reloading ("Live" Development)
Note that hot reloading has not been refactored in quite a while and is not
guaranteed to work at this time.
### Summary ### Summary
When developing in debug-builds with the nightly toolchain, conduwuit is modular When developing in debug-builds with the nightly toolchain, conduwuit is modular using dynamic libraries and various parts of the application are hot-reloadable while the server is running: http api handlers, admin commands, services, database, etc. These are all split up into individual workspace crates as seen in the `src/` directory. Changes to sourcecode in a crate rebuild that crate and subsequent crates depending on it. Reloading then occurs for the changed crates.
using dynamic libraries and various parts of the application are hot-reloadable
while the server is running: http api handlers, admin commands, services,
database, etc. These are all split up into individual workspace crates as seen
in the `src/` directory. Changes to sourcecode in a crate rebuild that crate and
subsequent crates depending on it. Reloading then occurs for the changed crates.
Release builds still produce static binaries which are unaffected. Rust's Release builds still produce static binaries which are unaffected. Rust's soundness guarantees are in full force. Thus you cannot hot-reload release binaries.
soundness guarantees are in full force. Thus you cannot hot-reload release
binaries.
### Requirements ### Requirements
Currently, this development setup only works on x86_64 and aarch64 Linux glibc. Currently, this development setup only works on x86_64 and aarch64 Linux glibc. [musl explicitly does not support hot reloadable libraries, and does not implement `dlclose`][2]. macOS does not fully support our usage of `RTLD_GLOBAL` possibly due to some thread-local issues. [This Rust issue][3] may be of relevance, specifically [this comment][4]. It may be possible to get it working on only very modern macOS versions such as at least Sonoma, as currently loading dylibs is supported, but not unloading them in our setup, and the cited comment mentions an Apple WWDC confirming there have been TLS changes to somewhat make this possible.
[musl explicitly does not support hot reloadable libraries, and does not
implement `dlclose`][2]. macOS does not fully support our usage of `RTLD_GLOBAL`
possibly due to some thread-local issues. [This Rust issue][3] may be of
relevance, specifically [this comment][4]. It may be possible to get it working
on only very modern macOS versions such as at least Sonoma, as currently loading
dylibs is supported, but not unloading them in our setup, and the cited comment
mentions an Apple WWDC confirming there have been TLS changes to somewhat make
this possible.
As mentioned above this requires the nightly toolchain. This is due to reliance As mentioned above this requires the nightly toolchain. This is due to reliance on various Cargo.toml features that are only available on nightly, most specifically `RUSTFLAGS` in Cargo.toml. Some of the implementation could also be simpler based on other various nightly features. We hope lots of nightly features start making it out of nightly sooner as there have been dozens of very helpful features that have been stuck in nightly ("unstable") for at least 5+ years that would make this simpler. We encourage greater community consensus to move these features into stability.
on various Cargo.toml features that are only available on nightly, most
specifically `RUSTFLAGS` in Cargo.toml. Some of the implementation could also be
simpler based on other various nightly features. We hope lots of nightly
features start making it out of nightly sooner as there have been dozens of very
helpful features that have been stuck in nightly ("unstable") for at least 5+
years that would make this simpler. We encourage greater community consensus to
move these features into stability.
This currently only works on x86_64/aarch64 Linux with a glibc C library. musl C This currently only works on x86_64/aarch64 Linux with a glibc C library. musl C library, macOS, and likely other host architectures are not supported (if other architectures work, feel free to let us know and/or make a PR updating this). This should work on GNU ld and lld (rust-lld) and gcc/clang, however if you happen to have linker issues it's recommended to try using `mold` or `gold` linkers, and please let us know in the [conduwuit Matrix room][7] the linker error and what linker solved this issue so we can figure out a solution. Ideally there should be minimal friction to using this, and in the future a build script (`build.rs`) may be suitable to making this easier to use if the capabilities allow us.
library, macOS, and likely other host architectures are not supported (if other
architectures work, feel free to let us know and/or make a PR updating this).
This should work on GNU ld and lld (rust-lld) and gcc/clang, however if you
happen to have linker issues it's recommended to try using `mold` or `gold`
linkers, and please let us know in the [conduwuit Matrix room][7] the linker
error and what linker solved this issue so we can figure out a solution. Ideally
there should be minimal friction to using this, and in the future a build script
(`build.rs`) may be suitable to making this easier to use if the capabilities
allow us.
### Usage ### Usage
As of 19 May 2024, the instructions for using this are: As of 19 May 2024, the instructions for using this are:
0. Have patience. Don't hesitate to join the [conduwuit Matrix room][7] to 0. Have patience. Don't hesitate to join the [conduwuit Matrix room][7] to receive help using this. As indicated by the various rustflags used and some of the interesting issues linked at the bottom, this is definitely not something the Rust ecosystem or toolchain is used to doing.
receive help using this. As indicated by the various rustflags used and some
of the interesting issues linked at the bottom, this is definitely not something
the Rust ecosystem or toolchain is used to doing.
1. Install the nightly toolchain using rustup. You may need to use `rustup 1. Install the nightly toolchain using rustup. You may need to use `rustup override set nightly` in your local conduwuit directory, or use `cargo +nightly` for all actions.
override set nightly` in your local conduwuit directory, or use `cargo
+nightly` for all actions.
2. Uncomment `cargo-features` at the top level / root Cargo.toml 2. Uncomment `cargo-features` at the top level / root Cargo.toml
3. Scroll down to the `# Developer profile` section and uncomment ALL the 3. Scroll down to the `# Developer profile` section and uncomment ALL the rustflags for each dev profile and their respective packages.
rustflags for each dev profile and their respective packages.
4. In each workspace crate's Cargo.toml (everything under `src/*` AND 4. In each workspace crate's Cargo.toml (everything under `src/*` AND `deps/rust-rocksdb/Cargo.toml`), uncomment the `dylib` crate type under `[lib]`.
`deps/rust-rocksdb/Cargo.toml`), uncomment the `dylib` crate type under
`[lib]`.
5. Due to [this rpath issue][5], you must export the `LD_LIBRARY_PATH` 5. Due to [this rpath issue][5], you must export the `LD_LIBRARY_PATH` environment variable to your nightly Rust toolchain library directory. If using rustup (hopefully), use this: `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/`
environment variable to your nightly Rust toolchain library directory. If
using rustup (hopefully), use this: `export
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/`
6. Start the server. You can use `cargo +nightly run` for this along with the 6. Start the server. You can use `cargo +nightly run` for this along with the standard.
standard.
7. Make some changes where you need to. 7. Make some changes where you need to.
8. In a separate terminal window in the same directory (or using a terminal 8. In a separate terminal window in the same directory (or using a terminal multiplexer like tmux), run the *build* Cargo command `cargo +nightly build`. Cargo should only rebuild what was changed / what's necessary, so it should not be rebuilding all the crates.
multiplexer like tmux), run the *build* Cargo command `cargo +nightly build`.
Cargo should only rebuild what was changed / what's necessary, so it should
not be rebuilding all the crates.
9. In your conduwuit server terminal, hit/send `CTRL+C` signal. This will tell 9. In your conduwuit server terminal, hit/send `CTRL+C` signal. This will tell conduwuit to find which libraries need to be reloaded, and reloads them as necessary.
conduwuit to find which libraries need to be reloaded, and reloads them as
necessary.
10. If there were no errors, it will tell you it successfully reloaded `#` 10. If there were no errors, it will tell you it successfully reloaded `#` modules, and your changes should now be visible. Repeat 7 - 9 as needed.
modules, and your changes should now be visible. Repeat 7 - 9 as needed.
To shutdown conduwuit in this setup, hit/send `CTRL+\`. Normal builds still To shutdown conduwuit in this setup, hit/send `CTRL+\`. Normal builds still shutdown with `CTRL+C` as usual.
shutdown with `CTRL+C` as usual.
Steps 1 - 5 are the initial first-time steps for using this. To remove the hot Steps 1 - 5 are the initial first-time steps for using this. To remove the hot reload setup, revert/comment all the Cargo.toml changes.
reload setup, revert/comment all the Cargo.toml changes.
As mentioned in the requirements section, if you happen to have some linker As mentioned in the requirements section, if you happen to have some linker issues, try using the `-fuse-ld=` rustflag and specify mold or gold in all the `rustflags` definitions in the top level Cargo.toml, and please let us know in the [conduwuit Matrix room][7] the problem. mold can be installed typically through your distro, and gold is provided by the binutils package.
issues, try using the `-fuse-ld=` rustflag and specify mold or gold in all the
`rustflags` definitions in the top level Cargo.toml, and please let us know in
the [conduwuit Matrix room][7] the problem. mold can be installed typically
through your distro, and gold is provided by the binutils package.
It's possible a helper script can be made to do all of this, or most preferably It's possible a helper script can be made to do all of this, or most preferably a specially made build script (build.rs). `cargo watch` support will be implemented soon which will eliminate the need to manually run `cargo build` all together.
a specially made build script (build.rs). `cargo watch` support will be
implemented soon which will eliminate the need to manually run `cargo build` all
together.
### Addendum ### Addendum
Conduit was inherited as a single crate without modularity or reloading in its Conduit was inherited as a single crate without modularity or reloading in its design. Reasonable partitioning and abstraction allowed a split into several crates, though many circular dependencies had to be corrected. The resulting crates now form a directed graph as depicted in figures below. The interfacing between these crates is still extremely broad which is not mitigable.
design. Reasonable partitioning and abstraction allowed a split into several
crates, though many circular dependencies had to be corrected. The resulting
crates now form a directed graph as depicted in figures below. The interfacing
between these crates is still extremely broad which is not mitigable.
Initially [hot_lib_reload][6] was investigated but found appropriate for a Initially [hot_lib_reload][6] was investigated but found appropriate for a project designed with modularity through limited interfaces, not a large and complex existing codebase. Instead a bespoke solution built directly on [libloading][8] satisfied our constraints. This required relatively minimal modifications and zero maintenance burden compared to what would be required otherwise. The technical difference lies with relocation processing: we leverage global bindings (`RTLD_GLOBAL`) in a very intentional way. Most libraries and off-the-shelf module systems (such as [hot_lib_reload][6]) restrict themselves to local bindings (`RTLD_LOCAL`). This allows them to release software to multiple platforms with much greater consistency, but at the cost of burdening applications to explicitly manage these bindings. In our case with an optional feature for developers, we shrug any such requirement to enjoy the cost/benefit on platforms where global relocations are properly cooperative.
project designed with modularity through limited interfaces, not a large and
complex existing codebase. Instead a bespoke solution built directly on
[libloading][8] satisfied our constraints. This required relatively minimal
modifications and zero maintenance burden compared to what would be required
otherwise. The technical difference lies with relocation processing: we leverage
global bindings (`RTLD_GLOBAL`) in a very intentional way. Most libraries and
off-the-shelf module systems (such as [hot_lib_reload][6]) restrict themselves
to local bindings (`RTLD_LOCAL`). This allows them to release software to
multiple platforms with much greater consistency, but at the cost of burdening
applications to explicitly manage these bindings. In our case with an optional
feature for developers, we shrug any such requirement to enjoy the cost/benefit
on platforms where global relocations are properly cooperative.
To make use of `RTLD_GLOBAL` the application has to be oriented as a directed To make use of `RTLD_GLOBAL` the application has to be oriented as a directed acyclic graph. The primary rule is simple and illustrated in the figure below: **no crate is allowed to call a function or use a variable from a crate below it.**
acyclic graph. The primary rule is simple and illustrated in the figure below:
**no crate is allowed to call a function or use a variable from a crate below
it.**
![conduwuit's dynamic library setup diagram - created by Jason ![conduwuit's dynamic library setup diagram - created by Jason Volk](assets/libraries.png)
Volk](assets/libraries.png)
When a symbol is referenced between crates they become bound: **crates cannot be When a symbol is referenced between crates they become bound: **crates cannot be unloaded until their calling crates are first unloaded.** Thus we start the reloading process from the crate which has no callers. There is a small problem though: the first crate is called by the base executable itself! This is solved by using an `RTLD_LOCAL` binding for just one link between the main executable and the first crate, freeing the executable from all modules as no global binding ever occurs between them.
unloaded until their calling crates are first unloaded.** Thus we start the
reloading process from the crate which has no callers. There is a small problem
though: the first crate is called by the base executable itself! This is solved
by using an `RTLD_LOCAL` binding for just one link between the main executable
and the first crate, freeing the executable from all modules as no global
binding ever occurs between them.
![conduwuit's reload and load order diagram - created by Jason ![conduwuit's reload and load order diagram - created by Jason Volk](assets/reload_order.png)
Volk](assets/reload_order.png)
Proper resource management is essential for reliable reloading to occur. This is Proper resource management is essential for reliable reloading to occur. This is a very basic ask in RAII-idiomatic Rust and the exposure to reloading hazards is remarkably low, generally stemming from poor patterns and practices. Unfortunately static analysis doesn't enforce reload-safety programmatically (though it could one day), for now hazards can be avoided by knowing a few basic do's and dont's:
a very basic ask in RAII-idiomatic Rust and the exposure to reloading hazards is
remarkably low, generally stemming from poor patterns and practices.
Unfortunately static analysis doesn't enforce reload-safety programmatically
(though it could one day), for now hazards can be avoided by knowing a few basic
do's and dont's:
1. Understand that code is memory. Just like one is forbidden from referencing 1. Understand that code is memory. Just like one is forbidden from referencing free'd memory, one must not transfer control to free'd code. Exposure to this is primarily from two things:
free'd memory, one must not transfer control to free'd code. Exposure to this
is primarily from two things:
- Callbacks, which this project makes very little use of. - Callbacks, which this project makes very little use of.
- Async tasks, which are addressed below. - Async tasks, which are addressed below.
2. Tie all resources to a scope or object lifetime with greatest possible 2. Tie all resources to a scope or object lifetime with greatest possible symmetry (locality). For our purposes this applies to code resources, which means async blocks and tokio tasks.
symmetry (locality). For our purposes this applies to code resources, which
means async blocks and tokio tasks.
- **Never spawn a task without receiving and storing its JoinHandle**. - **Never spawn a task without receiving and storing its JoinHandle**.
- **Always wait on join handles** before leaving a scope or in another cleanup - **Always wait on join handles** before leaving a scope or in another cleanup function called by an owning scope.
function called by an owning scope.
3. Know any minor specific quirks documented in code or here: 3. Know any minor specific quirks documented in code or here:
- Don't use `tokio::spawn`, instead use our `Handle` in `core/server.rs`, which - Don't use `tokio::spawn`, instead use our `Handle` in `core/server.rs`, which is reachable in most of the codebase via `services()` or other state. This is due to some bugs or assumptions made in tokio, as it happens in `unsafe {}` blocks, which are mitigated by circumventing some thread-local variables. Using runtime handles is good practice in any case.
is reachable in most of the codebase via `services()` or other state. This is
due to some bugs or assumptions made in tokio, as it happens in `unsafe {}`
blocks, which are mitigated by circumventing some thread-local variables. Using
runtime handles is good practice in any case.
The initial implementation PR is available [here][1]. The initial implementation PR is available [here][1].
### Interesting related issues/bugs ### Interesting related issues/bugs
- [DT_RUNPATH produced in binary with rpath = true is wrong (cargo)][5] - [DT_RUNPATH produced in binary with rpath = true is wrong (cargo)][5]
- [Disabling MIR Optimization in Rust Compilation - [Disabling MIR Optimization in Rust Compilation (cargo)](https://internals.rust-lang.org/t/disabling-mir-optimization-in-rust-compilation/19066/5)
(cargo)](https://internals.rust-lang.org/t/disabling-mir-optimization-in-rust-compilation/19066/5) - [Workspace-level metadata (cargo-deb)](https://github.com/kornelski/cargo-deb/issues/68)
- [Workspace-level metadata
(cargo-deb)](https://github.com/kornelski/cargo-deb/issues/68)
[1]: https://github.com/girlbossceo/conduwuit/pull/387 [1]: https://github.com/girlbossceo/conduwuit/pull/387
[2]: https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries [2]: https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries
+8 -19
View File
@@ -5,27 +5,16 @@
Have a look at [Complement's repository][complement] for an explanation of what Have a look at [Complement's repository][complement] for an explanation of what
it is. it is.
To test against Complement, with Nix (or [Lix](https://lix.systems) and To test against Complement, with [Lix][lix] and direnv installed and set up, you can:
[direnv installed and set up][direnv] (run `direnv allow` after setting up the hook), you can:
* Run `./bin/complement "$COMPLEMENT_SRC"` to build a Complement image, run * Run `./bin/complement "$COMPLEMENT_SRC" ./path/to/logs.jsonl ./path/to/results.jsonl`
the tests, and output the logs and results to the specified paths. This will also output the OCI image to build a Complement image, run the tests, and output the logs and results
at `result` to the specified paths. This will also output the OCI image at `result`
* Run `nix build .#complement` from the root of the repository to just build a * Run `nix build .#complement` from the root of the repository to just build a
Complement OCI image outputted to `result` (it's a `.tar.gz` file) Complement OCI image outputted to `result` (it's a `.tar.gz` file)
* Or download the latest Complement OCI image from the CI workflow artifacts * Or download the latest Complement OCI image from the CI workflow artifacts output
output from the commit/revision you want to test (e.g. from main) from the commit/revision you want to test (e.g. from main) [here][ci-workflows]
[here][ci-workflows]
If you want to use your own prebuilt OCI image (such as from our CI) without needing
Nix installed, put the image at `complement_oci_image.tar.gz` in the root of the repo
and run the script.
If you're on macOS and need to build an image, run `nix build .#linux-complement`.
We have a Complement fork as some tests have needed to be fixed. This can be found
at: <https://github.com/girlbossceo/complement>
[lix]: https://lix.systems/
[ci-workflows]: https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml?query=event%3Apush+is%3Asuccess+actor%3Agirlbossceo [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 [complement]: https://github.com/matrix-org/complement
[direnv]: https://direnv.net/docs/hook.html
+197
View File
@@ -0,0 +1,197 @@
#### **Note: This list may not up to date. There are rapidly more and more improvements, fixes, changes, etc being made that it is becoming more difficult to maintain this list. I recommend that you give conduwuit a try and see the differences for yourself. If you have any concerns, feel free to join the conduwuit Matrix room and ask any pre-usage questions.**
### list of features, bug fixes, etc that conduwuit does that Conduit does not
Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
## Performance
- Concurrency support for individual homeserver key fetching for faster remote room joins and room joins that will error less frequently
- Send `Cache-Control` response header with `immutable` and 1 year cache length for all media requests (download and thumbnail) to instruct clients to cache media, and reduce server load from media requests that could be otherwise cached
- Add feature flags and config options to enable/build with zstd, brotli, and/or gzip HTTP body compression (response and request)
- Eliminate all usage of the thread-blocking `getaddrinfo(3)` call upon DNS queries, significantly improving federation latency/ping and cache DNS results (NXDOMAINs, successful queries, etc) using hickory-dns / hickory-resolver
- Enable HTTP/2 support on all requests
- Vastly improve RocksDB default settings to use new features that help with performance significantly, uses settings tailored to SSDs, various ways to tweak RocksDB, and a conduwuit setting to tell RocksDB to use settings that are tailored to HDDs or slow spinning rust storage or buggy filesystems.
- Implement database flush and cleanup conduwuit operations when using RocksDB
- Implement RocksDB write buffer corking and coalescing in database write-heavy areas
- Perform connection pooling and keepalives where necessary to significantly improve federation performance and latency
- Various config options to tweak connection pooling, request timeouts, connection timeouts, DNS timeouts and settings, etc with good defaults which also help huge with performance via reusing connections and retrying where needed
- Properly get and use the amount of parallelism / tokio workers
- Implement building conduwuit with jemalloc (which extends to the RocksDB jemalloc feature for maximum gains) or hardened_malloc light variant, and io_uring support, and produce CI builds with jemalloc and io_uring by default for performance (Nix doesn't seem to build [hardened_malloc-rs](https://github.com/girlbossceo/hardened_malloc-rs) properly)
- Add support for caching DNS results with hickory-dns / hickory-resolver in conduwuit (not a replacement for a proper resolver cache, but still far better than nothing), also properly falls back on TCP for UDP errors or if a SRV response is too large
- Add config option for using DNS over TCP, and config option for controlling A/AAAA record lookup strategy (e.g. don't query AAAA records if you don't have IPv6 connectivity)
- Overall significant database, Client-Server, and federation performance and latency improvements (check out the ping room leaderboards if you don't believe me :>)
- Add config options for RocksDB compression and bottommost compression, including choosing the algorithm and compression level
- Use [loole](https://github.com/mahdi-shojaee/loole) MPSC channels instead of tokio MPSC channels for huge performance boosts in sending channels (mainly relevant for federation) and presence channels
- Use `tracing`/`log`'s `release_max_level_info` feature to improve performance, build speeds, binary size, and CPU usage in release builds by avoid compiling debug/trace log level macros that users will generally never use (can be disabled with a build-time feature flag)
- Remove some unnecessary checks on EDU handling for incoming transactions, effectively speeding them up
- Simplify, dedupe, etc huge chunks of the codebase, including some that were unnecessary overhead, binary bloats, or preventing compiler/linker optimisations
- Implement zero-copy RocksDB database accessors, substantially improving performance caused by unnecessary memory allocations
## General Fixes/Features
- Add legacy Element client hack fixing password changes and deactivations on legacy Element Android/iOS due to usage of an unspecced `user` field for UIAA
- Raise and improve all the various request timeouts making some things like room joins and client bugs error less or none at all than they should, and make them all user configurable
- Add missing `reason` field to user ban events (`/ban`)
- Safer and cleaner shutdowns across incoming/outgoing requests (graceful shutdown) and the database
- Stop sending `make_join` requests on room joins if 15 servers respond with `M_UNSUPPORTED_ROOM_VERSION` or `M_INVALID_ROOM_VERSION`
- Stop sending `make_join` requests if 50 servers cannot provide `make_join` for us
- Respect *most* client parameters for `/media/` requests (`allow_redirect` still needs work)
- Return joined member count of rooms for push rules/conditions instead of a hardcoded value of 10
- Make `CONDUIT_CONFIG` optional, relevant for container users that configure only by environment variables and no longer need to set `CONDUIT_CONFIG` to an empty string.
- Allow HEAD and PATCH (MSC4138) HTTP requests in CORS for clients (despite not being explicity mentioned in Matrix spec, HTTP spec says all HEAD requests need to behave the same as GET requests, Synapse supports HEAD requests)
- Fix using conduwuit with flake-compat on NixOS
- Resolve and remove some "features" from upstream that result in concurrency hazards, exponential backoff issues, or arbitrary performance limiters
- Find more servers for outbound federation `/hierarchy` requests instead of just the room ID server name
- Support for suggesting servers to join through at `/_matrix/client/v3/directory/room/{roomAlias}`
- Support for suggesting servers to join through us at `/_matrix/federation/v1/query/directory`
- Misc edge-case search fixes (e.g. potentially missing some events)
- Misc `/sync` fixes (e.g. returning unnecessary data or incorrect/invalid responses)
- Add `replaces_state` and `prev_sender` in `unsigned` for state event changes which primarily makes Element's "See history" button on a state event functional
- Fix Conduit not allowing incoming federation requests for various world readable rooms
- Fix Conduit not respecting the client-requested file name on media requests
- Prevent sending junk / non-membership events to `/send_join` and `/send_leave` endpoints
- Only allow the requested membership type on `/send_join` and `/send_leave` endpoints (e.g. don't allow leave memberships on join endpoints)
- Prevent state key impersonation on `/send_join` and `/send_leave` endpoints
- Validate `X-Matrix` origin and request body `"origin"` field on incoming transactions
- Add `GET /_matrix/client/v1/register/m.login.registration_token/validity` endpoint
- Explicitly define support for sliding sync at `/_matrix/client/versions` (`org.matrix.msc3575`)
- Fix seeing empty status messages on user presences
## Moderation
- (Also see [Admin Room](#admin-room) for all the admin commands pertaining to moderation, there's a lot!)
- Add support for room banning/blocking by ID using admin command
- Add support for serving `support` well-known from `[global.well_known]` (MSC1929) (`/.well-known/matrix/support`)
- Config option to forbid publishing rooms to the room directory (`lockdown_public_room_directory`) except for admins
- Admin commands to delete room aliases and unpublish rooms from our room directory
- For all [`/report`](https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3roomsroomidreporteventid) requests: check if the reported event ID belongs to the reported room ID, raise report reasoning character limit to 750, fix broken formatting, make a small delayed random response per spec suggestion on privacy, and check if the sender user is in the reported room.
- Support blocking servers from downloading remote media from, returning a 404
- Don't allow `m.call.invite` events to be sent in public rooms (prevents calling the entire room)
- On new public room creations, only allow moderators to send `m.call.invite`, `org.matrix.msc3401.call`, and `org.matrix.msc3401.call.member` events to prevent unprivileged users from calling the entire room
- Add support for a "global ACLs" feature (`forbidden_remote_server_names`) that blocks inbound remote room invites, room joins by room ID on server name, room joins by room alias on server name, incoming federated joins, and incoming federated room directory requests. This is very helpful for blocking servers that are purely toxic/bad and serve no value in allowing our users to suffer from things like room invite spam or such. Please note that this is not a substitute for room ACLs.
- Add support for a config option to forbid our local users from sending federated room directory requests for (`forbidden_remote_room_directory_server_names`). Similar to above, useful for blocking servers that help prevent our users from wandering into bad areas of Matrix via room directories of those malicious servers.
- Add config option for auto remediating/deactivating local non-admin users who attempt to join bad/forbidden rooms (`auto_deactivate_banned_room_attempts`)
- Deactivating users will remove their profile picture, blurhash, display name, and leave all rooms by default just like Synapse and for additional privacy
- Reject some EDUs from ACL'd users such as read receipts and typing indicators
## Privacy/Security
- Add config option for device name federation with a privacy-friendly default (disabled)
- Add config option for requiring authentication to the `/publicRooms` endpoint (room directory) with a default enabled for privacy
- Add config option for federating `/publicRooms` endpoint (room directory) to other servers with a default disabled for privacy
- Uses proper `argon2` crate by RustCrypto instead of questionable `rust-argon2` crate
- Generate passwords with 25 characters instead of 15
- Config option `ip_range_denylist` to support refusing to send requests (typically federation) to specific IP ranges, typically RFC 1918, non-routable, testnet, etc addresses like Synapse for security (note: this is not a guaranteed protection, and you should be using a firewall with zones if you want guaranteed protection as doing this on the application level is prone to bypasses).
- Config option to block non-admin users from sending room invites or receiving remote room invites. Admin users are still allowed.
- Config option to disable incoming and/or outgoing remote read receipts
- Config option to disable incoming and/or outgoing remote typing indicators
- Config option to disable incoming, outgoing, and/or local presence and for timing out remote users
- Sanitise file names for the `Content-Disposition` header for all media requests (thumbnails, downloads, uploads)
- Media repository on handling `Content-Disposition` and `Content-Type` is fully spec compliant and secured
- Send secure default HTTP headers such as a strong restrictive CSP (see MSC4149), deny iframes, disable `X-XSS-Protection`, disable interest cohort in `Permission-Policy`, etc to mitigate any potential attack surface such as from untrusted media
## Administration/Logging
- Commandline argument to specify the path to a config file instead of relying on `CONDUIT_CONFIG`
- Revamped admin room infrastructure and commands
- Substantially clean up, improve, and fix logging (less noisy dead server logging, registration attempts, more useful troubleshooting logging, proper error propagation, etc)
- Configurable RocksDB logging (`LOG` files) with proper defaults (rotate, max size, verbosity, etc) to stop LOG files from accumulating so much
- Explicit startup error if your configuration allows open registration without a token or such like Synapse with a way to bypass it if needed
- Replace the lightning bolt emoji option with support for setting any arbitrary text (e.g. another emoji) to suffix to all new user registrations, with a conduwuit default of "🏳️‍⚧️"
- Implement config option to auto join rooms upon registration
- Warn on unknown config options specified
- Add `/_conduwuit/server_version` route to return the version of conduwuit without relying on the federation API `/_matrix/federation/v1/version`
- Add `/_conduwuit/local_user_count` route to return the amount of registered active local users on your homeserver *if federation is enabled*
- Add configurable RocksDB recovery modes to aid in recovering corrupted RocksDB databases
- Support config options via `CONDUWUIT_` prefix and accessing non-global struct config options with the `__` split (e.g. `CONDUWUIT_WELL_KNOWN__SERVER`)
- Add support for listening on multiple TCP ports and multiple addresses
- **Opt-in** Sentry.io telemetry and metrics, mainly used for crash reporting
- Log the client IP on various requests such as registrations, banned room join attempts, logins, deactivations, federation transactions, etc
- Fix Conduit dropping some remote server federation response errors
## Maintenance/Stability
- GitLab CI ported to GitHub Actions
- Add support for the Matrix spec compliance test suite [Complement](https://github.com/matrix-org/complement/) via the Nix flake and various other fixes for it
- Implement running and diff'ing Complement results in CI and error if any mismatch occurs to prevent large cases of conduwuit regressions
- Repo is (officially) mirrored to GitHub, GitLab, git.gay, git.girlcock.ceo, sourcehut, and Codeberg (see README.md for their links)
- Docker container images published to GitLab Container Registry, GitHub Container Registry, and Dockerhub
- Extensively revamp the example config to be extremely helpful and useful to 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 dependencies as up to date as possible
- Purge unmaintained/irrelevant/broken database backends (heed, sled, persy) and other unnecessary code or overhead
- webp support for images
- Add cargo audit support to CI
- Add documentation lints via lychee and markdownlint-cli to CI
- CI tests for all sorts of feature matrixes (jemalloc, non-defaullt, all features, etc)
- Add static and dynamic linking smoke tests in CI to prevent any potential linking regressions for Complement, static binaries, Nix devshells, etc
- Add timestamp by commit date when building OCI images for keeping image build reproducibility and still have a meaningful "last modified date" for OCI image
- Add timestamp by commit date via `SOURCE_DATE_EPOCH` for Debian packages
- Startup check if conduwuit running in a container and is listening on 127.0.0.1 (generally containers are using NAT networking and 0.0.0.0 is the intended listening address)
- Add a panic catcher layer to return panic messages in HTTP responses if a panic occurs
- Add full compatibility support for SHA256 media file names instead of base64 file names to overcome filesystem file name length limitations (OS error file name too long) while still retaining upstream database compatibility
- Remove SQLite support due to being very poor performance, difficult to maintain against RocksDB, and is a blocker to significantly improved database code
## Admin Room
- Add support for a console CLI interface that can issue admin commands and output them in your terminal
- Add support for an admin-user-only commandline admin room interface that can be issued in any room with the `\\!admin` or `\!admin` prefix and returns the response as yourself in the same room
- Add admin commands for uptime, server startup, server shutdown, and server restart
- Fix admin room handler to not panic/crash if the admin room command response fails (e.g. too large message)
- Add command to dynamically change conduwuit's tracing log level filter on the fly
- Add admin command to fetch a server's `/.well-known/matrix/support` file
- Add debug admin command to force update user device lists (could potentially resolve some E2EE flukes)
- Implement **RocksDB online backups**, listing RocksDB backups, and listing database file counts all via admin commands
- Add various database visibility commands such as being able to query the getters and iterators used in conduwuit, a very helpful online debugging utility
- Forbid the admin room from being made public or world readable history
- Add `!admin` as a way to call the admin bot
- Extend clear cache admin command to support clearing more caches such as DNS and TLS name overrides
- Admin debug command to send a federation request/ping to a server's `/_matrix/federation/v1/version` endpoint and measures the latency it took
- Add admin command to bulk delete media via a codeblock list of MXC URLs.
- Add admin command to delete both the thumbnail and media MXC URLs from an event ID (e.g. from an abuse report)
- Add admin command to list all the rooms a local user is joined in
- Add admin command to list joined members in a room
- Add admin command to view the room topic of a room
- Add admin command to delete all remote media in the past X minutes as a form of deleting media that you don't want on your server that a remote user posted in a room, a `--force` flag to ignore errors, and support for reading `last modified time` instead of `creation time` for filesystems that don't support file created metadata
- Add admin command to return a room's full/complete state
- Admin debug command to fetch a PDU from a remote server and inserts it into our database/timeline as backfill
- Add admin command to delete media via a specific MXC. This deletes the MXC from our database, and the file locally.
- Add admin commands for banning (blocking) room IDs from our local users joining (admins are always allowed) and evicts all our local users from that room, in addition to bulk room banning support, and blocks room invites (remote and local) to the banned room, as a moderation feature
- Add admin commands to output jemalloc memory stats and memory usage
- Add admin command to get rooms a *remote* user shares with us
- Add debug admin commands to get the earliest and latest PDU in a room
- Add debug admin command to echo a message
- Add admin command to insert rooms tags for a user, most useful for inserting the `m.server_notice` tag on your admin room to make it "persistent" in the "System Alerts" section of Element
- Add experimental admin debug command for Dendrite's `AdminDownloadState` (`/admin/downloadState/{serverName}/{roomID}`) admin API endpoint to download and use a remote server's room state in the room
- Disable URL previews by default in the admin room due to various command outputs having "URLs" in them that clients may needlessly render/request
- Extend memory usage admin server command to support showing memory allocator stats such as jemalloc's
- Add admin debug command to see memory allocator's full extended debug statistics such as jemalloc's
## Misc
- Add guest support for accessing TURN servers via `turn_allow_guests` like Synapse
- Support for creating rooms with custom room IDs like Maunium Synapse (`room_id` request body field to `/createRoom`)
- Query parameter `?format=event|content` for returning either the room state event's content (default) for the full room state event on `/_matrix/client/v3/rooms/{roomId}/state/{eventType}[/{stateKey}]` requests (see <https://github.com/matrix-org/matrix-spec/issues/1047>)
- Send a User-Agent on all of our requests
- Send `avatar_url` on invite room membership events/changes
- Support sending [`well_known` response to client login responses](https://spec.matrix.org/v1.10/client-server-api/#post_matrixclientv3login) if using config option `[well_known.client]`
- Implement `include_state` search criteria support for `/search` requests (response now can include room states)
- Declare various missing Matrix versions and features at `/_matrix/client/versions`
- Implement legacy Matrix `/v1/` media endpoints that some clients and servers may still call
- Config option to change Conduit's behaviour of homeserver key fetching (`query_trusted_key_servers_first`). This option sets whether conduwuit will query trusted notary key servers first before the individual homeserver(s), or vice versa which may help in joining certain rooms.
- Implement unstable MSC2666 support for querying mutual rooms with a user
- Implement unstable MSC3266 room summary API support
- Implement unstable MSC4125 support for specifying servers to join via on federated invites
- Make conduwuit build and be functional under Nix + macOS
- Log out all sessions after unsetting the emergency password
- Assume well-knowns are broken if they exceed past 12288 characters.
- Add support for listening on both HTTP and HTTPS if using direct TLS with conduwuit for usecases such as Complement
- Add config option for disabling RocksDB Direct IO if needed
- Add various documentation on maintaining conduwuit, using RocksDB online backups, some troubleshooting, using admin commands, moderation documentation, etc
- (Developers): Add support for [hot reloadable/"live" modular development](development/hot_reload.md)
- (Developers): Add support for tokio-console
- (Developers): Add support for tracing flame graphs
- No cryptocurrency donations allowed, conduwuit is fully maintained by independent queer maintainers, and with a strong priority on inclusitivity and comfort for protected groups 🏳️‍⚧️
- [Add a community Code of Conduct for all conduwuit community spaces, primarily the Matrix space](https://conduwuit.puppyirl.gay/conduwuit_coc.html)
+5 -2
View File
@@ -4,12 +4,15 @@
{{#include ../README.md:body}} {{#include ../README.md:body}}
#### What's different about your fork than upstream Conduit?
See the [differences](differences.md) page
#### How can I deploy my own? #### How can I deploy my own?
- [Deployment options](deploying.md) - [Deployment options](deploying.md)
If you want to connect an appservice to conduwuit, take a look at the If you want to connect an appservice to conduwuit, take a look at the [appservices documentation](appservices.md).
[appservices documentation](appservices.md).
#### How can I contribute? #### How can I contribute?
+19 -88
View File
@@ -2,11 +2,7 @@
## Moderation ## Moderation
conduwuit has moderation through admin room commands. "binary commands" (medium conduwuit has moderation through admin room commands. "binary commands" (medium priority) and an admin API (low priority) is planned. Some moderation-related config options are available in the example config such as "global ACLs" and blocking media requests to certain servers. See the example config for the moderation config options under the "Moderation / Privacy / Security" section.
priority) and an admin API (low priority) is planned. Some moderation-related
config options are available in the example config such as "global ACLs" and
blocking media requests to certain servers. See the example config for the
moderation config options under the "Moderation / Privacy / Security" section.
conduwuit has moderation admin commands for: conduwuit has moderation admin commands for:
@@ -15,121 +11,56 @@ conduwuit has moderation admin commands for:
- managing room banning/blocking and user removal (`!admin rooms moderation`) - managing room banning/blocking and user removal (`!admin rooms moderation`)
- managing user accounts (`!admin users`) - managing user accounts (`!admin users`)
- fetching `/.well-known/matrix/support` from servers (`!admin federation`) - fetching `/.well-known/matrix/support` from servers (`!admin federation`)
- blocking incoming federation for certain rooms (not the same as room banning) - blocking incoming federation for certain rooms (not the same as room banning) (`!admin federation`)
(`!admin federation`)
- deleting media (see [the media section](#media)) - deleting media (see [the media section](#media))
Any commands with `-list` in them will require a codeblock in the message with 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:
each object being newline delimited. An example of doing this is:
```` ````
!admin rooms moderation ban-list-of-rooms !admin rooms moderation ban-list-of-rooms
``` ```
!roomid1:server.name !roomid1:server.name
#badroomalias1:server.name
!roomid2:server.name !roomid2:server.name
!roomid3:server.name !roomid3:server.name
#badroomalias2:server.name
``` ```
```` ````
## Database (RocksDB) ## Database
Generally there is very little you need to do. [Compaction][rocksdb-compaction] 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.
is ran automatically based on various defined thresholds tuned for conduwuit to
be high performance with the least I/O amplifcation or overhead. Manually 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.
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). 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 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 ## Backups
Currently only RocksDB supports online backups. If you'd like to backup your Currently only RocksDB supports online backups. If you'd like to backup your database online without any downtime, see the `!admin server` command for the backup commands and the `database_backup_path` config options in the example config. Please note that the format of the database backup is not the exact same. This is unfortunately a bad design choice by Facebook as we are using the database backup engine API from RocksDB, however the data is still there and can still be joined together.
database online without any downtime, see the `!admin server` command for the
backup commands and the `database_backup_path` config options in the example
config. Please note that the format of the database backup is not the exact
same. This is unfortunately a bad design choice by Facebook as we are using the
database backup engine API from RocksDB, however the data is still there and can
still be joined together.
To restore a backup from an online RocksDB backup: To restore a backup from an online RocksDB backup:
- shutdown conduwuit - shutdown conduwuit
- create a new directory for merging together the data - create a new directory for merging together the data
- in the online backup created, copy all `.sst` files in - in the online backup created, copy all `.sst` files in `$DATABASE_BACKUP_PATH/shared_checksum` to your new directory
`$DATABASE_BACKUP_PATH/shared_checksum` to your new directory - trim all the strings so instead of `######_sxxxxxxxxx.sst`, it reads `######.sst`. A way of doing this with sed and bash is `for file in *.sst; do mv "$file" "$(echo "$file" | sed 's/_s.*/.sst/')"; done`
- trim all the strings so instead of `######_sxxxxxxxxx.sst`, it reads - copy all the files in `$DATABASE_BACKUP_PATH/1` (or the latest backup number if you have multiple) to your new directory
`######.sst`. A way of doing this with sed and bash is `for file in *.sst; do mv - set your `database_path` config option to your new directory, or replace your old one with the new one you crafted
"$file" "$(echo "$file" | sed 's/_s.*/.sst/')"; done`
- copy all the files in `$DATABASE_BACKUP_PATH/1` (or the latest backup number
if you have multiple) to your new directory
- set your `database_path` config option to your new directory, or replace your
old one with the new one you crafted
- start up conduwuit again and it should open as normal - start up conduwuit again and it should open as normal
If you'd like to do an offline backup, shutdown conduwuit and copy your If you'd like to do an offline backup, shutdown conduwuit and copy your `database_path` directory elsewhere. This can be restored with no modifications needed.
`database_path` directory elsewhere. This can be restored with no modifications
needed.
Backing up media is also just copying the `media/` directory from your database Backing up media is also just copying the `media/` directory from your database directory.
directory.
## Media ## Media
Media still needs various work, however conduwuit implements media deletion via: Media still needs various work, however conduwuit implements media deletion via:
- MXC URI or Event ID (unencrypted and attempts to find the MXC URI in the - MXC URI or Event ID (unencrypted and attempts to find the MXC URI in the event)
event)
- Delete list of MXC URIs - Delete list of MXC URIs
- Delete remote media in the past `N` seconds/minutes via filesystem metadata on - Delete remote media in the past `N` seconds/minutes via filesystem metadata on the file created time (`btime`) or file modified time (`mtime`)
the file created time (`btime`) or file modified time (`mtime`)
See the `!admin media` command for further information. All media in conduwuit See the `!admin media` command for further information. All media in conduwuit is stored at `$DATABASE_DIR/media`. This will be configurable soon.
is stored at `$DATABASE_DIR/media`. This will be configurable soon.
If you are finding yourself needing extensive granular control over media, we If you are finding yourself needing extensive granular control over media, we recommend looking into [Matrix Media Repo](https://github.com/t2bot/matrix-media-repo). conduwuit intends to implement various utilities for media, but MMR is dedicated to extensive media management.
recommend looking into [Matrix Media
Repo](https://github.com/t2bot/matrix-media-repo). conduwuit intends to
implement various utilities for media, but MMR is dedicated to extensive media
management.
Built-in S3 support is also planned, but for now using a "S3 filesystem" on 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.
`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
+21 -152
View File
@@ -2,105 +2,23 @@
> ## Docker users ⚠️ > ## Docker users ⚠️
> >
> Docker is extremely UX unfriendly. Because of this, a ton of issues or support > Docker is extremely UX unfriendly. Because of this, a ton of issues or support is actually Docker support, not conduwuit support. We also cannot document the ever-growing list of Docker issues here.
> is actually Docker support, not conduwuit support. We also cannot document the
> ever-growing list of Docker issues here.
> >
> If you intend on asking for support and you are using Docker, **PLEASE** > If you intend on asking for support and you are using Docker, **PLEASE** triple validate your issues are **NOT** because you have a misconfiguration in your Docker setup.
> triple validate your issues are **NOT** because you have a misconfiguration in
> your Docker setup.
> >
> If there are things like Compose file issues or Dockerhub image issues, those > If there are things like Compose file issues or Dockerhub image issues, those can still be mentioned as long as they're something we can fix.
> can still be mentioned as long as they're something we can fix.
## conduwuit and Matrix issues ## Rocksdb / database issues
#### Lost access to admin room #### Direct IO
You can reinvite yourself to the admin room through the following methods: 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.
- Use the `--execute "users make_user_admin <username>"` conduwuit binary
argument once to invite yourslf to the admin room on startup
- Use the conduwuit console/CLI to run the `users make_user_admin` command
- Or specify the `emergency_password` config option to allow you to temporarily
log into the server account (`@conduit`) from a web client
## General potential issues
#### Potential DNS issues when using Docker
Docker has issues with its default DNS setup that may cause DNS to not be
properly functional when running conduwuit, resulting in federation issues. The
symptoms of this have shown in excessively long room joins (30+ minutes) from
very long DNS timeouts, log entries of "mismatching responding nameservers",
and/or partial or non-functional inbound/outbound federation.
This is **not** a conduwuit issue, and is purely a Docker issue. It is not
sustainable for heavy DNS activity which is normal for Matrix federation. The
workarounds for this are:
- Use DNS over TCP via the config option `query_over_tcp_only = true`
- 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
#### Database corruption #### Database corruption
If your database is corrupted *and* is failing to start (e.g. checksum If your database is corrupted *and* is failing to start (e.g. checksum mismatch), it may be recoverable but careful steps must be taken, and there is no guarantee it may be recoverable.
mismatch), it may be recoverable but careful steps must be taken, and there is
no guarantee it may be recoverable.
The first thing that can be done is launching conduwuit with the The first thing that can be done is launching conduwuit with the `rocksdb_repair` config option set to true. This will tell RocksDB to attempt to repair itself at launch. If this does not work, disable the option and continue reading.
`rocksdb_repair` config option set to true. This will tell RocksDB to attempt to
repair itself at launch. If this does not work, disable the option and continue
reading.
RocksDB has the following recovery modes: RocksDB has the following recovery modes:
@@ -109,84 +27,35 @@ RocksDB has the following recovery modes:
- `PointInTime` - `PointInTime`
- `SkipAnyCorruptedRecord` - `SkipAnyCorruptedRecord`
By default, conduwuit uses `TolerateCorruptedTailRecords` as generally these may By default, conduwuit uses `TolerateCorruptedTailRecords` as generally these may be due to bad federation and we can re-fetch the correct data over federation. The RocksDB default is `PointInTime` which will attempt to restore a "snapshot" of the data when it was last known to be good. This data can be either a few seconds old, or multiple minutes prior. `PointInTime` may not be suitable for default usage due to clients and servers possibly not being able to handle sudden "backwards time travels", and `AbsoluteConsistency` may be too strict.
be due to bad federation and we can re-fetch the correct data over federation.
The RocksDB default is `PointInTime` which will attempt to restore a "snapshot"
of the data when it was last known to be good. This data can be either a few
seconds old, or multiple minutes prior. `PointInTime` may not be suitable for
default usage due to clients and servers possibly not being able to handle
sudden "backwards time travels", and `AbsoluteConsistency` may be too strict.
`AbsoluteConsistency` will fail to start the database if any sign of corruption `AbsoluteConsistency` will fail to start the database if any sign of corruption is detected. `SkipAnyCorruptedRecord` will skip all forms of corruption unless it forbids the database from opening (e.g. too severe). Usage of `SkipAnyCorruptedRecord` voids any support as this may cause more damage and/or leave your database in a permanently inconsistent state, but it may do something if `PointInTime` does not work as a last ditch effort.
is detected. `SkipAnyCorruptedRecord` will skip all forms of corruption unless
it forbids the database from opening (e.g. too severe). Usage of
`SkipAnyCorruptedRecord` voids any support as this may cause more damage and/or
leave your database in a permanently inconsistent state, but it may do something
if `PointInTime` does not work as a last ditch effort.
With this in mind: With this in mind:
- First start conduwuit with the `PointInTime` recovery method. See the [example - First start conduwuit with the `PointInTime` recovery method. See the [example config](configuration/examples.md) for how to do this using `rocksdb_recovery_mode`
config](configuration/examples.md) for how to do this using - If your database successfully opens, clients are recommended to clear their client cache to account for the rollback
`rocksdb_recovery_mode` - Leave your conduwuit running in `PointInTime` for at least 30-60 minutes so as much possible corruption is restored
- If your database successfully opens, clients are recommended to clear their - If all goes will, you should be able to restore back to using `TolerateCorruptedTailRecords` and you have successfully recovered your database
client cache to account for the rollback
- Leave your conduwuit running in `PointInTime` for at least 30-60 minutes so as ## Media
much possible corruption is restored
- If all goes will, you should be able to restore back to using
`TolerateCorruptedTailRecords` and you have successfully recovered your database
## Debugging ## Debugging
Note that users should not really be debugging things. If you find yourself Note that users should not really be debugging things. If you find yourself debugging and find the issue, please let us know and/or how we can fix it. Various debug commands can be found in `!admin debug`.
debugging and find the issue, please let us know and/or how we can fix it.
Various debug commands can be found in `!admin debug`.
#### Debug/Trace log level #### Debug/Trace log level
conduwuit builds without debug or trace log levels at compile time by default 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.
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 #### Changing log level dynamically
conduwuit supports changing the tracing log environment filter on-the-fly using 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 #### Pinging servers
conduwuit can ping other servers using `!admin debug ping <server>`. This takes conduwuit can ping other servers using `!admin debug ping`. This takes a server name and goes through the server discovery process and queries `/_matrix/federation/v1/version`. Errors are outputted.
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 #### Allocator memory stats
When using jemalloc with jemallocator's `stats` feature (`--enable-stats`), you When using jemalloc with jemallocator's `stats` feature, you can see conduwuit's jemalloc memory stats by using `!admin debug memory-stats`
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
+8 -34
View File
@@ -1,8 +1,6 @@
# Setting up TURN/STURN # Setting up TURN/STURN
In order to make or receive calls, a TURN server is required. conduwuit suggests In order to make or receive calls, a TURN server is required. conduwuit suggests using [Coturn](https://github.com/coturn/coturn) for this purpose, which is also available as a Docker image.
using [Coturn](https://github.com/coturn/coturn) for this purpose, which is also
available as a Docker image.
### Configuration ### Configuration
@@ -14,41 +12,20 @@ static-auth-secret=<a secret key>
realm=<your server domain> realm=<your server domain>
``` ```
A common way to generate a suitable alphanumeric secret key is by using `pwgen A common way to generate a suitable alphanumeric secret key is by using `pwgen -s 64 1`.
-s 64 1`.
These same values need to be set in conduwuit. See the [example 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.
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
Run the [Coturn](https://hub.docker.com/r/coturn/coturn) image using Run the [Coturn](https://hub.docker.com/r/coturn/coturn) image using
```bash ```bash
docker run -d --network=host -v docker run -d --network=host -v $(pwd)/coturn.conf:/etc/coturn/turnserver.conf coturn/coturn
$(pwd)/coturn.conf:/etc/coturn/turnserver.conf coturn/coturn
``` ```
or docker-compose. For the latter, paste the following section into a file or docker-compose. For the latter, paste the following section into a file called `docker-compose.yml`
called `docker-compose.yml` and run `docker compose up -d` in the same and run `docker compose up -d` in the same directory.
directory.
```yml ```yml
version: 3 version: 3
@@ -62,9 +39,6 @@ services:
- ./coturn.conf:/etc/coturn/turnserver.conf - ./coturn.conf:/etc/coturn/turnserver.conf
``` ```
To understand why the host networking mode is used and explore alternative To understand why the host networking mode is used and explore alternative configuration options, please visit [Coturn's Docker documentation](https://github.com/coturn/coturn/blob/master/docker/coturn/README.md).
configuration options, please visit [Coturn's Docker
documentation](https://github.com/coturn/coturn/blob/master/docker/coturn/README.md).
For security recommendations see Synapse's [Coturn For security recommendations see Synapse's [Coturn documentation](https://element-hq.github.io/synapse/latest/turn-howto.html).
documentation](https://element-hq.github.io/synapse/latest/turn-howto.html).
+57 -38
View File
@@ -18,12 +18,12 @@ script = "direnv --version"
[[task]] [[task]]
name = "rustc" name = "rustc"
group = "versions" group = "versions"
script = "rustc --version -v" script = "rustc --version"
[[task]] [[task]]
name = "cargo" name = "cargo"
group = "versions" group = "versions"
script = "cargo --version -v" script = "cargo --version"
[[task]] [[task]]
name = "cargo-fmt" name = "cargo-fmt"
@@ -60,10 +60,15 @@ name = "markdownlint"
group = "versions" group = "versions"
script = "markdownlint --version" script = "markdownlint --version"
[[task]]
name = "dpkg"
group = "versions"
script = "dpkg --version"
[[task]] [[task]]
name = "cargo-audit" name = "cargo-audit"
group = "security" group = "security"
script = "cargo audit --color=always -D warnings -D unmaintained -D unsound -D yanked" script = "cargo audit -D warnings -D unmaintained -D unsound -D yanked"
[[task]] [[task]]
name = "cargo-fmt" name = "cargo-fmt"
@@ -81,7 +86,6 @@ env DIRENV_DEVSHELL=all-features \
direnv exec . \ direnv exec . \
cargo doc \ cargo doc \
--workspace \ --workspace \
--locked \
--profile test \ --profile test \
--all-features \ --all-features \
--no-deps \ --no-deps \
@@ -93,11 +97,10 @@ env DIRENV_DEVSHELL=all-features \
name = "clippy/default" name = "clippy/default"
group = "lints" group = "lints"
script = """ script = """
direnv exec . \
cargo clippy \ cargo clippy \
--workspace \ --workspace \
--locked \
--profile test \ --profile test \
--all-targets \
--color=always \ --color=always \
-- \ -- \
-D warnings -D warnings
@@ -111,8 +114,8 @@ env DIRENV_DEVSHELL=all-features \
direnv exec . \ direnv exec . \
cargo clippy \ cargo clippy \
--workspace \ --workspace \
--locked \
--profile test \ --profile test \
--all-targets \
--all-features \ --all-features \
--color=always \ --color=always \
-- \ -- \
@@ -120,41 +123,36 @@ env DIRENV_DEVSHELL=all-features \
""" """
[[task]] [[task]]
name = "clippy/no-features" name = "clippy/jemalloc"
group = "lints" group = "lints"
script = """ script = """
env DIRENV_DEVSHELL=no-features \ cargo clippy \
direnv exec . \
cargo clippy \
--workspace \ --workspace \
--locked \
--profile test \ --profile test \
--no-default-features \ --features jemalloc \
--all-targets \
--color=always \ --color=always \
-- \ -- \
-D warnings -D warnings
""" """
[[task]] #[[task]]
name = "clippy/other-features" #name = "clippy/hardened_malloc"
group = "lints" #group = "lints"
script = """ #script = """
direnv exec . \ #cargo clippy \
cargo clippy \ # --workspace \
--workspace \ # --features hardened_malloc \
--locked \ # --all-targets \
--profile test \ # --color=always \
--no-default-features \ # -- \
--features=console,systemd,element_hacks,direct_tls,perf_measurements,brotli_compression,blurhashing \ # -D warnings
--color=always \ #"""
-- \
-D warnings
"""
[[task]] [[task]]
name = "lychee" name = "lychee"
group = "lints" group = "lints"
script = "lychee --verbose --offline docs *.md --exclude development.md --exclude contributing.md --exclude testing.md" script = "lychee --verbose --offline docs *.md --exclude development.md"
[[task]] [[task]]
name = "markdownlint" name = "markdownlint"
@@ -162,28 +160,49 @@ group = "lints"
script = "markdownlint docs *.md || true" # TODO: fix the ton of markdown lints so we can drop `|| true` script = "markdownlint docs *.md || true" # TODO: fix the ton of markdown lints so we can drop `|| true`
[[task]] [[task]]
name = "cargo/default" name = "cargo/all"
group = "tests" group = "tests"
script = """ script = """
env DIRENV_DEVSHELL=default \ env DIRENV_DEVSHELL=all-features \
direnv exec . \ direnv exec . \
cargo test \ cargo test \
--workspace \ --workspace \
--locked \
--profile test \ --profile test \
--all-targets \ --all-targets \
--no-fail-fast \ --all-features \
--color=always \ --color=always \
-- \ -- \
--color=always --color=always
""" """
# Checks if the generated example config differs from the checked in repo's
# example config.
[[task]] [[task]]
name = "example-config" name = "cargo/default"
group = "tests" group = "tests"
depends = ["cargo/default"]
script = """ script = """
git diff --exit-code conduwuit-example.toml cargo test \
--workspace \
--profile test \
--all-targets \
--color=always \
-- \
--color=always
"""
# Ensure that the flake's default output can build and run without crashing
#
# This is a dynamically-linked jemalloc build, which is a case not covered by
# our other tests. We've had linking problems in the past with dynamic
# jemalloc builds that usually show up as an immediate segfault or "invalid free"
[[task]]
name = "nix-default"
group = "tests"
script = """
env DIRENV_DEVSHELL=dynamic \
CARGO_PROFILE="test" \
direnv exec . \
bin/nix-build-and-cache just .#default-test
env DIRENV_DEVSHELL=dynamic \
CARGO_PROFILE="test" \
direnv exec . \
nix run -L .#default-test -- --help && nix run -L .#default-test -- --version
""" """
Generated
+369 -248
View File
@@ -4,17 +4,16 @@
"inputs": { "inputs": {
"crane": "crane", "crane": "crane",
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"flake-parts": "flake-parts", "flake-utils": "flake-utils",
"nix-github-actions": "nix-github-actions",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgs-stable": "nixpkgs-stable" "nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1738524606, "lastModified": 1720542474,
"narHash": "sha256-hPYEJ4juK3ph7kbjbvv7PlU1D9pAkkhl+pwx8fZY53U=", "narHash": "sha256-aKjJ/4l2I9+wNGTaOGRsuS3M1+IoTibqgEMPDikXm04=",
"owner": "zhaofengli", "owner": "zhaofengli",
"repo": "attic", "repo": "attic",
"rev": "ff8a897d1f4408ebbf4d45fa9049c06b3e1e3f4e", "rev": "6139576a3ce6bb992e0f6c3022528ec233e45f00",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -27,16 +26,16 @@
"cachix": { "cachix": {
"inputs": { "inputs": {
"devenv": "devenv", "devenv": "devenv",
"flake-compat": "flake-compat_2", "flake-compat": "flake-compat_3",
"git-hooks": "git-hooks", "nixpkgs": "nixpkgs_3",
"nixpkgs": "nixpkgs_4" "pre-commit-hooks": "pre-commit-hooks"
}, },
"locked": { "locked": {
"lastModified": 1737621947, "lastModified": 1719923519,
"narHash": "sha256-8HFvG7fvIFbgtaYAY2628Tb89fA55nPm2jSiNs0/Cws=", "narHash": "sha256-7Rhljj2fsklFRsu+eq7N683Z9qukmreMEj5C1GqCrSA=",
"owner": "cachix", "owner": "cachix",
"repo": "cachix", "repo": "cachix",
"rev": "f65a3cd5e339c223471e64c051434616e18cc4f5", "rev": "4e9e71f78b9500fa6210cf1eaa4d75bdbab777c3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -48,31 +47,33 @@
}, },
"cachix_2": { "cachix_2": {
"inputs": { "inputs": {
"devenv": [ "devenv": "devenv_2",
"cachix",
"devenv"
],
"flake-compat": [ "flake-compat": [
"cachix", "cachix",
"devenv" "devenv",
"flake-compat"
], ],
"git-hooks": [ "nixpkgs": [
"cachix", "cachix",
"devenv" "devenv",
"nixpkgs"
], ],
"nixpkgs": "nixpkgs_2" "pre-commit-hooks": [
"cachix",
"devenv",
"pre-commit-hooks"
]
}, },
"locked": { "locked": {
"lastModified": 1728672398, "lastModified": 1712055811,
"narHash": "sha256-KxuGSoVUFnQLB2ZcYODW7AVPAh9JqRlD5BrfsC/Q4qs=", "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=",
"owner": "cachix", "owner": "cachix",
"repo": "cachix", "repo": "cachix",
"rev": "aac51f698309fd0f381149214b7eee213c66ef0a", "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "cachix", "owner": "cachix",
"ref": "latest",
"repo": "cachix", "repo": "cachix",
"type": "github" "type": "github"
} }
@@ -80,15 +81,15 @@
"complement": { "complement": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1741891349, "lastModified": 1720637557,
"narHash": "sha256-YvrzOWcX7DH1drp5SGa+E/fc7wN3hqFtPbqPjZpOu1Q=", "narHash": "sha256-oZz6nCmFmdJZpC+K1iOG2KkzTI6rlAmndxANPDVU7X0=",
"owner": "girlbossceo", "owner": "matrix-org",
"repo": "complement", "repo": "complement",
"rev": "e587b3df569cba411aeac7c20b6366d03c143745", "rev": "0d14432e010482ea9e13a6f7c47c1533c0c9d62f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "girlbossceo", "owner": "matrix-org",
"ref": "main", "ref": "main",
"repo": "complement", "repo": "complement",
"type": "github" "type": "github"
@@ -102,11 +103,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1722960479, "lastModified": 1717025063,
"narHash": "sha256-NhCkJJQhD5GUib8zN9JrmYGMwt4lCRp6ZVNzIiYCl0Y=", "narHash": "sha256-dIubLa56W9sNNz0e8jGxrX3CAkPXsq7snuFA/Ie6dn8=",
"owner": "ipetkov", "owner": "ipetkov",
"repo": "crane", "repo": "crane",
"rev": "4c6c77920b8d44cd6660c1621dea6b3fc4b4c4f4", "rev": "480dff0be03dac0e51a8dfc26e882b0d123a450e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -116,12 +117,17 @@
} }
}, },
"crane_2": { "crane_2": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1739936662, "lastModified": 1720546058,
"narHash": "sha256-x4syUjNUuRblR07nDPeLDP7DpphaBVbUaSoeZkFbGSk=", "narHash": "sha256-iU2yVaPIZm5vMGdlT0+57vdB/aPq/V5oZFBRwYw+HBM=",
"owner": "ipetkov", "owner": "ipetkov",
"repo": "crane", "repo": "crane",
"rev": "19de14aaeb869287647d9461cbd389187d8ecdb7", "rev": "2d83156f23c43598cf44e152c33a59d3892f8b29",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -138,22 +144,22 @@
"cachix", "cachix",
"flake-compat" "flake-compat"
], ],
"git-hooks": [ "nix": "nix_2",
"cachix",
"git-hooks"
],
"nix": "nix",
"nixpkgs": [ "nixpkgs": [
"cachix", "cachix",
"nixpkgs" "nixpkgs"
],
"pre-commit-hooks": [
"cachix",
"pre-commit-hooks"
] ]
}, },
"locked": { "locked": {
"lastModified": 1733323168, "lastModified": 1719759336,
"narHash": "sha256-d5DwB4MZvlaQpN6OQ4SLYxb5jA4UH5EtV5t5WOtjLPU=", "narHash": "sha256-3a34VL/QnHprl5gMy9xlx6d8J+iNp+W88Ex8smkgH9M=",
"owner": "cachix", "owner": "cachix",
"repo": "devenv", "repo": "devenv",
"rev": "efa9010b8b1cfd5dd3c7ed1e172a470c3b84a064", "rev": "bb32aa986f2f695385e54428d0eaf7d05b31466e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -162,6 +168,39 @@
"type": "github" "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": { "fenix": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -170,11 +209,11 @@
"rust-analyzer-src": "rust-analyzer-src" "rust-analyzer-src": "rust-analyzer-src"
}, },
"locked": { "locked": {
"lastModified": 1740724364, "lastModified": 1720852044,
"narHash": "sha256-D1jLIueJx1dPrP09ZZwTrPf4cubV+TsFMYbpYYTVj6A=", "narHash": "sha256-3NBYz8VuXuKU+8ONd9NFafCNjPEGHIZQ2Mdoam1a4mY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "edf7d9e431cda8782e729253835f178a356d3aab", "rev": "5087b12a595ee73131a944d922f24d81dae05725",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -185,6 +224,38 @@
} }
}, },
"flake-compat": { "flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_3": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1696426674, "lastModified": 1696426674,
@@ -200,14 +271,14 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat_2": { "flake-compat_4": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1733328505, "lastModified": 1696426674,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra", "owner": "edolstra",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -216,14 +287,14 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat_3": { "flake-compat_5": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1733328505, "lastModified": 1696426674,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra", "owner": "edolstra",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -233,60 +304,49 @@
"type": "github" "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": { "flake-utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1731533236, "lastModified": 1689068808,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -296,38 +356,11 @@
"type": "github" "type": "github"
} }
}, },
"git-hooks": {
"inputs": {
"flake-compat": [
"cachix",
"flake-compat"
],
"gitignore": "gitignore",
"nixpkgs": [
"cachix",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable_2"
},
"locked": {
"lastModified": 1733318908,
"narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": { "gitignore": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"cachix", "cachix",
"git-hooks", "pre-commit-hooks",
"nixpkgs" "nixpkgs"
] ]
}, },
@@ -345,30 +378,14 @@
"type": "github" "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": { "liburing": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1740613216, "lastModified": 1720798442,
"narHash": "sha256-NpPOBqNND3Qe9IwqYs0mJLGTmIx7e6FgUEBAnJ+1ZLA=", "narHash": "sha256-gtPppAoksMLW4GuruQ36nf4EAqIA1Bs6V9Xcx8dBxrQ=",
"owner": "axboe", "owner": "axboe",
"repo": "liburing", "repo": "liburing",
"rev": "e1003e496e66f9b0ae06674869795edf772d5500", "rev": "1d674f83b7d0f07553ac44d99a401b05853d9dbe",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -380,48 +397,38 @@
}, },
"nix": { "nix": {
"inputs": { "inputs": {
"flake-compat": [ "flake-compat": "flake-compat_2",
"nixpkgs": [
"cachix", "cachix",
"devenv" "devenv",
"cachix",
"devenv",
"nixpkgs"
], ],
"flake-parts": "flake-parts_2", "nixpkgs-regression": "nixpkgs-regression"
"libgit2": "libgit2",
"nixpkgs": "nixpkgs_3",
"nixpkgs-23-11": [
"cachix",
"devenv"
],
"nixpkgs-regression": [
"cachix",
"devenv"
],
"pre-commit-hooks": [
"cachix",
"devenv"
]
}, },
"locked": { "locked": {
"lastModified": 1727438425, "lastModified": 1712911606,
"narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=", "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
"owner": "domenkozar", "owner": "domenkozar",
"repo": "nix", "repo": "nix",
"rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546", "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "domenkozar", "owner": "domenkozar",
"ref": "devenv-2.24", "ref": "devenv-2.21",
"repo": "nix", "repo": "nix",
"type": "github" "type": "github"
} }
}, },
"nix-filter": { "nix-filter": {
"locked": { "locked": {
"lastModified": 1731533336, "lastModified": 1710156097,
"narHash": "sha256-oRam5PS1vcrr5UPgALW0eo1m/5/pls27Z/pabHNy2Ms=", "narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=",
"owner": "numtide", "owner": "numtide",
"repo": "nix-filter", "repo": "nix-filter",
"rev": "f7653272fd234696ae94229839a99b73c9ab7de0", "rev": "3342559a24e85fc164b295c3444e8a139924675b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -434,16 +441,20 @@
"nix-github-actions": { "nix-github-actions": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"attic", "cachix",
"devenv",
"cachix",
"devenv",
"poetry2nix",
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1729742964, "lastModified": 1688870561,
"narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=", "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix-github-actions", "repo": "nix-github-actions",
"rev": "e04df33f62cdcf93d73e9a04142464753a16db67", "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -452,13 +463,42 @@
"type": "github" "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": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1726042813, "lastModified": 1711401922,
"narHash": "sha256-LnNKCCxnwgF+575y0pxUdlGZBO/ru1CtGHIqQVfvjlA=", "narHash": "sha256-QoQqXoj8ClGo0sqD/qWKFWezgEwUL0SUh37/vY2jNhc=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "159be5db480d1df880a0135ca0bfed84c2f88353", "rev": "07262b18b97000d16a4bdb003418bd2fb067a932",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -468,93 +508,77 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-stable": { "nixpkgs-regression": {
"locked": { "locked": {
"lastModified": 1724316499, "lastModified": 1643052045,
"narHash": "sha256-Qb9MhKBUTCfWg/wqqaxt89Xfi6qTD3XpTzQ9eXi3JmE=", "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "797f7dc49e0bc7fab4b57c021cdf68f595e47841", "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-24.05", "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": 1711460390,
"narHash": "sha256-akSgjDZL6pVHEfSE6sz1DNSXuYX6hq+P/1Z5IoYWs7E=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "44733514b72e732bd49f5511bd0203dea9b9a434",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs-stable_2": { "nixpkgs-stable_2": {
"locked": { "locked": {
"lastModified": 1730741070, "lastModified": 1718811006,
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", "narHash": "sha256-0Y8IrGhRmBmT7HHXlxxepg2t8j1X90++qRN3lukGaIk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", "rev": "03d771e513ce90147b65fe922d87d3a0356fc125",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-24.05", "ref": "nixos-23.11",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1730531603, "lastModified": 1692808169,
"narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=", "narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d", "rev": "9201b5ff357e781bf014d0330d18555695df7ba8",
"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": 1740547748,
"narHash": "sha256-Ly2fBL1LscV+KyCqPRufUBuiw+zmWrlJzpWOWbahplg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3a05eebede89661660945da1f151959900903b6a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -564,19 +588,101 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_3": {
"locked": {
"lastModified": 1719848872,
"narHash": "sha256-H3+EC5cYuq+gQW8y0lSrrDZfH71LB4DAf+TDFyvwCNA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "00d80d13810dbfea8ab4ed1009b09100cca86ba8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1720768451,
"narHash": "sha256-EYekUHJE2gxeo2pM/zM9Wlqw1Uw2XTJXOSAO79ksc4Y=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7e7c39ea35c5cdd002cd4588b03a3fb9ece6fad9",
"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"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat_4",
"gitignore": "gitignore",
"nixpkgs": [
"cachix",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable_2"
},
"locked": {
"lastModified": 1719259945,
"narHash": "sha256-F1h+XIsGKT9TkGO3omxDLEb/9jOOsI6NnzsXFsZhry4=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"rocksdb": { "rocksdb": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1741308171, "lastModified": 1720900786,
"narHash": "sha256-YdBvdQ75UJg5ffwNjxizpviCVwVDJnBkM8ZtGIduMgY=", "narHash": "sha256-Vta9Um/RRuWwZ46BjXftV06iWLm/j/9MX39emXUvSAY=",
"owner": "girlbossceo", "owner": "girlbossceo",
"repo": "rocksdb", "repo": "rocksdb",
"rev": "3ce04794bcfbbb0d2e6f81ae35fc4acf688b6986", "rev": "911f4243e69c2e320a7a209bf1f5f3ff5f825495",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "girlbossceo", "owner": "girlbossceo",
"ref": "v9.11.1", "ref": "v9.4.0",
"repo": "rocksdb", "repo": "rocksdb",
"type": "github" "type": "github"
} }
@@ -588,22 +694,22 @@
"complement": "complement", "complement": "complement",
"crane": "crane_2", "crane": "crane_2",
"fenix": "fenix", "fenix": "fenix",
"flake-compat": "flake-compat_3", "flake-compat": "flake-compat_5",
"flake-utils": "flake-utils", "flake-utils": "flake-utils_3",
"liburing": "liburing", "liburing": "liburing",
"nix-filter": "nix-filter", "nix-filter": "nix-filter",
"nixpkgs": "nixpkgs_5", "nixpkgs": "nixpkgs_4",
"rocksdb": "rocksdb" "rocksdb": "rocksdb"
} }
}, },
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1740691488, "lastModified": 1720717809,
"narHash": "sha256-Fs6vBrByuiOf2WO77qeMDMTXcTGzrIMqLBv+lNeywwM=", "narHash": "sha256-6I+fm+nTLF/iaj7ffiFGlSY7POmubwUaPA/Wq0Bm53M=",
"owner": "rust-lang", "owner": "rust-lang",
"repo": "rust-analyzer", "repo": "rust-analyzer",
"rev": "fe3eda77d3a7ce212388bda7b6cec8bffcc077e5", "rev": "ffbc5ad993d5cd2f3b8bcf9a511165470944ab91",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -627,6 +733,21 @@
"repo": "default", "repo": "default",
"type": "github" "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"
}
} }
}, },
"root": "root", "root": "root",
+49 -234
View File
@@ -2,23 +2,21 @@
inputs = { inputs = {
attic.url = "github:zhaofengli/attic?ref=main"; attic.url = "github:zhaofengli/attic?ref=main";
cachix.url = "github:cachix/cachix?ref=master"; cachix.url = "github:cachix/cachix?ref=master";
complement = { url = "github:girlbossceo/complement?ref=main"; flake = false; }; complement = { url = "github:matrix-org/complement?ref=main"; flake = false; };
crane = { url = "github:ipetkov/crane?ref=master"; }; crane = { url = "github:ipetkov/crane?ref=master"; inputs.nixpkgs.follows = "nixpkgs"; };
fenix = { url = "github:nix-community/fenix?ref=main"; inputs.nixpkgs.follows = "nixpkgs"; }; fenix = { url = "github:nix-community/fenix?ref=main"; inputs.nixpkgs.follows = "nixpkgs"; };
flake-compat = { url = "github:edolstra/flake-compat?ref=master"; flake = false; }; flake-compat = { url = "github:edolstra/flake-compat?ref=master"; flake = false; };
flake-utils.url = "github:numtide/flake-utils?ref=main"; flake-utils.url = "github:numtide/flake-utils?ref=main";
nix-filter.url = "github:numtide/nix-filter?ref=main"; nix-filter.url = "github:numtide/nix-filter?ref=main";
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixpkgs-unstable"; nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.11.1"; flake = false; }; rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.4.0"; flake = false; };
liburing = { url = "github:axboe/liburing?ref=master"; flake = false; }; liburing = { url = "github:axboe/liburing?ref=master"; flake = false; };
}; };
outputs = inputs: outputs = inputs:
inputs.flake-utils.lib.eachDefaultSystem (system: inputs.flake-utils.lib.eachDefaultSystem (system:
let let
pkgsHost = import inputs.nixpkgs{ pkgsHost = inputs.nixpkgs.legacyPackages.${system};
inherit system;
};
pkgsHostStatic = pkgsHost.pkgsStatic; pkgsHostStatic = pkgsHost.pkgsStatic;
# The Rust toolchain to use # The Rust toolchain to use
@@ -26,34 +24,18 @@
file = ./rust-toolchain.toml; file = ./rust-toolchain.toml;
# See also `rust-toolchain.toml` # See also `rust-toolchain.toml`
sha256 = "sha256-X/4ZBHO3iW0fOenQ3foEvscgAPJYl2abspaBThDOukI="; sha256 = "sha256-6eN/GKzjVSjEhGO9FhWObkRFaE1Jf+uqMSdQnb8lcB4=";
}; };
mkScope = pkgs: pkgs.lib.makeScope pkgs.newScope (self: { mkScope = pkgs: pkgs.lib.makeScope pkgs.newScope (self: {
inherit pkgs; inherit pkgs;
book = self.callPackage ./nix/pkgs/book {}; book = self.callPackage ./nix/pkgs/book {};
complement = self.callPackage ./nix/pkgs/complement {}; complement = self.callPackage ./nix/pkgs/complement {};
craneLib = ((inputs.crane.mkLib pkgs).overrideToolchain (_: toolchain)); craneLib = ((inputs.crane.mkLib pkgs).overrideToolchain toolchain);
inherit inputs; inherit inputs;
main = self.callPackage ./nix/pkgs/main {}; main = self.callPackage ./nix/pkgs/main {};
oci-image = self.callPackage ./nix/pkgs/oci-image {}; oci-image = self.callPackage ./nix/pkgs/oci-image {};
tini = pkgs.tini.overrideAttrs { rocksdb = pkgs.rocksdb.overrideAttrs (old: {
# 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; src = inputs.rocksdb;
version = pkgs.lib.removePrefix version = pkgs.lib.removePrefix
"v" "v"
@@ -64,28 +46,17 @@
patches = []; patches = [];
cmakeFlags = pkgs.lib.subtractLists cmakeFlags = pkgs.lib.subtractLists
[ [
# no real reason to have snappy or zlib, no one uses this # no real reason to have snappy, no one uses this
"-DWITH_SNAPPY=1" "-DWITH_SNAPPY=1"
"-DZLIB=1"
"-DWITH_ZLIB=1"
# we dont need to use ldb or sst_dump (core_tools) # we dont need to use ldb or sst_dump (core_tools)
"-DWITH_CORE_TOOLS=1" "-DWITH_CORE_TOOLS=1"
# we dont need to build rocksdb tests # we dont need to build rocksdb tests
"-DWITH_TESTS=1" "-DWITH_TESTS=1"
# we use rust-rocksdb via C interface and dont need C++ RTTI # we use rust-rocksdb via C interface and dont need C++ RTTI
"-DUSE_RTTI=1" "-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 old.cmakeFlags
++ [ ++ [
# no real reason to have snappy, no one uses this
"-DWITH_SNAPPY=0"
"-DZLIB=0"
"-DWITH_ZLIB=0"
# we dont need to use ldb or sst_dump (core_tools) # we dont need to use ldb or sst_dump (core_tools)
"-DWITH_CORE_TOOLS=0" "-DWITH_CORE_TOOLS=0"
# we dont need trace tools # we dont need trace tools
@@ -102,20 +73,18 @@
# preInstall hooks has stuff for messing with ldb/sst_dump which we dont need or use # preInstall hooks has stuff for messing with ldb/sst_dump which we dont need or use
preInstall = ""; 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; scopeHost = mkScope pkgsHost;
scopeHostStatic = mkScope pkgsHostStatic; 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 { mkDevShell = scope: scope.pkgs.mkShell {
env = scope.main.env // { env = scope.main.env // {
@@ -128,9 +97,9 @@
# code. # code.
COMPLEMENT_SRC = inputs.complement.outPath; COMPLEMENT_SRC = inputs.complement.outPath;
# Needed for Complement: <https://github.com/golang/go/issues/52690> # Needed for Complement
CGO_CFLAGS = "-Wl,--no-gc-sections"; CGO_CFLAGS = "-I${scope.pkgs.olm}/include";
CGO_LDFLAGS = "-Wl,--no-gc-sections"; CGO_LDFLAGS = "-L${scope.pkgs.olm}/lib";
}; };
# Development tools # Development tools
@@ -144,11 +113,8 @@
toolchain toolchain
] ]
++ (with pkgsHost.pkgs; [ ++ (with pkgsHost.pkgs; [
# Required by hardened-malloc.rs dep engage
binutils
cargo-audit cargo-audit
cargo-auditable
# Needed for producing Debian packages # Needed for producing Debian packages
cargo-deb cargo-deb
@@ -156,14 +122,11 @@
# Needed for CI to check validity of produced Debian packages (dpkg-deb) # Needed for CI to check validity of produced Debian packages (dpkg-deb)
dpkg dpkg
engage
# Needed for Complement # Needed for Complement
go go
# Needed for our script for Complement # Needed for our script for Complement
jq jq
gotestfmt
# Needed for finding broken markdown links # Needed for finding broken markdown links
lychee lychee
@@ -174,72 +137,34 @@
# Useful for editing the book locally # Useful for editing the book locally
mdbook mdbook
# used for rust caching in CI to speed it up
sccache sccache
] ])
# liburing is Linux-exclusive
++ lib.optional stdenv.hostPlatform.isLinux liburing
++ lib.optional stdenv.hostPlatform.isLinux numactl)
++ scope.main.buildInputs ++ scope.main.buildInputs
++ scope.main.propagatedBuildInputs ++ scope.main.propagatedBuildInputs
++ scope.main.nativeBuildInputs; ++ scope.main.nativeBuildInputs;
meta.broken = scope.main.meta.broken;
}; };
in in
{ {
packages = { packages = {
default = scopeHost.main.override { default = scopeHost.main;
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 { default-debug = scopeHost.main.override {
profile = "dev"; profile = "dev";
# debug build users expect full logs # debug build users expect full logs
disable_release_max_log_level = true; 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 { default-test = scopeHost.main.override {
profile = "test"; profile = "test";
disable_release_max_log_level = true; 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 = scopeHost.main.override {
all_features = true; all_features = true;
disable_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 # this is non-functional on nix for some reason
"hardened_malloc" "hardened_malloc"
# conduwuit_mods is a development-only hot reload feature # dont include experimental features
"conduwuit_mods" "experimental"
]; ];
}; };
all-features-debug = scopeHost.main.override { all-features-debug = scopeHost.main.override {
@@ -248,12 +173,10 @@
# debug build users expect full logs # debug build users expect full logs
disable_release_max_log_level = true; disable_release_max_log_level = true;
disable_features = [ disable_features = [
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason # this is non-functional on nix for some reason
"hardened_malloc" "hardened_malloc"
# conduwuit_mods is a development-only hot reload feature # dont include experimental features
"conduwuit_mods" "experimental"
]; ];
}; };
hmalloc = scopeHost.main.override { features = ["hardened_malloc"]; }; hmalloc = scopeHost.main.override { features = ["hardened_malloc"]; };
@@ -263,16 +186,10 @@
main = scopeHost.main.override { main = scopeHost.main.override {
all_features = true; all_features = true;
disable_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 # this is non-functional on nix for some reason
"hardened_malloc" "hardened_malloc"
# conduwuit_mods is a development-only hot reload feature # dont include experimental features
"conduwuit_mods" "experimental"
]; ];
}; };
}; };
@@ -283,12 +200,10 @@
# debug build users expect full logs # debug build users expect full logs
disable_release_max_log_level = true; disable_release_max_log_level = true;
disable_features = [ disable_features = [
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason # this is non-functional on nix for some reason
"hardened_malloc" "hardened_malloc"
# conduwuit_mods is a development-only hot reload feature # dont include experimental features
"conduwuit_mods" "experimental"
]; ];
}; };
}; };
@@ -302,8 +217,6 @@
complement = scopeHost.complement; complement = scopeHost.complement;
static-complement = scopeHostStatic.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 builtins.listToAttrs
@@ -312,7 +225,14 @@
(crossSystem: (crossSystem:
let let
binaryName = "static-${crossSystem}"; binaryName = "static-${crossSystem}";
scopeCrossStatic = mkCrossScope crossSystem; pkgsCrossStatic =
(import inputs.nixpkgs {
inherit system;
crossSystem = {
config = crossSystem;
};
}).pkgsStatic;
scopeCrossStatic = mkScope pkgsCrossStatic;
in in
[ [
# An output for a statically-linked binary # An output for a statically-linked binary
@@ -321,15 +241,6 @@
value = scopeCrossStatic.main; 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 # An output for a statically-linked unstripped debug ("dev") binary
{ {
name = "${binaryName}-debug"; name = "${binaryName}-debug";
@@ -347,14 +258,6 @@
value = scopeCrossStatic.main.override { value = scopeCrossStatic.main.override {
profile = "test"; profile = "test";
disable_release_max_log_level = true; 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"
];
}; };
} }
@@ -364,39 +267,11 @@
value = scopeCrossStatic.main.override { value = scopeCrossStatic.main.override {
all_features = true; all_features = true;
disable_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 # this is non-functional on nix for some reason
"hardened_malloc" "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 # dont include experimental features
"experimental" "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);
}; };
} }
@@ -409,12 +284,10 @@
# debug build users expect full logs # debug build users expect full logs
disable_release_max_log_level = true; disable_release_max_log_level = true;
disable_features = [ disable_features = [
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason # this is non-functional on nix for some reason
"hardened_malloc" "hardened_malloc"
# conduwuit_mods is a development-only hot reload feature # dont include experimental features
"conduwuit_mods" "experimental"
]; ];
}; };
} }
@@ -433,17 +306,6 @@
value = scopeCrossStatic.oci-image; 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 # An output for an OCI image based on that unstripped debug ("dev") binary
{ {
name = "oci-image-${crossSystem}-debug"; name = "oci-image-${crossSystem}-debug";
@@ -463,41 +325,11 @@
main = scopeCrossStatic.main.override { main = scopeCrossStatic.main.override {
all_features = true; all_features = true;
disable_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 # this is non-functional on nix for some reason
"hardened_malloc" "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 # dont include experimental features
"experimental" "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);
}; };
}; };
} }
@@ -512,12 +344,10 @@
# debug build users expect full logs # debug build users expect full logs
disable_release_max_log_level = true; disable_release_max_log_level = true;
disable_features = [ disable_features = [
# dont include experimental features
"experimental"
# this is non-functional on nix for some reason # this is non-functional on nix for some reason
"hardened_malloc" "hardened_malloc"
# conduwuit_mods is a development-only hot reload feature # dont include experimental features
"conduwuit_mods" "experimental"
]; ];
}; };
}; };
@@ -532,20 +362,11 @@
}; };
}; };
} }
# An output for a complement OCI image for the specified platform
{
name = "complement-${crossSystem}";
value = scopeCrossStatic.complement;
}
] ]
) )
[ [
#"x86_64-apple-darwin" "x86_64-unknown-linux-musl"
#"aarch64-apple-darwin" "aarch64-unknown-linux-musl"
"x86_64-linux-gnu"
"x86_64-linux-musl"
"aarch64-linux-musl"
] ]
) )
); );
@@ -556,16 +377,10 @@
main = prev.main.override { main = prev.main.override {
all_features = true; all_features = true;
disable_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 # this is non-functional on nix for some reason
"hardened_malloc" "hardened_malloc"
# conduwuit_mods is a development-only hot reload feature # dont include experimental features
"conduwuit_mods" "experimental"
]; ];
}; };
})); }));
-2
View File
@@ -14,10 +14,8 @@ stdenv.mkDerivation {
include = [ include = [
"book.toml" "book.toml"
"conduwuit-example.toml" "conduwuit-example.toml"
"CODE_OF_CONDUCT.md"
"CONTRIBUTING.md" "CONTRIBUTING.md"
"README.md" "README.md"
"development.md"
"debian/conduwuit.service" "debian/conduwuit.service"
"debian/README.md" "debian/README.md"
"arch/conduwuit.service" "arch/conduwuit.service"
-21
View File
@@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDfzCCAmegAwIBAgIUcrZdSPmCh33Evys/U6mTPpShqdcwDQYJKoZIhvcNAQEL
BQAwPzELMAkGA1UEBhMCNjkxCzAJBgNVBAgMAjQyMRUwEwYDVQQKDAx3b29mZXJz
IGluYy4xDDAKBgNVBAMMA2hzMTAgFw0yNTAzMTMxMjU4NTFaGA8yMDUyMDcyODEy
NTg1MVowPzELMAkGA1UEBhMCNjkxCzAJBgNVBAgMAjQyMRUwEwYDVQQKDAx3b29m
ZXJzIGluYy4xDDAKBgNVBAMMA2hzMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBANL+h2ZmK/FqN5uLJPtIy6Feqcyb6EX7MQBEtxuJ56bTAbjHuCLZLpYt
/wOWJ91drHqZ7Xd5iTisGdMu8YS803HSnHkzngf4VXKhVrdzW2YDrpZRxmOhtp88
awOHmP7mqlJyBbCOQw8aDVrT0KmEIWzA7g+nFRQ5Ff85MaP+sQrHGKZbo61q8HBp
L0XuaqNckruUKtxnEqrm5xx5sYyYKg7rrSFE5JMFoWKB1FNWJxyWT42BhGtnJZsK
K5c+NDSOU4TatxoN6mpNSBpCz/a11PiQHMEfqRk6JA4g3911dqPTfZBevUdBh8gl
8maIzqeZGhvyeKTmull1Y0781yyuj98CAwEAAaNxMG8wCQYDVR0TBAIwADALBgNV
HQ8EBAMCBPAwNgYDVR0RBC8wLYIRKi5kb2NrZXIuaW50ZXJuYWyCA2hzMYIDaHMy
ggNoczOCA2hzNIcEfwAAATAdBgNVHQ4EFgQUr4VYrmW1d+vjBTJewvy7fJYhLDYw
DQYJKoZIhvcNAQELBQADggEBADkYqkjNYxjWX8hUUAmFHNdCwzT1CpYe/5qzLiyJ
irDSdMlC5g6QqMUSrpu7nZxo1lRe1dXGroFVfWpoDxyCjSQhplQZgtYqtyLfOIx+
HQ7cPE/tUU/KsTGc0aL61cETB6u8fj+rQKUGdfbSlm0Rpu4v0gC8RnDj06X/hZ7e
VkWU+dOBzxlqHuLlwFFtVDgCyyTatIROx5V+GpMHrVqBPO7HcHhwqZ30k2kMM8J3
y1CWaliQM85jqtSZV+yUHKQV8EksSowCFJuguf+Ahz0i0/koaI3i8m4MRN/1j13d
jbTaX5a11Ynm3A27jioZdtMRty6AJ88oCp18jxVzqTxNNO4=
-----END CERTIFICATE-----
+5 -32
View File
@@ -6,45 +6,18 @@ allow_public_room_directory_over_federation = true
allow_public_room_directory_without_auth = true allow_public_room_directory_without_auth = true
allow_registration = true allow_registration = true
database_path = "/database" database_path = "/database"
log = "trace,h2=debug,hyper=debug" log = "trace,h2=warn,hyper=warn"
port = [8008, 8448] port = [8008, 8448]
trusted_servers = [] trusted_servers = []
only_query_trusted_key_servers = false
query_trusted_key_servers_first = 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 yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse = true
ip_range_denylist = [] ip_range_denylist = []
url_preview_domain_contains_allowlist = ["*"] url_preview_domain_contains_allowlist = ["*"]
url_preview_domain_explicit_denylist = ["*"]
media_compat_file_link = false media_compat_file_link = false
media_startup_check = true media_startup_check = false
prune_missing_media = true rocksdb_direct_io = false
log_colors = true
admin_room_notices = false
allow_check_for_updates = false
intentionally_unknown_config_option_for_testing = true
rocksdb_log_level = "info"
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
allow_invalid_tls_certificates_yes_i_know_what_the_fuck_i_am_doing_with_this_and_i_know_this_is_insecure = true
# 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] [global.tls]
certs = "/certificate.crt"
dual_protocol = true dual_protocol = true
key = "/private_key.key"
+27 -19
View File
@@ -3,8 +3,10 @@
, buildEnv , buildEnv
, coreutils , coreutils
, dockerTools , dockerTools
, gawk
, lib , lib
, main , main
, openssl
, stdenv , stdenv
, tini , tini
, writeShellScriptBin , writeShellScriptBin
@@ -16,30 +18,38 @@ let
all_features = true; all_features = true;
disable_release_max_log_level = true; disable_release_max_log_level = true;
disable_features = [ 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 # this is non-functional on nix for some reason
"hardened_malloc" "hardened_malloc"
# dont include experimental features # dont include experimental features
"experimental" "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"
]; ];
}; };
start = writeShellScriptBin "start" '' start = writeShellScriptBin "start" ''
set -euxo pipefail set -euxo pipefail
${lib.getExe openssl} genrsa -out private_key.key 2048
${lib.getExe openssl} req \
-new \
-sha256 \
-key private_key.key \
-subj "/C=US/ST=CA/O=MyOrg, Inc./CN=$SERVER_NAME" \
-out signing_request.csr
cp ${./v3.ext} v3.ext
echo "DNS.1 = $SERVER_NAME" >> v3.ext
echo "IP.1 = $(${lib.getExe gawk} 'END{print $1}' /etc/hosts)" \
>> v3.ext
${lib.getExe openssl} x509 \
-req \
-extfile v3.ext \
-in signing_request.csr \
-CA /complement/ca/ca.crt \
-CAkey /complement/ca/ca.key \
-CAcreateserial \
-out certificate.crt \
-days 1 \
-sha256
${lib.getExe' coreutils "env"} \ ${lib.getExe' coreutils "env"} \
CONDUWUIT_SERVER_NAME="$SERVER_NAME" \ CONDUWUIT_SERVER_NAME="$SERVER_NAME" \
${lib.getExe main'} ${lib.getExe main'}
@@ -47,7 +57,7 @@ let
in in
dockerTools.buildImage { dockerTools.buildImage {
name = "complement-conduwuit"; name = "complement-${main.pname}";
tag = "main"; tag = "main";
copyToRoot = buildEnv { copyToRoot = buildEnv {
@@ -68,17 +78,15 @@ dockerTools.buildImage {
"${lib.getExe start}" "${lib.getExe start}"
]; ];
Entrypoint = if !stdenv.hostPlatform.isDarwin Entrypoint = if !stdenv.isDarwin
# Use the `tini` init system so that signals (e.g. ctrl+c/SIGINT) # Use the `tini` init system so that signals (e.g. ctrl+c/SIGINT)
# are handled as expected # are handled as expected
then [ "${lib.getExe' tini "tini"}" "--" ] then [ "${lib.getExe' tini "tini"}" "--" ]
else []; else [];
Env = [ Env = [
"CONDUWUIT_TLS__KEY=${./private_key.key}" "SSL_CERT_FILE=/complement/ca/ca.crt"
"CONDUWUIT_TLS__CERTS=${./certificate.crt}"
"CONDUWUIT_CONFIG=${./config.toml}" "CONDUWUIT_CONFIG=${./config.toml}"
"RUST_BACKTRACE=full"
]; ];
ExposedPorts = { ExposedPorts = {
-28
View File
@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDS/odmZivxajeb
iyT7SMuhXqnMm+hF+zEARLcbieem0wG4x7gi2S6WLf8DlifdXax6me13eYk4rBnT
LvGEvNNx0px5M54H+FVyoVa3c1tmA66WUcZjobafPGsDh5j+5qpScgWwjkMPGg1a
09CphCFswO4PpxUUORX/OTGj/rEKxximW6OtavBwaS9F7mqjXJK7lCrcZxKq5ucc
ebGMmCoO660hROSTBaFigdRTVicclk+NgYRrZyWbCiuXPjQ0jlOE2rcaDepqTUga
Qs/2tdT4kBzBH6kZOiQOIN/ddXaj032QXr1HQYfIJfJmiM6nmRob8nik5rpZdWNO
/Ncsro/fAgMBAAECggEAITCCkfv+a5I+vwvrPE/eIDso0JOxvNhfg+BLQVy3AMnu
WmeoMmshZeREWgcTrEGg8QQnk4Sdrjl8MnkO6sddJ2luza3t7OkGX+q7Hk5aETkB
DIo+f8ufU3sIhlydF3OnVSK0fGpUaBq8AQ6Soyeyrk3G5NVufmjgae5QPbDBnqUb
piOGyfcwagL4JtCbZsMk8AT7vQSynLm6zaWsVzWNd71jummLqtVV063K95J9PqVN
D8meEcP3WR5kQrvf+mgy9RVgWLRtVWN8OLZfJ9yrnl4Efj62elrldUj4jaCFezGQ
8f0W+d8jjt038qhmEdymw2MWQ+X/b0R79lJar1Up8QKBgQD1DtHxauhl+JUoI3y+
3eboqXl7YPJt1/GTnChb4b6D1Z1hvLsOKUa7hjGEfruYGbsWXBCRMICdfzp+iWcq
/lEOp7/YU9OaW4lQMoG4sXMoBWd9uLgg0E+aH6VDJOBvxsfafqM4ufmtspzwEm90
FU1cq6oImomFnPChSq4X+3+YpwKBgQDcalaK9llCcscWA8HAP8WVVNTjCOqiDp9q
td61E9IO/FIB/gW5y+JkaFRrA2CN1zY3s3K92uveLTNYTArecWlDcPNNFDuaYu2M
Roz4bC104HGh+zztJ0iPVzELL81Lgg6wHhLONN+eVi4gTftJxzJFXybyb+xVT25A
91ynKXB+CQKBgQC+Ub43MoI+/6pHvBfb3FbDByvz6D0flgBmVXb6tP3TQYmzKHJV
8zSd2wCGGC71V7Z3DRVIzVR1/SOetnPLbivhp+JUzfWfAcxI3pDksdvvjxLrDxTh
VycbWcxtsywjY0w/ou581eLVRcygnpC0pP6qJCAwAmUfwd0YRvmiYo6cLQKBgHIW
UIlJDdaJFmdctnLOD3VGHZMOUHRlYTqYvJe5lKbRD5mcZFZRI/OY1Ok3LEj+tj+K
kL+YizHK76KqaY3N4hBYbHbfHCLDRfWvptQHGlg+vFJ9eoG+LZ6UIPyLV5XX0cZz
KoS1dXG9Zc6uznzXsDucDsq6B/f4TzctUjXsCyARAoGAOKb4HtuNyYAW0jUlujR7
IMHwUesOGlhSXqFtP9aTvk6qJgvV0+3CKcWEb4y02g+uYftP8BLNbJbIt9qOqLYh
tOVyzCoamAi8araAhjA0w4dXvqDCDK7k/gZFkojmKQtRijoxTHnWcDc3vAjYCgaM
9MVtdgSkuh2gwkD/mMoAJXM=
-----END PRIVATE KEY-----
-16
View File
@@ -1,16 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIChDCCAWwCAQAwPzELMAkGA1UEBhMCNjkxCzAJBgNVBAgMAjQyMRUwEwYDVQQK
DAx3b29mZXJzIGluYy4xDDAKBgNVBAMMA2hzMTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBANL+h2ZmK/FqN5uLJPtIy6Feqcyb6EX7MQBEtxuJ56bTAbjH
uCLZLpYt/wOWJ91drHqZ7Xd5iTisGdMu8YS803HSnHkzngf4VXKhVrdzW2YDrpZR
xmOhtp88awOHmP7mqlJyBbCOQw8aDVrT0KmEIWzA7g+nFRQ5Ff85MaP+sQrHGKZb
o61q8HBpL0XuaqNckruUKtxnEqrm5xx5sYyYKg7rrSFE5JMFoWKB1FNWJxyWT42B
hGtnJZsKK5c+NDSOU4TatxoN6mpNSBpCz/a11PiQHMEfqRk6JA4g3911dqPTfZBe
vUdBh8gl8maIzqeZGhvyeKTmull1Y0781yyuj98CAwEAAaAAMA0GCSqGSIb3DQEB
CwUAA4IBAQDR/gjfxN0IID1MidyhZB4qpdWn3m6qZnEQqoTyHHdWalbfNXcALC79
ffS+Smx40N5hEPvqy6euR89N5YuYvt8Hs+j7aWNBn7Wus5Favixcm2JcfCTJn2R3
r8FefuSs2xGkoyGsPFFcXE13SP/9zrZiwvOgSIuTdz/Pbh6GtEx7aV4DqHJsrXnb
XuPxpQleoBqKvQgSlmaEBsJg13TQB+Fl2foBVUtqAFDQiv+RIuircf0yesMCKJaK
MPH4Oo+r3pR8lI8ewfJPreRhCoV+XrGYMubaakz003TJ1xlOW8M+N9a6eFyMVh76
U1nY/KP8Ua6Lgaj9PRz7JCRzNoshZID/
-----END CERTIFICATE REQUEST-----
-6
View File
@@ -4,9 +4,3 @@ keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names subjectAltName = @alt_names
[alt_names] [alt_names]
DNS.1 = *.docker.internal
DNS.2 = hs1
DNS.3 = hs2
DNS.4 = hs3
DNS.5 = hs4
IP.1 = 127.0.0.1
+27 -8
View File
@@ -13,6 +13,12 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
lib.concatStringsSep 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 # This disables PIE for static builds, which isn't great in terms
# of security. Unfortunately, my hand is forced because nixpkgs' # of security. Unfortunately, my hand is forced because nixpkgs'
# `libstdc++.a` is built without `-fPIE`, which precludes us from # `libstdc++.a` is built without `-fPIE`, which precludes us from
@@ -22,13 +28,25 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
[ "-C" "relocation-model=static" ] [ "-C" "relocation-model=static" ]
++ lib.optionals ++ lib.optionals
(stdenv.buildPlatform.config != stdenv.hostPlatform.config) (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" "-l"
"stdc++" "stdc++"
"-L" "-L"
"${stdenv.cc.cc.lib}/${stdenv.hostPlatform.config}/lib" "${stdenv.cc.cc.lib}/${stdenv.hostPlatform.config}/lib"
] ]
@@ -40,7 +58,7 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
# even covers the case of build scripts that need native code compiled and # even covers the case of build scripts that need native code compiled and
# run on the build platform (I think). # run on the build platform (I think).
# #
# [0]: https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/pkgs/build-support/rust/lib/default.nix#L48-L68 # [0]: https://github.com/NixOS/nixpkgs/blob/5cdb38bb16c6d0a38779db14fcc766bc1b2394d6/pkgs/build-support/rust/lib/default.nix#L57-L80
// //
( (
let let
@@ -56,7 +74,8 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
{ {
"CC_${cargoEnvVarTarget}" = envVars.ccForTarget; "CC_${cargoEnvVarTarget}" = envVars.ccForTarget;
"CXX_${cargoEnvVarTarget}" = envVars.cxxForTarget; "CXX_${cargoEnvVarTarget}" = envVars.cxxForTarget;
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.ccForTarget; "CARGO_TARGET_${cargoEnvVarTarget}_LINKER" =
envVars.linkerForTarget;
} }
) )
// //
@@ -67,7 +86,7 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
{ {
"CC_${cargoEnvVarTarget}" = envVars.ccForHost; "CC_${cargoEnvVarTarget}" = envVars.ccForHost;
"CXX_${cargoEnvVarTarget}" = envVars.cxxForHost; "CXX_${cargoEnvVarTarget}" = envVars.cxxForHost;
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.ccForHost; "CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.linkerForHost;
CARGO_BUILD_TARGET = rustcTarget; CARGO_BUILD_TARGET = rustcTarget;
} }
) )
@@ -79,7 +98,7 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
{ {
"CC_${cargoEnvVarTarget}" = envVars.ccForBuild; "CC_${cargoEnvVarTarget}" = envVars.ccForBuild;
"CXX_${cargoEnvVarTarget}" = envVars.cxxForBuild; "CXX_${cargoEnvVarTarget}" = envVars.cxxForBuild;
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.ccForBuild; "CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.linkerForBuild;
HOST_CC = "${pkgsBuildHost.stdenv.cc}/bin/cc"; HOST_CC = "${pkgsBuildHost.stdenv.cc}/bin/cc";
HOST_CXX = "${pkgsBuildHost.stdenv.cc}/bin/c++"; HOST_CXX = "${pkgsBuildHost.stdenv.cc}/bin/c++";
} }
+46 -61
View File
@@ -7,35 +7,17 @@
, liburing , liburing
, pkgsBuildHost , pkgsBuildHost
, rocksdb , rocksdb
, removeReferencesTo
, rust , rust
, rust-jemalloc-sys , rust-jemalloc-sys
, stdenv , stdenv
# Options (keep sorted) # Options (keep sorted)
, all_features ? false
, default_features ? true , 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 , disable_release_max_log_level ? false
, all_features ? false
, disable_features ? []
, features ? [] , features ? []
, profile ? "release" , 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 let
@@ -57,7 +39,7 @@ features'' = lib.subtractLists disable_features' features';
featureEnabled = feature : builtins.elem feature features''; featureEnabled = feature : builtins.elem feature features'';
enableLiburing = featureEnabled "io_uring" && !stdenv.hostPlatform.isDarwin; enableLiburing = featureEnabled "io_uring" && !stdenv.isDarwin;
# This derivation will set the JEMALLOC_OVERRIDE variable, causing the # This derivation will set the JEMALLOC_OVERRIDE variable, causing the
# tikv-jemalloc-sys crate to use the nixpkgs jemalloc instead of building it's # tikv-jemalloc-sys crate to use the nixpkgs jemalloc instead of building it's
@@ -74,41 +56,48 @@ rust-jemalloc-sys' = (rust-jemalloc-sys.override {
# we dont need cxx/C++ integration # we dont need cxx/C++ integration
[ "--disable-cxx" ] ++ [ "--disable-cxx" ] ++
# tikv-jemalloc-sys/profiling feature # tikv-jemalloc-sys/profiling feature
lib.optional (featureEnabled "jemalloc_prof") "--enable-prof" ++ lib.optional (featureEnabled "jemalloc_prof") "--enable-prof";
# tikv-jemalloc-sys/stats feature
(if (featureEnabled "jemalloc_stats") then [ "--enable-stats" ] else [ "--disable-stats" ]);
}); });
buildDepsOnlyEnv = buildDepsOnlyEnv =
let let
rocksdb' = (rocksdb.override { rocksdb' = (rocksdb.override {
jemalloc = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys'; jemalloc = rust-jemalloc-sys';
# rocksdb fails to build with prefixed jemalloc, which is required on # rocksdb fails to build with prefixed jemalloc, which is required on
# darwin due to [1]. In this case, fall back to building rocksdb with # darwin due to [1]. In this case, fall back to building rocksdb with
# libc malloc. This should not cause conflicts, because all of the # libc malloc. This should not cause conflicts, because all of the
# jemalloc symbols are prefixed. # jemalloc symbols are prefixed.
# #
# [1]: https://github.com/tikv/jemallocator/blob/ab0676d77e81268cd09b059260c75b38dbef2d51/jemalloc-sys/src/env.rs#L17 # [1]: https://github.com/tikv/jemallocator/blob/ab0676d77e81268cd09b059260c75b38dbef2d51/jemalloc-sys/src/env.rs#L17
enableJemalloc = featureEnabled "jemalloc" && !stdenv.hostPlatform.isDarwin; enableJemalloc = featureEnabled "jemalloc" && !stdenv.isDarwin;
# for some reason enableLiburing in nixpkgs rocksdb is default true # for some reason enableLiburing in nixpkgs rocksdb is default true
# which breaks Darwin entirely # which breaks Darwin entirely
enableLiburing = enableLiburing; enableLiburing = enableLiburing;
}).overrideAttrs (old: { }).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; 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;
# outputs has "tools" which we dont need or use sse42Support = stdenv.targetPlatform.isx86_64;
outputs = [ "out" ];
# preInstall hooks has stuff for messing with ldb/sst_dump which we dont need or use cmakeFlags = if stdenv.targetPlatform.isx86_64
preInstall = ""; then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags
++ lib.optionals stdenv.targetPlatform.isx86_64 [
"-DPORTABLE=x86-64-v2"
"-DUSE_SSE=1"
"-DHAVE_SSE=1"
"-DHAVE_SSE42=1"
]
else if stdenv.targetPlatform.isAarch64
then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags
++ lib.optionals stdenv.targetPlatform.isAarch64 [
# cortex-a55 == ARMv8.2-a
"-DPORTABLE=armv8.2-a"
]
else old.cmakeFlags;
}); });
in in
{ {
@@ -136,8 +125,10 @@ buildPackageEnv = {
CARGO_BUILD_RUSTFLAGS = buildDepsOnlyEnv.CARGO_BUILD_RUSTFLAGS CARGO_BUILD_RUSTFLAGS = buildDepsOnlyEnv.CARGO_BUILD_RUSTFLAGS
+ lib.optionalString (enableLiburing && stdenv.hostPlatform.isStatic) + lib.optionalString (enableLiburing && stdenv.hostPlatform.isStatic)
" -L${lib.getLib liburing}/lib -luring" " -L${lib.getLib liburing}/lib -luring"
+ lib.optionalString x86_64_haswell_target_optimised + lib.optionalString stdenv.targetPlatform.isx86_64
" -Ctarget-cpu=haswell"; " -Ctarget-cpu=x86-64-v2"
+ lib.optionalString stdenv.targetPlatform.isAarch64
" -Ctarget-cpu=cortex-a55"; # cortex-a55 == ARMv8.2-a
}; };
@@ -155,33 +146,16 @@ commonAttrs = {
# Keep sorted # Keep sorted
include = [ include = [
".cargo"
"Cargo.lock" "Cargo.lock"
"Cargo.toml" "Cargo.toml"
"deps"
"src" "src"
]; ];
}; };
doCheck = true;
cargoExtraArgs = "--no-default-features --locked "
+ lib.optionalString
(features'' != [])
"--features " + (builtins.concatStringsSep "," features'');
dontStrip = profile == "dev" || profile == "test"; 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 = [ nativeBuildInputs = [
# bindgen needs the build platform's libclang. Apparently due to "splicing # bindgen needs the build platform's libclang. Apparently due to "splicing
@@ -194,6 +168,14 @@ commonAttrs = {
# differing values for `NIX_CFLAGS_COMPILE`, which contributes to spurious # differing values for `NIX_CFLAGS_COMPILE`, which contributes to spurious
# rebuilds of bindgen and its depedents. # rebuilds of bindgen and its depedents.
jq jq
]
++ 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
]; ];
}; };
in in
@@ -203,13 +185,16 @@ craneLib.buildPackage ( commonAttrs // {
env = buildDepsOnlyEnv; env = buildDepsOnlyEnv;
}); });
doCheck = true; cargoExtraArgs = "--no-default-features "
cargoExtraArgs = "--no-default-features --locked "
+ lib.optionalString + lib.optionalString
(features'' != []) (features'' != [])
"--features " + (builtins.concatStringsSep "," features''); "--features " + (builtins.concatStringsSep "," features'');
# This is redundant with CI
cargoTestCommand = "";
cargoCheckCommand = "";
doCheck = false;
env = buildPackageEnv; env = buildPackageEnv;
passthru = { passthru = {
+1 -19
View File
@@ -14,10 +14,9 @@ dockerTools.buildLayeredImage {
created = "@${toString inputs.self.lastModified}"; created = "@${toString inputs.self.lastModified}";
contents = [ contents = [
dockerTools.caCertificates dockerTools.caCertificates
main
]; ];
config = { config = {
Entrypoint = if !stdenv.hostPlatform.isDarwin Entrypoint = if !stdenv.isDarwin
# Use the `tini` init system so that signals (e.g. ctrl+c/SIGINT) # Use the `tini` init system so that signals (e.g. ctrl+c/SIGINT)
# are handled as expected # are handled as expected
then [ "${lib.getExe' tini "tini"}" "--" ] then [ "${lib.getExe' tini "tini"}" "--" ]
@@ -25,22 +24,5 @@ dockerTools.buildLayeredImage {
Cmd = [ Cmd = [
"${lib.getExe main}" "${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;
};
}; };
} }
+1 -11
View File
@@ -12,15 +12,5 @@
"nix": { "nix": {
"enabled": true "enabled": true
}, },
"labels": [ "labels": ["dependencies", "github_actions"]
"dependencies",
"github_actions"
],
"ignoreDeps": [
"tikv-jemllocator",
"tikv-jemalloc-sys",
"tikv-jemalloc-ctl",
"opentelemetry-rust",
"tracing-opentelemetry"
]
} }
+3 -9
View File
@@ -2,6 +2,8 @@
# #
# Other files that need upkeep when this changes: # Other files that need upkeep when this changes:
# #
# * `.gitlab-ci.yml`
# * `.github/workflows/ci.yml`
# * `Cargo.toml` # * `Cargo.toml`
# * `flake.nix` # * `flake.nix`
# #
@@ -9,21 +11,13 @@
# If you're having trouble making the relevant changes, bug a maintainer. # If you're having trouble making the relevant changes, bug a maintainer.
[toolchain] [toolchain]
channel = "1.86.0" channel = "1.80.0"
profile = "minimal"
components = [ components = [
# For rust-analyzer # For rust-analyzer
"rust-src", "rust-src",
"rust-analyzer",
# For CI and editors
"rustfmt",
"clippy",
] ]
targets = [ targets = [
#"x86_64-apple-darwin",
"x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-musl", "x86_64-unknown-linux-musl",
"aarch64-unknown-linux-musl", "aarch64-unknown-linux-musl",
"aarch64-unknown-linux-gnu",
#"aarch64-apple-darwin",
] ]
+15 -20
View File
@@ -1,33 +1,28 @@
array_width = 80 edition = "2021"
chain_width = 60
comment_width = 80
condense_wildcard_suffixes = true condense_wildcard_suffixes = true
style_edition = "2024"
fn_call_width = 80
fn_single_line = true
format_code_in_doc_comments = true format_code_in_doc_comments = true
format_macro_bodies = true format_macro_bodies = true
format_macro_matchers = true format_macro_matchers = true
format_strings = true format_strings = true
group_imports = "StdExternalCrate"
hard_tabs = true
hex_literal_case = "Upper" hex_literal_case = "Upper"
imports_granularity = "Crate" max_width = 120
match_arm_blocks = false tab_spaces = 4
match_arm_leading_pipes = "Always" array_width = 80
comment_width = 80
wrap_comments = true
fn_params_layout = "Compressed"
fn_call_width = 80
fn_single_line = true
hard_tabs = true
match_block_trailing_comma = true match_block_trailing_comma = true
max_width = 98 imports_granularity = "Crate"
newline_style = "Unix"
normalize_comments = false normalize_comments = false
overflow_delimited_expr = true
reorder_impl_items = true reorder_impl_items = true
reorder_imports = true reorder_imports = true
single_line_if_else_max_width = 60 group_imports = "StdExternalCrate"
single_line_let_else_max_width = 80 newline_style = "Unix"
struct_lit_width = 40
tab_spaces = 4
unstable_features = true
use_field_init_shorthand = true use_field_init_shorthand = true
use_small_heuristics = "Off" use_small_heuristics = "Off"
use_try_shorthand = true use_try_shorthand = true
wrap_comments = true chain_width = 60
+6 -7
View File
@@ -1,5 +1,5 @@
[package] [package]
name = "conduwuit_admin" name = "conduit_admin"
categories.workspace = true categories.workspace = true
description.workspace = true description.workspace = true
edition.workspace = true edition.workspace = true
@@ -17,6 +17,7 @@ crate-type = [
] ]
[features] [features]
#dev_release_log_level = []
release_max_log_level = [ release_max_log_level = [
"tracing/max_level_trace", "tracing/max_level_trace",
"tracing/release_max_level_info", "tracing/release_max_level_info",
@@ -26,13 +27,11 @@ release_max_log_level = [
[dependencies] [dependencies]
clap.workspace = true clap.workspace = true
conduwuit-api.workspace = true conduit-api.workspace = true
conduwuit-core.workspace = true conduit-core.workspace = true
conduwuit-database.workspace = true conduit-service.workspace = true
conduwuit-macros.workspace = true
conduwuit-service.workspace = true
const-str.workspace = true const-str.workspace = true
futures.workspace = true futures-util.workspace = true
log.workspace = true log.workspace = true
ruma.workspace = true ruma.workspace = true
serde_json.workspace = true serde_json.workspace = true
-68
View File
@@ -1,68 +0,0 @@
use clap::Parser;
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,
};
#[derive(Debug, Parser)]
#[command(name = "conduwuit", version = conduwuit::version())]
pub(super) enum AdminCommand {
#[command(subcommand)]
/// - Commands for managing appservices
Appservices(AppserviceCommand),
#[command(subcommand)]
/// - Commands for managing local users
Users(UserCommand),
#[command(subcommand)]
/// - Commands for managing rooms
Rooms(RoomCommand),
#[command(subcommand)]
/// - Commands for managing federation
Federation(FederationCommand),
#[command(subcommand)]
/// - Commands for managing the server
Server(ServerCommand),
#[command(subcommand)]
/// - Commands for managing media
Media(MediaCommand),
#[command(subcommand)]
/// - Commands for checking integrity
Check(CheckCommand),
#[command(subcommand)]
/// - Commands for debugging things
Debug(DebugCommand),
#[command(subcommand)]
/// - Low-level queries for database getters and iterators
Query(QueryCommand),
}
#[tracing::instrument(skip_all, name = "command")]
pub(super) async fn process(command: AdminCommand, context: &Command<'_>) -> Result {
use AdminCommand::*;
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(())
}
+23 -46
View File
@@ -1,84 +1,61 @@
use ruma::{api::appservice::Registration, events::room::message::RoomMessageEventContent}; use ruma::{api::appservice::Registration, events::room::message::RoomMessageEventContent};
use crate::{Result, admin_command}; use crate::{services, Result};
#[admin_command] pub(super) async fn register(body: Vec<&str>) -> Result<RoomMessageEventContent> {
pub(super) async fn register(&self) -> Result<RoomMessageEventContent> { if body.len() < 2 || !body[0].trim().starts_with("```") || 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( return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.", "Expected code block in command body. Add --help for details.",
)); ));
} }
let appservice_config_body = self.body[1..self.body.len().checked_sub(1).unwrap()].join("\n"); let appservice_config = body[1..body.len().checked_sub(1).unwrap()].join("\n");
let parsed_config = serde_yaml::from_str::<Registration>(&appservice_config_body); let parsed_config = serde_yaml::from_str::<Registration>(&appservice_config);
match parsed_config { match parsed_config {
| Ok(registration) => match self Ok(yaml) => match services().appservice.register_appservice(yaml).await {
.services Ok(id) => Ok(RoomMessageEventContent::text_plain(format!(
.appservice "Appservice registered with ID: {id}."
.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}" "Failed to register appservice: {e}"
))), ))),
}, },
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!( Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Could not parse appservice config as YAML: {e}" "Could not parse appservice config: {e}"
))), ))),
} }
} }
#[admin_command] pub(super) async fn unregister(_body: Vec<&str>, appservice_identifier: String) -> Result<RoomMessageEventContent> {
pub(super) async fn unregister( match services()
&self,
appservice_identifier: String,
) -> Result<RoomMessageEventContent> {
match self
.services
.appservice .appservice
.unregister_appservice(&appservice_identifier) .unregister_appservice(&appservice_identifier)
.await .await
{ {
| Ok(()) => Ok(RoomMessageEventContent::text_plain("Appservice unregistered.")), Ok(()) => Ok(RoomMessageEventContent::text_plain("Appservice unregistered.")),
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!( Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to unregister appservice: {e}" "Failed to unregister appservice: {e}"
))), ))),
} }
} }
#[admin_command] pub(super) async fn show(_body: Vec<&str>, appservice_identifier: String) -> Result<RoomMessageEventContent> {
pub(super) async fn show_appservice_config( match services()
&self,
appservice_identifier: String,
) -> Result<RoomMessageEventContent> {
match self
.services
.appservice .appservice
.get_registration(&appservice_identifier) .get_registration(&appservice_identifier)
.await .await
{ {
| Some(config) => { Some(config) => {
let config_str = serde_yaml::to_string(&config) let config_str = serde_yaml::to_string(&config).expect("config should've been validated on register");
.expect("config should've been validated on register"); let output = format!("Config for {appservice_identifier}:\n\n```yaml\n{config_str}\n```",);
let output =
format!("Config for {appservice_identifier}:\n\n```yaml\n{config_str}\n```",);
Ok(RoomMessageEventContent::notice_markdown(output)) Ok(RoomMessageEventContent::notice_markdown(output))
}, },
| None => Ok(RoomMessageEventContent::text_plain("Appservice does not exist.")), None => Ok(RoomMessageEventContent::text_plain("Appservice does not exist.")),
} }
} }
#[admin_command] pub(super) async fn list(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
pub(super) async fn list_registered(&self) -> Result<RoomMessageEventContent> { let appservices = services().appservice.iter_ids().await;
let appservices = self.services.appservice.iter_ids().await;
let output = format!("Appservices ({}): {}", appservices.len(), appservices.join(", ")); let output = format!("Appservices ({}): {}", appservices.len(), appservices.join(", "));
Ok(RoomMessageEventContent::text_plain(output)) Ok(RoomMessageEventContent::text_plain(output))
} }
+20 -8
View File
@@ -1,12 +1,13 @@
mod commands; mod commands;
use clap::Subcommand; use clap::Subcommand;
use conduwuit::Result; use conduit::Result;
use ruma::events::room::message::RoomMessageEventContent;
use crate::admin_command_dispatch; use self::commands::*;
#[derive(Debug, Subcommand)] #[cfg_attr(test, derive(Debug))]
#[admin_command_dispatch] #[derive(Subcommand)]
pub(super) enum AppserviceCommand { pub(super) enum AppserviceCommand {
/// - Register an appservice using its registration YAML /// - Register an appservice using its registration YAML
/// ///
@@ -28,13 +29,24 @@ pub(super) enum AppserviceCommand {
/// - Show an appservice's config using its ID /// - Show an appservice's config using its ID
/// ///
/// You can find the ID using the `list-appservices` command. /// You can find the ID using the `list-appservices` command.
#[clap(alias("show"))] Show {
ShowAppserviceConfig {
/// The appservice to show /// The appservice to show
appservice_identifier: String, appservice_identifier: String,
}, },
/// - List all the currently registered appservices /// - List all the currently registered appservices
#[clap(alias("list"))] List,
ListRegistered, }
pub(super) async fn process(command: AppserviceCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
AppserviceCommand::Register => register(body).await?,
AppserviceCommand::Unregister {
appservice_identifier,
} => unregister(body, appservice_identifier).await?,
AppserviceCommand::Show {
appservice_identifier,
} => show(body, appservice_identifier).await?,
AppserviceCommand::List => list(body).await?,
})
} }
+10 -12
View File
@@ -1,27 +1,25 @@
use conduwuit::Result; use conduit::Result;
use conduwuit_macros::implement;
use futures::StreamExt;
use ruma::events::room::message::RoomMessageEventContent; use ruma::events::room::message::RoomMessageEventContent;
use crate::Command; use crate::services;
/// Uses the iterator in `src/database/key_value/users.rs` to iterator over /// Uses the iterator in `src/database/key_value/users.rs` to iterator over
/// every user in our database (remote and local). Reports total count, any /// every user in our database (remote and local). Reports total count, any
/// errors if there were any, etc /// errors if there were any, etc
#[implement(Command, params = "<'_>")] pub(super) async fn check_all_users(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
pub(super) async fn check_all_users(&self) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let users = self.services.users.iter().collect::<Vec<_>>().await; let results = services().users.db.iter();
let query_time = timer.elapsed(); let query_time = timer.elapsed();
let users = results.collect::<Vec<_>>();
let total = users.len(); let total = users.len();
let err_count = users.iter().filter(|_user| false).count(); let err_count = users.iter().filter(|user| user.is_err()).count();
let ok_count = users.iter().filter(|_user| true).count(); let ok_count = users.iter().filter(|user| user.is_ok()).count();
let message = format!( let message = format!(
"Database query completed in {query_time:?}:\n\n```\nTotal entries: \ "Database query completed in {query_time:?}:\n\n```\nTotal entries: {total:?}\nFailure/Invalid user count: \
{total:?}\nFailure/Invalid user count: {err_count:?}\nSuccess/Valid user count: \ {err_count:?}\nSuccess/Valid user count: {ok_count:?}\n```"
{ok_count:?}\n```"
); );
Ok(RoomMessageEventContent::notice_markdown(message)) Ok(RoomMessageEventContent::notice_markdown(message))
+12 -5
View File
@@ -1,12 +1,19 @@
mod commands; mod commands;
use clap::Subcommand; use clap::Subcommand;
use conduwuit::Result; use conduit::Result;
use ruma::events::room::message::RoomMessageEventContent;
use crate::admin_command_dispatch; use self::commands::*;
#[admin_command_dispatch] #[cfg_attr(test, derive(Debug))]
#[derive(Debug, Subcommand)] #[derive(Subcommand)]
pub(super) enum CheckCommand { pub(super) enum CheckCommand {
CheckAllUsers, AllUsers,
}
pub(super) async fn process(command: CheckCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
CheckCommand::AllUsers => check_all_users(body).await?,
})
} }
-39
View File
@@ -1,39 +0,0 @@
use std::{fmt, time::SystemTime};
use conduwuit::Result;
use conduwuit_service::Services;
use futures::{
Future, FutureExt,
io::{AsyncWriteExt, BufWriter},
lock::Mutex,
};
use ruma::EventId;
pub(crate) struct Command<'a> {
pub(crate) services: &'a Services,
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 + '_ + use<'_> {
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
+62 -77
View File
@@ -2,15 +2,14 @@ mod commands;
pub(crate) mod tester; pub(crate) mod tester;
use clap::Subcommand; use clap::Subcommand;
use conduwuit::Result; use conduit::Result;
use ruma::{EventId, OwnedRoomOrAliasId, RoomId, ServerName}; use ruma::{events::room::message::RoomMessageEventContent, EventId, OwnedRoomOrAliasId, RoomId, ServerName};
use service::rooms::short::{ShortEventId, ShortRoomId}; use tester::TesterCommand;
use self::tester::TesterCommand; use self::commands::*;
use crate::admin_command_dispatch;
#[admin_command_dispatch] #[cfg_attr(test, derive(Debug))]
#[derive(Debug, Subcommand)] #[derive(Subcommand)]
pub(super) enum DebugCommand { pub(super) enum DebugCommand {
/// - Echo input of admin command /// - Echo input of admin command
Echo { Echo {
@@ -32,21 +31,12 @@ pub(super) enum DebugCommand {
/// the command. /// the command.
ParsePdu, ParsePdu,
/// - Retrieve and print a PDU by EventID from the conduwuit database /// - Retrieve and print a PDU by ID from the conduwuit database
GetPdu { GetPdu {
/// An event ID (a $ followed by the base64 reference hash) /// An event ID (a $ followed by the base64 reference hash)
event_id: Box<EventId>, 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 /// - 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 /// database/timeline if found and we do not have this PDU already
/// (following normal event auth rules, handles it as an incoming PDU). /// (following normal event auth rules, handles it as an incoming PDU).
@@ -86,22 +76,6 @@ pub(super) enum DebugCommand {
room_id: OwnedRoomOrAliasId, room_id: OwnedRoomOrAliasId,
}, },
/// - Get and display signing keys from local cache or remote server.
GetSigningKeys {
server_name: Option<Box<ServerName>>,
#[arg(long)]
notary: Option<Box<ServerName>>,
#[arg(short, long)]
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 /// - Sends a federation request to the remote server's
/// `/_matrix/federation/v1/version` endpoint and measures the latency it /// `/_matrix/federation/v1/version` endpoint and measures the latency it
/// took for the server to respond /// took for the server to respond
@@ -137,13 +111,6 @@ pub(super) enum DebugCommand {
/// the command. /// the command.
VerifyJson, 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 /// - Prints the very first PDU in the specified room (typically
/// m.room.create) /// m.room.create)
FirstPduInRoom { FirstPduInRoom {
@@ -191,13 +158,7 @@ pub(super) enum DebugCommand {
}, },
/// - Print extended memory usage /// - 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. /// - Print general tokio runtime metric totals.
RuntimeMetrics, RuntimeMetrics,
@@ -206,37 +167,61 @@ pub(super) enum DebugCommand {
/// invocation. /// invocation.
RuntimeInterval, RuntimeInterval,
/// - Print the current time
Time,
/// - List dependencies
ListDependencies {
#[arg(short, long)]
names: bool,
},
/// - Get database statistics
DatabaseStats {
property: Option<String>,
#[arg(short, long, alias("column"))]
map: Option<String>,
},
/// - Trim memory usage
TrimMemory,
/// - List database files
DatabaseFiles {
map: Option<String>,
#[arg(long)]
level: Option<i32>,
},
/// - Developer test stubs /// - Developer test stubs
#[command(subcommand)] #[command(subcommand)]
#[allow(non_snake_case)]
#[clap(hide(true))]
Tester(TesterCommand), Tester(TesterCommand),
} }
pub(super) async fn process(command: DebugCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
DebugCommand::Echo {
message,
} => echo(body, message).await?,
DebugCommand::GetAuthChain {
event_id,
} => get_auth_chain(body, event_id).await?,
DebugCommand::ParsePdu => parse_pdu(body).await?,
DebugCommand::GetPdu {
event_id,
} => get_pdu(body, event_id).await?,
DebugCommand::GetRemotePdu {
event_id,
server,
} => get_remote_pdu(body, event_id, server).await?,
DebugCommand::GetRoomState {
room_id,
} => get_room_state(body, room_id).await?,
DebugCommand::Ping {
server,
} => ping(body, server).await?,
DebugCommand::ForceDeviceListUpdates => force_device_list_updates(body).await?,
DebugCommand::ChangeLogLevel {
filter,
reset,
} => change_log_level(body, filter, reset).await?,
DebugCommand::SignJson => sign_json(body).await?,
DebugCommand::VerifyJson => verify_json(body).await?,
DebugCommand::FirstPduInRoom {
room_id,
} => first_pdu_in_room(body, room_id).await?,
DebugCommand::LatestPduInRoom {
room_id,
} => latest_pdu_in_room(body, room_id).await?,
DebugCommand::GetRemotePduList {
server,
force,
} => get_remote_pdu_list(body, server, force).await?,
DebugCommand::ForceSetRoomStateFromServer {
room_id,
server_name,
} => force_set_room_state_from_server(body, server_name, room_id).await?,
DebugCommand::ResolveTrueDestination {
server_name,
no_cache,
} => resolve_true_destination(body, server_name, no_cache).await?,
DebugCommand::MemoryStats => memory_stats(),
DebugCommand::RuntimeMetrics => runtime_metrics(body).await?,
DebugCommand::RuntimeInterval => runtime_interval(body).await?,
DebugCommand::Tester(command) => tester::process(command, body).await?,
})
}
+13 -24
View File
@@ -1,45 +1,34 @@
use conduwuit::Err;
use ruma::events::room::message::RoomMessageEventContent; use ruma::events::room::message::RoomMessageEventContent;
use crate::{Result, admin_command, admin_command_dispatch}; use crate::Result;
#[admin_command_dispatch] #[derive(clap::Subcommand)]
#[derive(Debug, clap::Subcommand)] #[cfg_attr(test, derive(Debug))]
pub(crate) enum TesterCommand { pub(crate) enum TesterCommand {
Panic,
Failure,
Tester, Tester,
Timer, Timer,
} }
#[rustfmt::skip] pub(super) async fn process(command: TesterCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
#[admin_command] match command {
async fn panic(&self) -> Result<RoomMessageEventContent> { TesterCommand::Tester => tester(body).await,
TesterCommand::Timer => timer(body).await,
panic!("panicked") }
}
#[rustfmt::skip]
#[admin_command]
async fn failure(&self) -> Result<RoomMessageEventContent> {
Err!("failed")
} }
#[inline(never)] #[inline(never)]
#[rustfmt::skip] #[rustfmt::skip]
#[admin_command] #[allow(unused_variables)]
async fn tester(&self) -> Result<RoomMessageEventContent> { async fn tester(body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(RoomMessageEventContent::notice_plain("legacy")) Ok(RoomMessageEventContent::notice_plain("completed"))
} }
#[inline(never)] #[inline(never)]
#[rustfmt::skip] #[rustfmt::skip]
#[admin_command] async fn timer(body: Vec<&str>) -> Result<RoomMessageEventContent> {
async fn timer(&self) -> Result<RoomMessageEventContent> {
let started = std::time::Instant::now(); let started = std::time::Instant::now();
timed(self.body); timed(&body);
let elapsed = started.elapsed(); let elapsed = started.elapsed();
Ok(RoomMessageEventContent::notice_plain(format!("completed in {elapsed:#?}"))) Ok(RoomMessageEventContent::notice_plain(format!("completed in {elapsed:#?}")))
+47 -49
View File
@@ -1,29 +1,21 @@
use std::fmt::Write; use std::fmt::Write;
use conduwuit::Result; use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, RoomId, ServerName, UserId};
use futures::StreamExt;
use ruma::{
OwnedRoomId, RoomId, ServerName, UserId, events::room::message::RoomMessageEventContent,
};
use crate::{admin_command, get_room_info}; use crate::{escape_html, get_room_info, services, Result};
#[admin_command] pub(super) async fn disable_room(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
pub(super) async fn disable_room(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> { services().rooms.metadata.disable_room(&room_id, true)?;
self.services.rooms.metadata.disable_room(&room_id, true);
Ok(RoomMessageEventContent::text_plain("Room disabled.")) Ok(RoomMessageEventContent::text_plain("Room disabled."))
} }
#[admin_command] pub(super) async fn enable_room(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
pub(super) async fn enable_room(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> { services().rooms.metadata.disable_room(&room_id, false)?;
self.services.rooms.metadata.disable_room(&room_id, false);
Ok(RoomMessageEventContent::text_plain("Room enabled.")) Ok(RoomMessageEventContent::text_plain("Room enabled."))
} }
#[admin_command] pub(super) async fn incoming_federation(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
pub(super) async fn incoming_federation(&self) -> Result<RoomMessageEventContent> { let map = services()
let map = self
.services
.rooms .rooms
.event_handler .event_handler
.federation_handletime .federation_handletime
@@ -39,13 +31,11 @@ pub(super) async fn incoming_federation(&self) -> Result<RoomMessageEventContent
Ok(RoomMessageEventContent::text_plain(&msg)) Ok(RoomMessageEventContent::text_plain(&msg))
} }
#[admin_command]
pub(super) async fn fetch_support_well_known( pub(super) async fn fetch_support_well_known(
&self, _body: Vec<&str>, server_name: Box<ServerName>,
server_name: Box<ServerName>,
) -> Result<RoomMessageEventContent> { ) -> Result<RoomMessageEventContent> {
let response = self let response = services()
.services .globals
.client .client
.default .default
.get(format!("https://{server_name}/.well-known/matrix/support")) .get(format!("https://{server_name}/.well-known/matrix/support"))
@@ -65,20 +55,16 @@ pub(super) async fn fetch_support_well_known(
} }
let json: serde_json::Value = match serde_json::from_str(&text) { let json: serde_json::Value = match serde_json::from_str(&text) {
| Ok(json) => json, Ok(json) => json,
| Err(_) => { Err(_) => {
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain("Response text/body is not valid JSON."));
"Response text/body is not valid JSON.",
));
}, },
}; };
let pretty_json: String = match serde_json::to_string_pretty(&json) { let pretty_json: String = match serde_json::to_string_pretty(&json) {
| Ok(json) => json, Ok(json) => json,
| Err(_) => { Err(_) => {
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain("Response text/body is not valid JSON."));
"Response text/body is not valid JSON.",
));
}, },
}; };
@@ -87,32 +73,26 @@ pub(super) async fn fetch_support_well_known(
))) )))
} }
#[admin_command] pub(super) async fn remote_user_in_rooms(_body: Vec<&str>, user_id: Box<UserId>) -> Result<RoomMessageEventContent> {
pub(super) async fn remote_user_in_rooms( if user_id.server_name() == services().globals.config.server_name {
&self,
user_id: Box<UserId>,
) -> Result<RoomMessageEventContent> {
if user_id.server_name() == self.services.server.name {
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain(
"User belongs to our server, please use `list-joined-rooms` user admin command \ "User belongs to our server, please use `list-joined-rooms` user admin command instead.",
instead.",
)); ));
} }
if !self.services.users.exists(&user_id).await { if !services().users.exists(&user_id)? {
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain(
"Remote user does not exist in our database.", "Remote user does not exist in our database.",
)); ));
} }
let mut rooms: Vec<(OwnedRoomId, u64, String)> = self let mut rooms: Vec<(OwnedRoomId, u64, String)> = services()
.services
.rooms .rooms
.state_cache .state_cache
.rooms_joined(&user_id) .rooms_joined(&user_id)
.then(|room_id| get_room_info(self.services, room_id)) .filter_map(Result::ok)
.collect() .map(|room_id| get_room_info(&room_id))
.await; .collect();
if rooms.is_empty() { if rooms.is_empty() {
return Ok(RoomMessageEventContent::text_plain("User is not in any rooms.")); return Ok(RoomMessageEventContent::text_plain("User is not in any rooms."));
@@ -121,15 +101,33 @@ pub(super) async fn remote_user_in_rooms(
rooms.sort_by_key(|r| r.1); rooms.sort_by_key(|r| r.1);
rooms.reverse(); rooms.reverse();
let output = format!( let output_plain = format!(
"Rooms {user_id} shares with us ({}):\n```\n{}\n```", "Rooms {user_id} shares with us ({}):\n{}",
rooms.len(), rooms.len(),
rooms rooms
.iter() .iter()
.map(|(id, members, name)| format!("{id} | Members: {members} | Name: {name}")) .map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}"))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .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_markdown(output)) Ok(RoomMessageEventContent::text_html(output_plain, output_html))
} }
+23 -5
View File
@@ -1,13 +1,13 @@
mod commands; mod commands;
use clap::Subcommand; use clap::Subcommand;
use conduwuit::Result; use conduit::Result;
use ruma::{RoomId, ServerName, UserId}; use ruma::{events::room::message::RoomMessageEventContent, RoomId, ServerName, UserId};
use crate::admin_command_dispatch; use self::commands::*;
#[admin_command_dispatch] #[cfg_attr(test, derive(Debug))]
#[derive(Debug, Subcommand)] #[derive(Subcommand)]
pub(super) enum FederationCommand { pub(super) enum FederationCommand {
/// - List all rooms we are currently handling an incoming pdu from /// - List all rooms we are currently handling an incoming pdu from
IncomingFederation, IncomingFederation,
@@ -40,3 +40,21 @@ pub(super) enum FederationCommand {
user_id: Box<UserId>, user_id: Box<UserId>,
}, },
} }
pub(super) async fn process(command: FederationCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
FederationCommand::DisableRoom {
room_id,
} => disable_room(body, room_id).await?,
FederationCommand::EnableRoom {
room_id,
} => enable_room(body, room_id).await?,
FederationCommand::IncomingFederation => incoming_federation(body).await?,
FederationCommand::FetchSupportWellKnown {
server_name,
} => fetch_support_well_known(body, server_name).await?,
FederationCommand::RemoteUserInRooms {
user_id,
} => remote_user_in_rooms(body, user_id).await?,
})
}
+241
View File
@@ -0,0 +1,241 @@
use std::{panic::AssertUnwindSafe, time::Instant};
use clap::{CommandFactory, Parser};
use conduit::{error, trace, Error};
use futures_util::future::FutureExt;
use ruma::{
events::{
relation::InReplyTo,
room::message::{Relation::Reply, RoomMessageEventContent},
},
OwnedEventId,
};
extern crate conduit_service as service;
use conduit::{utils::string::common_prefix, Result};
pub(crate) use service::admin::{Command, Service};
use service::admin::{CommandOutput, CommandResult, HandlerResult};
use crate::{
appservice, appservice::AppserviceCommand, check, check::CheckCommand, debug, debug::DebugCommand, federation,
federation::FederationCommand, media, media::MediaCommand, query, query::QueryCommand, room, room::RoomCommand,
server, server::ServerCommand, services, user, user::UserCommand,
};
pub(crate) const PAGE_SIZE: usize = 100;
#[derive(Parser)]
#[command(name = "admin", version = env!("CARGO_PKG_VERSION"))]
pub(crate) enum AdminCommand {
#[command(subcommand)]
/// - Commands for managing appservices
Appservices(AppserviceCommand),
#[command(subcommand)]
/// - Commands for managing local users
Users(UserCommand),
#[command(subcommand)]
/// - Commands for managing rooms
Rooms(RoomCommand),
#[command(subcommand)]
/// - Commands for managing federation
Federation(FederationCommand),
#[command(subcommand)]
/// - Commands for managing the server
Server(ServerCommand),
#[command(subcommand)]
/// - Commands for managing media
Media(MediaCommand),
#[command(subcommand)]
/// - Commands for checking integrity
Check(CheckCommand),
#[command(subcommand)]
/// - Commands for debugging things
Debug(DebugCommand),
#[command(subcommand)]
/// - Low-level queries for database getters and iterators
Query(QueryCommand),
}
#[must_use]
pub(crate) fn handle(command: Command) -> HandlerResult { Box::pin(handle_command(command)) }
#[must_use]
pub(crate) fn complete(line: &str) -> String { complete_admin_command(AdminCommand::command(), line) }
#[tracing::instrument(skip_all, name = "admin")]
async fn handle_command(command: Command) -> CommandResult {
AssertUnwindSafe(process_command(&command))
.catch_unwind()
.await
.map_err(Error::from_panic)
.or_else(|error| handle_panic(&error, command))
}
async fn process_command(command: &Command) -> CommandOutput {
process_admin_message(&command.command)
.await
.and_then(|content| reply(content, command.reply_id.clone()))
}
fn handle_panic(error: &Error, command: Command) -> CommandResult {
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:?}");
Ok(reply(content, command.reply_id))
}
fn reply(mut content: RoomMessageEventContent, reply_id: Option<OwnedEventId>) -> Option<RoomMessageEventContent> {
content.relates_to = reply_id.map(|event_id| Reply {
in_reply_to: InReplyTo {
event_id,
},
});
Some(content)
}
// Parse and process a message from the admin room
async fn process_admin_message(msg: &str) -> CommandOutput {
let mut lines = msg.lines().filter(|l| !l.trim().is_empty());
let command = lines.next().expect("each string has at least one line");
let body = lines.collect::<Vec<_>>();
let parsed = match parse_admin_command(command) {
Ok(parsed) => parsed,
Err(error) => {
let server_name = services().globals.server_name();
let message = error.replace("server.name", server_name.as_str());
return Some(RoomMessageEventContent::notice_markdown(message));
},
};
let timer = Instant::now();
let result = process_admin_command(parsed, body).await;
let elapsed = timer.elapsed();
conduit::debug!(?command, ok = result.is_ok(), "command processed in {elapsed:?}");
match result {
Ok(reply) => Some(reply),
Err(error) => Some(RoomMessageEventContent::notice_markdown(format!(
"Encountered an error while handling the command:\n```\n{error:#?}\n```"
))),
}
}
#[tracing::instrument(skip_all, name = "command")]
async fn process_admin_command(command: AdminCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
let reply_message_content = match command {
AdminCommand::Appservices(command) => appservice::process(command, body).await?,
AdminCommand::Media(command) => media::process(command, body).await?,
AdminCommand::Users(command) => user::process(command, body).await?,
AdminCommand::Rooms(command) => room::process(command, body).await?,
AdminCommand::Federation(command) => federation::process(command, body).await?,
AdminCommand::Server(command) => server::process(command, body).await?,
AdminCommand::Debug(command) => debug::process(command, body).await?,
AdminCommand::Query(command) => query::process(command, body).await?,
AdminCommand::Check(command) => check::process(command, body).await?,
};
Ok(reply_message_content)
}
// Parse chat messages from the admin room into an AdminCommand object
fn parse_admin_command(command_line: &str) -> Result<AdminCommand, String> {
let argv = parse_command_line(command_line);
AdminCommand::try_parse_from(argv).map_err(|error| error.to_string())
}
fn complete_admin_command(mut cmd: clap::Command, line: &str) -> String {
let argv = parse_command_line(line);
let mut ret = Vec::<String>::with_capacity(argv.len().saturating_add(1));
'token: for token in argv.into_iter().skip(1) {
let cmd_ = cmd.clone();
let mut choice = Vec::new();
for sub in cmd_.get_subcommands() {
let name = sub.get_name();
if *name == token {
// token already complete; recurse to subcommand
ret.push(token);
cmd.clone_from(sub);
continue 'token;
} else if name.starts_with(&token) {
// partial match; add to choices
choice.push(name);
}
}
if choice.len() == 1 {
// One choice. Add extra space because it's complete
let choice = *choice.first().expect("only choice");
ret.push(choice.to_owned());
ret.push(String::new());
} else if choice.is_empty() {
// Nothing found, return original string
ret.push(token);
} else {
// Find the common prefix
ret.push(common_prefix(&choice).into());
}
// Return from completion
return ret.join(" ");
}
// Return from no completion. Needs a space though.
ret.push(String::new());
ret.join(" ")
}
// Parse chat messages from the admin room into an AdminCommand object
fn parse_command_line(command_line: &str) -> Vec<String> {
let mut argv = command_line
.split_whitespace()
.map(str::to_owned)
.collect::<Vec<String>>();
// Remove any escapes that came with a server-side escape command
if !argv.is_empty() && argv[0].ends_with("admin") {
argv[0] = argv[0].trim_start_matches('\\').into();
}
// First indice has to be "admin" but for console convenience we add it here
let server_user = services().globals.server_user.as_str();
if !argv.is_empty() && !argv[0].ends_with("admin") && !argv[0].starts_with(server_user) {
argv.insert(0, "admin".to_owned());
}
// Replace `help command` with `command --help`
// Clap has a help subcommand, but it omits the long help description.
if argv.len() > 1 && argv[1] == "help" {
argv.remove(1);
argv.push("--help".to_owned());
}
// Backwards compatibility with `register_appservice`-style commands
if argv.len() > 1 && argv[1].contains('_') {
argv[1] = argv[1].replace('_', "-");
}
// Backwards compatibility with `register_appservice`-style commands
if argv.len() > 2 && argv[2].contains('_') {
argv[2] = argv[2].replace('_', "-");
}
// if the user is using the `query` command (argv[1]), replace the database
// function/table calls with underscores to match the codebase
if argv.len() > 3 && argv[1].eq("query") {
argv[3] = argv[3].replace('_', "-");
}
trace!(?command_line, ?argv, "parse");
argv
}
+47 -267
View File
@@ -1,21 +1,11 @@
use std::time::Duration; use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, EventId, MxcUri};
use tracing::{debug, info};
use conduwuit::{ use crate::services;
Result, debug, debug_info, debug_warn, error, info, trace, utils::time::parse_timepoint_ago,
};
use conduwuit_service::media::Dim;
use ruma::{
EventId, Mxc, MxcUri, OwnedMxcUri, OwnedServerName, ServerName,
events::room::message::RoomMessageEventContent,
};
use crate::{admin_command, utils::parse_local_user_id};
#[admin_command]
pub(super) async fn delete( pub(super) async fn delete(
&self, _body: Vec<&str>, mxc: Option<Box<MxcUri>>, event_id: Option<Box<EventId>>,
mxc: Option<Box<MxcUri>>,
event_id: Option<Box<EventId>>,
) -> Result<RoomMessageEventContent> { ) -> Result<RoomMessageEventContent> {
if event_id.is_some() && mxc.is_some() { if event_id.is_some() && mxc.is_some() {
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain(
@@ -24,25 +14,20 @@ pub(super) async fn delete(
} }
if let Some(mxc) = mxc { if let Some(mxc) = mxc {
trace!("Got MXC URL: {mxc}"); debug!("Got MXC URL: {mxc}");
self.services services().media.delete(mxc.as_ref()).await?;
.media
.delete(&mxc.as_str().try_into()?)
.await?;
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain(
"Deleted the MXC from our database and on our filesystem.", "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}");
if let Some(event_id) = event_id { let mut mxc_urls = vec![];
trace!("Got event ID to delete media from: {event_id}"); let mut mxc_deletion_count: usize = 0;
let mut mxc_urls = Vec::with_capacity(4);
// parsing the PDU for any MXC URLs begins here // parsing the PDU for any MXC URLs begins here
match self.services.rooms.timeline.get_pdu_json(&event_id).await { if let Some(event_json) = services().rooms.timeline.get_pdu_json(&event_id)? {
| Ok(event_json) => {
if let Some(content_key) = event_json.get("content") { if let Some(content_key) = event_json.get("content") {
debug!("Event ID has \"content\"."); debug!("Event ID has \"content\".");
let content_obj = content_key.as_object(); let content_obj = content_key.as_object();
@@ -58,10 +43,7 @@ pub(super) async fn delete(
let final_url = url.to_string().replace('"', ""); let final_url = url.to_string().replace('"', "");
mxc_urls.push(final_url); mxc_urls.push(final_url);
} else { } else {
info!( 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"
);
} }
} }
@@ -76,24 +58,17 @@ pub(super) async fn delete(
debug!("Found a thumbnail_url in info key: {thumbnail_url}"); debug!("Found a thumbnail_url in info key: {thumbnail_url}");
if thumbnail_url.to_string().starts_with("\"mxc://") { if thumbnail_url.to_string().starts_with("\"mxc://") {
debug!( debug!("Pushing thumbnail URL {thumbnail_url} to list of MXCs to delete");
"Pushing thumbnail URL {thumbnail_url} to list of \ let final_thumbnail_url = thumbnail_url.to_string().replace('"', "");
MXCs to delete"
);
let final_thumbnail_url =
thumbnail_url.to_string().replace('"', "");
mxc_urls.push(final_thumbnail_url); mxc_urls.push(final_thumbnail_url);
} else { } else {
info!( info!(
"Found a thumbnail URL in the event ID {event_id} \ "Found a thumbnail URL in the event ID {event_id} but did not start with \
but did not start with mxc://, ignoring" mxc://, ignoring"
); );
} }
} else { } else {
info!( info!("No \"thumbnail_url\" key in \"info\" key, assuming no thumbnails.");
"No \"thumbnail_url\" key in \"info\" key, assuming no \
thumbnails."
);
} }
} }
} }
@@ -114,8 +89,8 @@ pub(super) async fn delete(
mxc_urls.push(final_url); mxc_urls.push(final_url);
} else { } else {
info!( info!(
"Found a URL in the event ID {event_id} but did not \ "Found a URL in the event ID {event_id} but did not start with mxc://, \
start with mxc://, ignoring" ignoring"
); );
} }
} else { } else {
@@ -125,275 +100,80 @@ pub(super) async fn delete(
} }
} else { } else {
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain(
"Event ID does not have a \"content\" key or failed parsing the \ "Event ID does not have a \"content\" key or failed parsing the event ID JSON.",
event ID JSON.",
)); ));
} }
} else { } else {
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain(
"Event ID does not have a \"content\" key, this is not a message or an \ "Event ID does not have a \"content\" key, this is not a message or an event type that contains \
event type that contains media.", media.",
)); ));
} }
}, } else {
| _ => {
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain(
"Event ID does not exist or is not known to us.", "Event ID does not exist or is not known to us.",
)); ));
},
} }
if mxc_urls.is_empty() { 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."); info!("Parsed event ID {event_id} but did not contain any MXC URLs.");
return Ok(RoomMessageEventContent::text_plain( return Ok(RoomMessageEventContent::text_plain("Parsed event ID but found no MXC URLs."));
"Parsed event ID but found no MXC URLs.",
));
} }
let mut mxc_deletion_count: usize = 0;
for mxc_url in mxc_urls { for mxc_url in mxc_urls {
match self services().media.delete(&mxc_url).await?;
.services
.media
.delete(&mxc_url.as_str().try_into()?)
.await
{
| Ok(()) => {
debug_info!("Successfully deleted {mxc_url} from filesystem and database");
mxc_deletion_count = mxc_deletion_count.saturating_add(1); 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!( return Ok(RoomMessageEventContent::text_plain(format!(
"Deleted {mxc_deletion_count} total MXCs from our database and the filesystem from \ "Deleted {mxc_deletion_count} total MXCs from our database and the filesystem from event ID {event_id}."
event ID {event_id}."
))); )));
} }
Ok(RoomMessageEventContent::text_plain( Ok(RoomMessageEventContent::text_plain(
"Please specify either an MXC using --mxc or an event ID using --event-id of the \ "Please specify either an MXC using --mxc or an event ID using --event-id of the message containing an image. \
message containing an image. See --help for details.", See --help for details.",
)) ))
} }
#[admin_command] pub(super) async fn delete_list(body: Vec<&str>) -> Result<RoomMessageEventContent> {
pub(super) async fn delete_list(&self) -> Result<RoomMessageEventContent> { if body.len() < 2 || !body[0].trim().starts_with("```") || 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( return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.", "Expected code block in command body. Add --help for details.",
)); ));
} }
let mut failed_parsed_mxcs: usize = 0; let mxc_list = body
.clone()
let mxc_list = self .drain(1..body.len().checked_sub(1).unwrap())
.body .collect::<Vec<_>>();
.to_vec()
.drain(1..self.body.len().checked_sub(1).unwrap())
.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; let mut mxc_deletion_count: usize = 0;
for mxc in &mxc_list { for mxc in mxc_list {
trace!(%failed_parsed_mxcs, %mxc_deletion_count, "Deleting MXC {mxc} in bulk"); debug!("Deleting MXC {mxc} in bulk");
match self.services.media.delete(mxc).await { services().media.delete(mxc).await?;
| Ok(()) => { mxc_deletion_count = mxc_deletion_count
debug_info!("Successfully deleted {mxc} from filesystem and database"); .checked_add(1)
mxc_deletion_count = mxc_deletion_count.saturating_add(1); .expect("mxc_deletion_count should not get this high");
},
| Err(e) => {
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
continue;
},
}
} }
Ok(RoomMessageEventContent::text_plain(format!( Ok(RoomMessageEventContent::text_plain(format!(
"Finished bulk MXC deletion, deleted {mxc_deletion_count} total MXCs from our database \ "Finished bulk MXC deletion, deleted {mxc_deletion_count} total MXCs from our database and the filesystem.",
and the filesystem. {failed_parsed_mxcs} MXCs failed to be parsed from the database.",
))) )))
} }
#[admin_command]
pub(super) async fn delete_past_remote_media( pub(super) async fn delete_past_remote_media(
&self, _body: Vec<&str>, duration: String, force: bool,
duration: String,
before: bool,
after: bool,
yes_i_want_to_delete_local_media: bool,
) -> Result<RoomMessageEventContent> { ) -> Result<RoomMessageEventContent> {
if before && after { let deleted_count = services()
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 .media
.delete_all_remote_media_at_after_time( .delete_all_remote_media_at_after_time(duration, force)
duration,
before,
after,
yes_i_want_to_delete_local_media,
)
.await?; .await?;
Ok(RoomMessageEventContent::text_plain(format!( Ok(RoomMessageEventContent::text_plain(format!(
"Deleted {deleted_count} total files.", "Deleted {deleted_count} total files.",
))) )))
} }
#[admin_command]
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).await?;
Ok(RoomMessageEventContent::text_plain(format!(
"Deleted {deleted_count} total files.",
)))
}
#[admin_command]
pub(super) async fn delete_all_from_server(
&self,
server_name: Box<ServerName>,
yes_i_want_to_delete_local_media: bool,
) -> Result<RoomMessageEventContent> {
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
.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 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)
&& !yes_i_want_to_delete_local_media)
{
trace!("skipping MXC URI {mxc}");
continue;
}
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
match self.services.media.delete(&mxc).await {
| Ok(()) => {
deleted_count = deleted_count.saturating_add(1);
},
| Err(e) => {
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
continue;
},
}
}
Ok(RoomMessageEventContent::text_plain(format!(
"Deleted {deleted_count} total files.",
)))
}
#[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).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,
) -> Result<RoomMessageEventContent> {
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
let timeout = Duration::from_millis(timeout.into());
let mut result = self
.services
.media
.fetch_remote_content(&mxc, None, server.as_deref(), timeout)
.await?;
// Grab the length of the content before clearing it to not flood the output
let len = result.content.as_ref().expect("content").len();
result.content.as_mut().expect("content").clear();
let out = format!("```\n{result:#?}\nreceived {len} bytes for file content.\n```");
Ok(RoomMessageEventContent::notice_markdown(out))
}
#[admin_command]
pub(super) async fn get_remote_thumbnail(
&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());
let dim = Dim::new(width, height, None);
let mut result = self
.services
.media
.fetch_remote_thumbnail(&mxc, None, server.as_deref(), timeout, &dim)
.await?;
// Grab the length of the content before clearing it to not flood the output
let len = result.content.as_ref().expect("content").len();
result.content.as_mut().expect("content").clear();
let out = format!("```\n{result:#?}\nreceived {len} bytes for file content.\n```");
Ok(RoomMessageEventContent::notice_markdown(out))
}
+27 -73
View File
@@ -1,17 +1,16 @@
#![allow(rustdoc::broken_intra_doc_links)]
mod commands; mod commands;
use clap::Subcommand; use clap::Subcommand;
use conduwuit::Result; use conduit::Result;
use ruma::{EventId, MxcUri, OwnedMxcUri, OwnedServerName, ServerName}; use ruma::{events::room::message::RoomMessageEventContent, EventId, MxcUri};
use crate::admin_command_dispatch; use self::commands::*;
#[admin_command_dispatch] #[cfg_attr(test, derive(Debug))]
#[derive(Debug, Subcommand)] #[derive(Subcommand)]
pub(super) enum MediaCommand { pub(super) enum MediaCommand {
/// - Deletes a single media file from our database and on the filesystem /// - Deletes a single media file from our database and on the filesystem
/// via a single MXC URL or event ID (not redacted) /// via a single MXC URL
Delete { Delete {
/// The MXC URL to delete /// The MXC URL to delete
#[arg(long)] #[arg(long)]
@@ -24,76 +23,31 @@ pub(super) enum MediaCommand {
}, },
/// - Deletes a codeblock list of MXC URLs from our database and on the /// - Deletes a codeblock list of MXC URLs from our database and on the
/// filesystem. This will always ignore errors. /// filesystem
DeleteList, DeleteList,
/// - Deletes all remote (and optionally local) media created before or /// - Deletes all remote media in the last X amount of time using filesystem
/// after [duration] time using filesystem metadata first created at date, /// metadata first created at date.
/// or fallback to last modified date. This will always ignore errors by
/// default.
DeletePastRemoteMedia { DeletePastRemoteMedia {
/// - The relative time (e.g. 30s, 5m, 7d) within which to search /// - The duration (at or after), e.g. "5m" to delete all media in the
/// past 5 minutes
duration: String, duration: String,
/// Continues deleting remote media if an undeletable object is found
/// - Only delete media created before [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. This will
/// always ignore errors by default.
DeleteAllFromUser {
username: String,
},
/// - Deletes all remote media from the specified remote server. This will
/// always ignore errors by default.
DeleteAllFromServer {
server_name: Box<ServerName>,
/// Long argument to delete local media
#[arg(long)]
yes_i_want_to_delete_local_media: bool,
},
GetFileInfo {
/// The MXC URL to lookup info for.
mxc: OwnedMxcUri,
},
GetRemoteFile {
/// The MXC URL to fetch
mxc: OwnedMxcUri,
#[arg(short, long)] #[arg(short, long)]
server: Option<OwnedServerName>, force: bool,
#[arg(short, long, default_value("10000"))]
timeout: u32,
},
GetRemoteThumbnail {
/// The MXC URL to fetch
mxc: OwnedMxcUri,
#[arg(short, long)]
server: Option<OwnedServerName>,
#[arg(short, long, default_value("10000"))]
timeout: u32,
#[arg(short, long, default_value("800"))]
width: u32,
#[arg(short, long, default_value("800"))]
height: u32,
}, },
} }
pub(super) async fn process(command: MediaCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
MediaCommand::Delete {
mxc,
event_id,
} => delete(body, mxc, event_id).await?,
MediaCommand::DeleteList => delete_list(body).await?,
MediaCommand::DeletePastRemoteMedia {
duration,
force,
} => delete_past_remote_media(body, duration, force).await?,
})
}
+23 -29
View File
@@ -1,60 +1,54 @@
#![recursion_limit = "192"]
#![allow(clippy::wildcard_imports)] #![allow(clippy::wildcard_imports)]
#![allow(clippy::enum_glob_use)]
#![allow(clippy::too_many_arguments)]
pub(crate) mod admin;
pub(crate) mod command;
pub(crate) mod processor;
mod tests;
pub(crate) mod utils;
pub(crate) mod appservice; pub(crate) mod appservice;
pub(crate) mod check; pub(crate) mod check;
pub(crate) mod debug; pub(crate) mod debug;
pub(crate) mod federation; pub(crate) mod federation;
pub(crate) mod handler;
pub(crate) mod media; pub(crate) mod media;
pub(crate) mod query; pub(crate) mod query;
pub(crate) mod room; pub(crate) mod room;
pub(crate) mod server; pub(crate) mod server;
mod tests;
pub(crate) mod user; pub(crate) mod user;
pub(crate) mod utils;
extern crate conduwuit_api as api; extern crate conduit_api as api;
extern crate conduwuit_core as conduwuit; extern crate conduit_core as conduit;
extern crate conduwuit_service as service; extern crate conduit_service as service;
pub(crate) use conduwuit::Result; pub(crate) use conduit::{mod_ctor, mod_dtor, Result};
pub(crate) use conduwuit_macros::{admin_command, admin_command_dispatch}; pub(crate) use service::{services, user_is_local};
pub(crate) use crate::{ pub(crate) use crate::{
command::Command, handler::Service,
utils::{escape_html, get_room_info}, utils::{escape_html, get_room_info},
}; };
pub(crate) const PAGE_SIZE: usize = 100; mod_ctor! {}
mod_dtor! {}
conduwuit::mod_ctor! {} /// Install the admin command handler
conduwuit::mod_dtor! {} pub async fn init() {
conduwuit::rustc_flags_capture! {} _ = services()
.admin
/// Install the admin command processor
pub async fn init(admin_service: &service::admin::Service) {
_ = admin_service
.complete .complete
.write() .write()
.expect("locked for writing") .expect("locked for writing")
.insert(processor::complete); .insert(handler::complete);
_ = admin_service _ = services()
.admin
.handle .handle
.write() .write()
.await .await
.insert(processor::dispatch); .insert(handler::handle);
} }
/// Uninstall the admin command handler /// Uninstall the admin command handler
pub async fn fini(admin_service: &service::admin::Service) { pub async fn fini() {
_ = admin_service.handle.write().await.take(); _ = services().admin.handle.write().await.take();
_ = admin_service _ = services()
.admin
.complete .complete
.write() .write()
.expect("locked for writing") .expect("locked for writing")
-290
View File
@@ -1,290 +0,0 @@
use std::{
fmt::Write,
mem::take,
panic::AssertUnwindSafe,
sync::{Arc, Mutex},
time::SystemTime,
};
use clap::{CommandFactory, Parser};
use conduwuit::{
Error, Result, debug, error,
log::{
capture,
capture::Capture,
fmt::{markdown_table, markdown_table_head},
},
trace,
utils::string::{collect_stream, common_prefix},
warn,
};
use futures::{AsyncWriteExt, future::FutureExt, io::BufWriter};
use ruma::{
EventId,
events::{
relation::InReplyTo,
room::message::{Relation::Reply, RoomMessageEventContent},
},
};
use service::{
Services,
admin::{CommandInput, CommandOutput, ProcessorFuture, ProcessorResult},
};
use tracing::Level;
use tracing_subscriber::{EnvFilter, filter::LevelFilter};
use crate::{Command, admin, admin::AdminCommand};
#[must_use]
pub(super) fn complete(line: &str) -> String { complete_command(AdminCommand::command(), line) }
#[must_use]
pub(super) fn dispatch(services: Arc<Services>, command: CommandInput) -> ProcessorFuture {
Box::pin(handle_command(services, command))
}
#[tracing::instrument(skip_all, name = "admin")]
async fn handle_command(services: Arc<Services>, command: CommandInput) -> ProcessorResult {
AssertUnwindSafe(Box::pin(process_command(services, &command)))
.catch_unwind()
.await
.map_err(Error::from_panic)
.unwrap_or_else(|error| handle_panic(&error, &command))
}
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,
};
let context = Command {
services: &services,
body: &body,
timer: SystemTime::now(),
reply_id: input.reply_id.as_deref(),
output: BufWriter::new(Vec::new()).into(),
};
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))
},
}
}
#[allow(clippy::result_large_err)]
fn handle_panic(error: &Error, command: &CommandInput) -> ProcessorResult {
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:?}");
Err(reply(content, command.reply_id.as_deref()))
}
/// Parse and process a message from the admin room
async fn process(
context: &Command<'_>,
command: AdminCommand,
args: &[String],
) -> (Result, String) {
let (capture, logs) = capture_create(context);
let capture_scope = capture.start();
let result = Box::pin(admin::process(command, context)).await;
drop(capture_scope);
debug!(
ok = result.is_ok(),
elapsed = ?context.timer.elapsed(),
command = ?args,
"command processed"
);
let mut output = String::new();
// Prepend the logs only if any were captured
let logs = logs.lock().expect("locked");
if logs.lines().count() > 2 {
writeln!(&mut output, "{logs}").expect("failed to format logs to command output");
}
drop(logs);
(result, output)
}
fn capture_create(context: &Command<'_>) -> (Arc<Capture>, Arc<Mutex<String>>) {
let env_config = &context.services.server.config.admin_log_capture;
let env_filter = EnvFilter::try_new(env_config).unwrap_or_else(|e| {
warn!("admin_log_capture filter invalid: {e:?}");
cfg!(debug_assertions)
.then_some("debug")
.or(Some("info"))
.map(Into::into)
.expect("default capture EnvFilter")
});
let log_level = env_filter
.max_level_hint()
.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 logs = Arc::new(Mutex::new(
collect_stream(|s| markdown_table_head(s)).expect("markdown table header"),
));
let capture = Capture::new(
&context.services.server.log.capture,
Some(filter),
capture::fmt(markdown_table, logs.clone()),
);
(capture, logs)
}
/// Parse chat messages from the admin room into an AdminCommand object
#[allow(clippy::result_large_err)]
fn parse<'a>(
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) => {
let message = error
.to_string()
.replace("server.name", services.globals.server_name().as_str());
Err(reply(RoomMessageEventContent::notice_plain(message), input.reply_id.as_deref()))
},
}
}
fn parse_command(line: &str) -> Result<(AdminCommand, Vec<String>)> {
let argv = parse_line(line);
let command = AdminCommand::try_parse_from(&argv)?;
Ok((command, argv))
}
fn complete_command(mut cmd: clap::Command, line: &str) -> String {
let argv = parse_line(line);
let mut ret = Vec::<String>::with_capacity(argv.len().saturating_add(1));
'token: for token in argv.into_iter().skip(1) {
let cmd_ = cmd.clone();
let mut choice = Vec::new();
for sub in cmd_.get_subcommands() {
let name = sub.get_name();
if *name == token {
// token already complete; recurse to subcommand
ret.push(token);
cmd.clone_from(sub);
continue 'token;
} else if name.starts_with(&token) {
// partial match; add to choices
choice.push(name);
}
}
if choice.len() == 1 {
// One choice. Add extra space because it's complete
let choice = *choice.first().expect("only choice");
ret.push(choice.to_owned());
ret.push(String::new());
} else if choice.is_empty() {
// Nothing found, return original string
ret.push(token);
} else {
// Find the common prefix
ret.push(common_prefix(&choice).into());
}
// Return from completion
return ret.join(" ");
}
// Return from no completion. Needs a space though.
ret.push(String::new());
ret.join(" ")
}
/// Parse chat messages from the admin room into an AdminCommand object
fn parse_line(command_line: &str) -> Vec<String> {
let mut argv = command_line
.split_whitespace()
.map(str::to_owned)
.collect::<Vec<String>>();
// Remove any escapes that came with a server-side escape command
if !argv.is_empty() && argv[0].ends_with("admin") {
argv[0] = argv[0].trim_start_matches('\\').into();
}
// First indice has to be "admin" but for console convenience we add it here
if !argv.is_empty() && !argv[0].ends_with("admin") && !argv[0].starts_with('@') {
argv.insert(0, "admin".to_owned());
}
// Replace `help command` with `command --help`
// Clap has a help subcommand, but it omits the long help description.
if argv.len() > 1 && argv[1] == "help" {
argv.remove(1);
argv.push("--help".to_owned());
}
// Backwards compatibility with `register_appservice`-style commands
if argv.len() > 1 && argv[1].contains('_') {
argv[1] = argv[1].replace('_', "-");
}
// Backwards compatibility with `register_appservice`-style commands
if argv.len() > 2 && argv[2].contains('_') {
argv[2] = argv[2].replace('_', "-");
}
// if the user is using the `query` command (argv[1]), replace the database
// function/table calls with underscores to match the codebase
if argv.len() > 3 && argv[1].eq("query") {
argv[3] = argv[3].replace('_', "-");
}
trace!(?command_line, ?argv, "parse");
argv
}
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() },
});
content
}
+22 -54
View File
@@ -1,72 +1,40 @@
use clap::Subcommand; use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use futures::StreamExt;
use ruma::{RoomId, UserId, events::room::message::RoomMessageEventContent};
use crate::{admin_command, admin_command_dispatch}; use super::AccountData;
use crate::{services, Result};
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
/// All the getters and iterators from src/database/key_value/account_data.rs /// All the getters and iterators from src/database/key_value/account_data.rs
pub(crate) enum AccountDataCommand { pub(super) async fn account_data(subcommand: AccountData) -> Result<RoomMessageEventContent> {
/// - Returns all changes to the account data that happened after `since`. match subcommand {
ChangesSince { AccountData::ChangesSince {
/// Full user ID user_id,
user_id: Box<UserId>, since,
/// UNIX timestamp since (u64) room_id,
since: u64, } => {
/// Optional room ID of the account data
room_id: Option<Box<RoomId>>,
},
/// - Searches the account data for a specific kind.
AccountDataGet {
/// Full user ID
user_id: Box<UserId>,
/// Account data event type
kind: String,
/// Optional room ID of the account data
room_id: Option<Box<RoomId>>,
},
}
#[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 timer = tokio::time::Instant::now();
let results: Vec<_> = self let results = services()
.services
.account_data .account_data
.changes_since(room_id.as_deref(), &user_id, since, None) .changes_since(room_id.as_deref(), &user_id, since)?;
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
} },
AccountData::Get {
#[admin_command] user_id,
async fn account_data_get( kind,
&self, room_id,
user_id: Box<UserId>, } => {
kind: String,
room_id: Option<Box<RoomId>>,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = self let results = services()
.services
.account_data .account_data
.get_raw(room_id.as_deref(), &user_id, &kind) .get(room_id.as_deref(), &user_id, kind)?;
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
},
}
} }
+19 -27
View File
@@ -1,41 +1,33 @@
use clap::Subcommand; use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use crate::Command; use super::Appservice;
use crate::{services, Result};
#[derive(Debug, Subcommand)]
/// All the getters and iterators from src/database/key_value/appservice.rs
pub(crate) enum AppserviceCommand {
/// - Gets the appservice registration info/details from the ID as a string
GetRegistration {
/// Appservice registration ID
appservice_id: Box<str>,
},
/// - Gets all appservice registrations with their ID and registration info
All,
}
/// All the getters and iterators from src/database/key_value/appservice.rs /// All the getters and iterators from src/database/key_value/appservice.rs
pub(super) async fn process(subcommand: AppserviceCommand, context: &Command<'_>) -> Result { pub(super) async fn appservice(subcommand: Appservice) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand { match subcommand {
| AppserviceCommand::GetRegistration { appservice_id } => { Appservice::GetRegistration {
appservice_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services.appservice.get_registration(&appservice_id).await; let results = services()
.appservice
.db
.get_registration(appservice_id.as_ref());
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "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```"
)))
}, },
| AppserviceCommand::All => { Appservice::All => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services.appservice.all().await; let results = services().appservice.all();
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "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```"
)))
}, },
} }
.await
} }
+35 -36
View File
@@ -1,58 +1,57 @@
use clap::Subcommand; use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use ruma::ServerName;
use crate::Command; use super::Globals;
use crate::{services, Result};
#[derive(Debug, Subcommand)]
/// All the getters and iterators from src/database/key_value/globals.rs
pub(crate) enum GlobalsCommand {
DatabaseVersion,
CurrentCount,
LastCheckForUpdatesId,
/// - This returns an empty `Ok(BTreeMap<..>)` when there are no keys found
/// for the server.
SigningKeysFor {
origin: Box<ServerName>,
},
}
/// All the getters and iterators from src/database/key_value/globals.rs /// All the getters and iterators from src/database/key_value/globals.rs
pub(super) async fn process(subcommand: GlobalsCommand, context: &Command<'_>) -> Result { pub(super) async fn globals(subcommand: Globals) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand { match subcommand {
| GlobalsCommand::DatabaseVersion => { Globals::DatabaseVersion => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services.globals.db.database_version().await; let results = services().globals.db.database_version();
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "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```"
)))
}, },
| GlobalsCommand::CurrentCount => { Globals::CurrentCount => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services.globals.db.current_count(); let results = services().globals.db.current_count();
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "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```"
)))
}, },
| GlobalsCommand::LastCheckForUpdatesId => { Globals::LastCheckForUpdatesId => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services.updates.last_check_for_updates_id().await; let results = services().updates.last_check_for_updates_id();
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "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```"
)))
}, },
| GlobalsCommand::SigningKeysFor { origin } => { Globals::LoadKeypair => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services.server_keys.verify_keys_for(&origin).await; let results = services().globals.db.load_keypair();
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "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```"
)))
},
Globals::SigningKeysFor {
origin,
} => {
let timer = tokio::time::Instant::now();
let results = services().globals.db.signing_keys_for(&origin);
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
}, },
} }
.await
} }
+279 -38
View File
@@ -2,81 +2,322 @@ mod account_data;
mod appservice; mod appservice;
mod globals; mod globals;
mod presence; mod presence;
mod pusher;
mod raw;
mod resolver; mod resolver;
mod room_alias; mod room_alias;
mod room_state_cache; mod room_state_cache;
mod room_timeline;
mod sending; mod sending;
mod short;
mod users; mod users;
use clap::Subcommand; use clap::Subcommand;
use conduwuit::Result; use conduit::Result;
use room_state_cache::room_state_cache;
use ruma::{
events::{room::message::RoomMessageEventContent, RoomAccountDataEventType},
OwnedServerName, RoomAliasId, RoomId, ServerName, UserId,
};
use self::{ use self::{
account_data::AccountDataCommand, appservice::AppserviceCommand, globals::GlobalsCommand, account_data::account_data, appservice::appservice, globals::globals, presence::presence, resolver::resolver,
presence::PresenceCommand, pusher::PusherCommand, raw::RawCommand, resolver::ResolverCommand, room_alias::room_alias, sending::sending, users::users,
room_alias::RoomAliasCommand, room_state_cache::RoomStateCacheCommand,
room_timeline::RoomTimelineCommand, sending::SendingCommand, short::ShortCommand,
users::UsersCommand,
}; };
use crate::admin_command_dispatch;
#[admin_command_dispatch] #[cfg_attr(test, derive(Debug))]
#[derive(Debug, Subcommand)] #[derive(Subcommand)]
/// Query tables from database /// Query tables from database
pub(super) enum QueryCommand { pub(super) enum QueryCommand {
/// - account_data.rs iterators and getters /// - account_data.rs iterators and getters
#[command(subcommand)] #[command(subcommand)]
AccountData(AccountDataCommand), AccountData(AccountData),
/// - appservice.rs iterators and getters /// - appservice.rs iterators and getters
#[command(subcommand)] #[command(subcommand)]
Appservice(AppserviceCommand), Appservice(Appservice),
/// - presence.rs iterators and getters /// - presence.rs iterators and getters
#[command(subcommand)] #[command(subcommand)]
Presence(PresenceCommand), Presence(Presence),
/// - rooms/alias.rs iterators and getters /// - rooms/alias.rs iterators and getters
#[command(subcommand)] #[command(subcommand)]
RoomAlias(RoomAliasCommand), RoomAlias(RoomAlias),
/// - rooms/state_cache iterators and getters /// - rooms/state_cache iterators and getters
#[command(subcommand)] #[command(subcommand)]
RoomStateCache(RoomStateCacheCommand), RoomStateCache(RoomStateCache),
/// - rooms/timeline iterators and getters
#[command(subcommand)]
RoomTimeline(RoomTimelineCommand),
/// - globals.rs iterators and getters /// - globals.rs iterators and getters
#[command(subcommand)] #[command(subcommand)]
Globals(GlobalsCommand), Globals(Globals),
/// - sending.rs iterators and getters /// - sending.rs iterators and getters
#[command(subcommand)] #[command(subcommand)]
Sending(SendingCommand), Sending(Sending),
/// - users.rs iterators and getters /// - users.rs iterators and getters
#[command(subcommand)] #[command(subcommand)]
Users(UsersCommand), Users(Users),
/// - resolver service /// - resolver service
#[command(subcommand)] #[command(subcommand)]
Resolver(ResolverCommand), Resolver(Resolver),
}
/// - pusher service
#[command(subcommand)] #[cfg_attr(test, derive(Debug))]
Pusher(PusherCommand), #[derive(Subcommand)]
/// All the getters and iterators from src/database/key_value/account_data.rs
/// - short service pub(super) enum AccountData {
#[command(subcommand)] /// - Returns all changes to the account data that happened after `since`.
Short(ShortCommand), ChangesSince {
/// Full user ID
/// - raw service user_id: Box<UserId>,
#[command(subcommand)] /// UNIX timestamp since (u64)
Raw(RawCommand), since: u64,
/// Optional room ID of the account data
room_id: Option<Box<RoomId>>,
},
/// - Searches the account data for a specific kind.
Get {
/// Full user ID
user_id: Box<UserId>,
/// Account data event type
kind: RoomAccountDataEventType,
/// Optional room ID of the account data
room_id: Option<Box<RoomId>>,
},
}
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// All the getters and iterators from src/database/key_value/appservice.rs
pub(super) enum Appservice {
/// - Gets the appservice registration info/details from the ID as a string
GetRegistration {
/// Appservice registration ID
appservice_id: Box<str>,
},
/// - Gets all appservice registrations with their ID and registration info
All,
}
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// All the getters and iterators from src/database/key_value/presence.rs
pub(super) enum Presence {
/// - Returns the latest presence event for the given user.
GetPresence {
/// Full user ID
user_id: Box<UserId>,
},
/// - Iterator of the most recent presence updates that happened after the
/// event with id `since`.
PresenceSince {
/// UNIX timestamp since (u64)
since: u64,
},
}
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// All the getters and iterators from src/database/key_value/rooms/alias.rs
pub(super) enum RoomAlias {
ResolveLocalAlias {
/// Full room alias
alias: Box<RoomAliasId>,
},
/// - Iterator of all our local room aliases for the room ID
LocalAliasesForRoom {
/// Full room ID
room_id: Box<RoomId>,
},
/// - Iterator of all our local aliases in our database with their room IDs
AllLocalAliases,
}
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
pub(super) enum RoomStateCache {
ServerInRoom {
server: Box<ServerName>,
room_id: Box<RoomId>,
},
RoomServers {
room_id: Box<RoomId>,
},
ServerRooms {
server: Box<ServerName>,
},
RoomMembers {
room_id: Box<RoomId>,
},
LocalUsersInRoom {
room_id: Box<RoomId>,
},
ActiveLocalUsersInRoom {
room_id: Box<RoomId>,
},
RoomJoinedCount {
room_id: Box<RoomId>,
},
RoomInvitedCount {
room_id: Box<RoomId>,
},
RoomUserOnceJoined {
room_id: Box<RoomId>,
},
RoomMembersInvited {
room_id: Box<RoomId>,
},
GetInviteCount {
room_id: Box<RoomId>,
user_id: Box<UserId>,
},
GetLeftCount {
room_id: Box<RoomId>,
user_id: Box<UserId>,
},
RoomsJoined {
user_id: Box<UserId>,
},
RoomsLeft {
user_id: Box<UserId>,
},
RoomsInvited {
user_id: Box<UserId>,
},
InviteState {
user_id: Box<UserId>,
room_id: Box<RoomId>,
},
}
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// All the getters and iterators from src/database/key_value/globals.rs
pub(super) enum Globals {
DatabaseVersion,
CurrentCount,
LastCheckForUpdatesId,
LoadKeypair,
/// - This returns an empty `Ok(BTreeMap<..>)` when there are no keys found
/// for the server.
SigningKeysFor {
origin: Box<ServerName>,
},
}
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// All the getters and iterators from src/database/key_value/sending.rs
pub(super) enum Sending {
/// - Queries database for all `servercurrentevent_data`
ActiveRequests,
/// - Queries database for `servercurrentevent_data` but for a specific
/// destination
///
/// This command takes only *one* format of these arguments:
///
/// appservice_id
/// server_name
/// user_id AND push_key
///
/// See src/service/sending/mod.rs for the definition of the `Destination`
/// enum
ActiveRequestsFor {
#[arg(short, long)]
appservice_id: Option<String>,
#[arg(short, long)]
server_name: Option<Box<ServerName>>,
#[arg(short, long)]
user_id: Option<Box<UserId>>,
#[arg(short, long)]
push_key: Option<String>,
},
/// - Queries database for `servernameevent_data` which are the queued up
/// requests that will eventually be sent
///
/// This command takes only *one* format of these arguments:
///
/// appservice_id
/// server_name
/// user_id AND push_key
///
/// See src/service/sending/mod.rs for the definition of the `Destination`
/// enum
QueuedRequests {
#[arg(short, long)]
appservice_id: Option<String>,
#[arg(short, long)]
server_name: Option<Box<ServerName>>,
#[arg(short, long)]
user_id: Option<Box<UserId>>,
#[arg(short, long)]
push_key: Option<String>,
},
GetLatestEduCount {
server_name: Box<ServerName>,
},
}
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// All the getters and iterators from src/database/key_value/users.rs
pub(super) enum Users {
Iter,
}
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// Resolver service and caches
pub(super) enum Resolver {
/// Query the destinations cache
DestinationsCache {
server_name: Option<OwnedServerName>,
},
/// Query the overrides cache
OverridesCache {
name: Option<String>,
},
}
/// Processes admin query commands
pub(super) async fn process(command: QueryCommand, _body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
QueryCommand::AccountData(command) => account_data(command).await?,
QueryCommand::Appservice(command) => appservice(command).await?,
QueryCommand::Presence(command) => presence(command).await?,
QueryCommand::RoomAlias(command) => room_alias(command).await?,
QueryCommand::RoomStateCache(command) => room_state_cache(command).await?,
QueryCommand::Globals(command) => globals(command).await?,
QueryCommand::Sending(command) => sending(command).await?,
QueryCommand::Users(command) => users(command).await?,
QueryCommand::Resolver(command) => resolver(command).await?,
})
} }
+19 -37
View File
@@ -1,51 +1,33 @@
use clap::Subcommand; use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use futures::StreamExt;
use ruma::UserId;
use crate::Command; use super::Presence;
use crate::{services, Result};
#[derive(Debug, Subcommand)]
/// All the getters and iterators from src/database/key_value/presence.rs
pub(crate) enum PresenceCommand {
/// - Returns the latest presence event for the given user.
GetPresence {
/// Full user ID
user_id: Box<UserId>,
},
/// - Iterator of the most recent presence updates that happened after the
/// event with id `since`.
PresenceSince {
/// UNIX timestamp since (u64)
since: u64,
},
}
/// All the getters and iterators in key_value/presence.rs /// All the getters and iterators in key_value/presence.rs
pub(super) async fn process(subcommand: PresenceCommand, context: &Command<'_>) -> Result { pub(super) async fn presence(subcommand: Presence) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand { match subcommand {
| PresenceCommand::GetPresence { user_id } => { Presence::GetPresence {
user_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services.presence.get_presence(&user_id).await; let results = services().presence.db.get_presence(&user_id)?;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "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```"
)))
}, },
| PresenceCommand::PresenceSince { since } => { Presence::PresenceSince {
since,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<(_, _, _)> = services let results = services().presence.db.presence_since(since);
.presence let presence_since: Vec<(_, _, _)> = results.collect();
.presence_since(since)
.map(|(user_id, count, bytes)| (user_id.to_owned(), count, bytes.to_vec()))
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "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{presence_since:#?}\n```"
)))
}, },
} }
.await
} }
-29
View File
@@ -1,29 +0,0 @@
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
}
-504
View File
@@ -1,504 +0,0 @@
use std::{borrow::Cow, collections::BTreeMap, ops::Deref, sync::Arc};
use clap::Subcommand;
use conduwuit::{
Err, Result, apply, at, is_zero,
utils::{
stream::{IterStream, ReadyExt, TryIgnore, TryParallelExt},
string::EMPTY,
},
};
use conduwuit_database::Map;
use conduwuit_service::Services;
use futures::{FutureExt, Stream, 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: Option<_> = map.is_none().then(|| {
self.services
.db
.keys()
.map(Deref::deref)
.map(ToOwned::to_owned)
});
let maps: Vec<_> = map
.unwrap_or_default()
.into_iter()
.chain(default_all_maps.into_iter().flatten())
.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 timer = Instant::now();
let count = with_maps_or(map.as_deref(), self.services)
.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 timer = Instant::now();
let result = with_maps_or(map.as_deref(), self.services)
.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 timer = Instant::now();
let result = with_maps_or(map.as_deref(), self.services)
.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 timer = Instant::now();
let result = with_maps_or(map.as_deref(), self.services)
.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 timer = Instant::now();
let result = with_maps_or(map.as_deref(), self.services)
.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:#?}")))
}
fn with_maps_or<'a>(
map: Option<&'a str>,
services: &'a Services,
) -> impl Stream<Item = &'a Arc<Map>> + Send + 'a {
let default_all_maps = map
.is_none()
.then(|| services.db.keys().map(Deref::deref))
.into_iter()
.flatten();
map.into_iter()
.chain(default_all_maps)
.map(|map| services.db.get(map))
.filter_map(Result::ok)
.stream()
}
+75 -62
View File
@@ -1,74 +1,87 @@
use clap::Subcommand; use std::fmt::Write;
use conduwuit::{Result, utils::time};
use futures::StreamExt;
use ruma::{OwnedServerName, events::room::message::RoomMessageEventContent};
use crate::{admin_command, admin_command_dispatch}; use conduit::{utils::time, Result};
use ruma::{events::room::message::RoomMessageEventContent, OwnedServerName};
#[admin_command_dispatch] use super::Resolver;
#[derive(Debug, Subcommand)] use crate::services;
/// Resolver service and caches
pub(crate) enum ResolverCommand { /// All the getters and iterators in key_value/users.rs
/// Query the destinations cache pub(super) async fn resolver(subcommand: Resolver) -> Result<RoomMessageEventContent> {
DestinationsCache { match subcommand {
server_name: Option<OwnedServerName>, Resolver::DestinationsCache {
server_name,
} => destinations_cache(server_name).await,
Resolver::OverridesCache {
name,
} => overrides_cache(name).await,
}
}
async fn destinations_cache(server_name: Option<OwnedServerName>) -> Result<RoomMessageEventContent> {
use service::sending::CachedDest;
let mut out = String::new();
writeln!(out, "| Server Name | Destination | Hostname | Expires |")?;
writeln!(out, "| ----------- | ----------- | -------- | ------- |")?;
let row = |(
name,
&CachedDest {
ref dest,
ref host,
expire,
}, },
)| {
let expire = time::format(expire, "%+");
writeln!(out, "| {name} | {dest} | {host} | {expire} |").expect("wrote line");
};
/// Query the overrides cache let map = services()
OverridesCache { .globals
name: Option<String>, .resolver
.destinations
.read()
.expect("locked");
if let Some(server_name) = server_name.as_ref() {
map.get_key_value(server_name).map(row);
} else {
map.iter().for_each(row);
}
Ok(RoomMessageEventContent::notice_markdown(out))
}
async fn overrides_cache(server_name: Option<String>) -> Result<RoomMessageEventContent> {
use service::sending::CachedOverride;
let mut out = String::new();
writeln!(out, "| Server Name | IP | Port | Expires |")?;
writeln!(out, "| ----------- | --- | ----:| ------- |")?;
let row = |(
name,
&CachedOverride {
ref ips,
port,
expire,
}, },
} )| {
#[admin_command]
async fn destinations_cache(
&self,
server_name: Option<OwnedServerName>,
) -> Result<RoomMessageEventContent> {
use service::resolver::cache::CachedDest;
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, "%+"); let expire = time::format(expire, "%+");
self.write_str(&format!("| {name} | {dest} | {host} | {expire} |\n")) writeln!(out, "| {name} | {ips:?} | {port} | {expire} |").expect("wrote line");
.await?; };
}
Ok(RoomMessageEventContent::notice_plain("")) let map = services()
} .globals
.resolver
.overrides
.read()
.expect("locked");
#[admin_command]
async fn overrides_cache(&self, server_name: Option<String>) -> Result<RoomMessageEventContent> {
use service::resolver::cache::CachedOverride;
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 let Some(server_name) = server_name.as_ref() {
if name != server_name { map.get_key_value(server_name).map(row);
continue; } else {
} map.iter().for_each(row);
} }
let expire = time::format(expire, "%+"); Ok(RoomMessageEventContent::notice_markdown(out))
self.write_str(&format!("| {name} | {ips:?} | {port} | {expire} | {overriding:?} |\n"))
.await?;
}
Ok(RoomMessageEventContent::notice_plain(""))
} }
+25 -48
View File
@@ -1,66 +1,43 @@
use clap::Subcommand; use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::Result;
use futures::StreamExt;
use ruma::{RoomAliasId, RoomId};
use crate::Command; use super::RoomAlias;
use crate::{services, Result};
#[derive(Debug, Subcommand)]
/// All the getters and iterators from src/database/key_value/rooms/alias.rs
pub(crate) enum RoomAliasCommand {
ResolveLocalAlias {
/// Full room alias
alias: Box<RoomAliasId>,
},
/// - Iterator of all our local room aliases for the room ID
LocalAliasesForRoom {
/// Full room ID
room_id: Box<RoomId>,
},
/// - Iterator of all our local aliases in our database with their room IDs
AllLocalAliases,
}
/// All the getters and iterators in src/database/key_value/rooms/alias.rs /// All the getters and iterators in src/database/key_value/rooms/alias.rs
pub(super) async fn process(subcommand: RoomAliasCommand, context: &Command<'_>) -> Result { pub(super) async fn room_alias(subcommand: RoomAlias) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand { match subcommand {
| RoomAliasCommand::ResolveLocalAlias { alias } => { RoomAlias::ResolveLocalAlias {
alias,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services.rooms.alias.resolve_local_alias(&alias).await; let results = services().rooms.alias.resolve_local_alias(&alias);
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "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```"
)))
}, },
| RoomAliasCommand::LocalAliasesForRoom { room_id } => { RoomAlias::LocalAliasesForRoom {
room_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let aliases: Vec<_> = services let results = services().rooms.alias.local_aliases_for_room(&room_id);
.rooms let aliases: Vec<_> = results.collect();
.alias
.local_aliases_for_room(&room_id)
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```") Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```"
)))
}, },
| RoomAliasCommand::AllLocalAliases => { RoomAlias::AllLocalAliases => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let aliases = services let results = services().rooms.alias.all_local_aliases();
.rooms let aliases: Vec<_> = results.collect();
.alias
.all_local_aliases()
.map(|(room_id, alias)| (room_id.to_owned(), alias.to_owned()))
.collect::<Vec<_>>()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```") Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```"
)))
}, },
} }
.await
} }
+108 -185
View File
@@ -1,310 +1,233 @@
use clap::Subcommand; use ruma::events::room::message::RoomMessageEventContent;
use conduwuit::{Error, Result};
use futures::StreamExt;
use ruma::{RoomId, ServerName, UserId, events::room::message::RoomMessageEventContent};
use crate::Command; use super::RoomStateCache;
use crate::{services, Result};
#[derive(Debug, Subcommand)] pub(super) async fn room_state_cache(subcommand: RoomStateCache) -> Result<RoomMessageEventContent> {
pub(crate) enum RoomStateCacheCommand { match subcommand {
ServerInRoom { RoomStateCache::ServerInRoom {
server: Box<ServerName>, server,
room_id: Box<RoomId>, room_id,
}, } => {
RoomServers {
room_id: Box<RoomId>,
},
ServerRooms {
server: Box<ServerName>,
},
RoomMembers {
room_id: Box<RoomId>,
},
LocalUsersInRoom {
room_id: Box<RoomId>,
},
ActiveLocalUsersInRoom {
room_id: Box<RoomId>,
},
RoomJoinedCount {
room_id: Box<RoomId>,
},
RoomInvitedCount {
room_id: Box<RoomId>,
},
RoomUserOnceJoined {
room_id: Box<RoomId>,
},
RoomMembersInvited {
room_id: Box<RoomId>,
},
GetInviteCount {
room_id: Box<RoomId>,
user_id: Box<UserId>,
},
GetLeftCount {
room_id: Box<RoomId>,
user_id: Box<UserId>,
},
RoomsJoined {
user_id: Box<UserId>,
},
RoomsLeft {
user_id: Box<UserId>,
},
RoomsInvited {
user_id: Box<UserId>,
},
InviteState {
user_id: Box<UserId>,
room_id: Box<RoomId>,
},
}
pub(super) async fn process(subcommand: RoomStateCacheCommand, context: &Command<'_>) -> Result {
let services = context.services;
let c = match subcommand {
| RoomStateCacheCommand::ServerInRoom { server, room_id } => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let result = services let result = services()
.rooms .rooms
.state_cache .state_cache
.server_in_room(&server, &room_id) .server_in_room(&server, &room_id);
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::RoomServers { room_id } => { RoomStateCache::RoomServers {
room_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Result<Vec<_>> = services()
.rooms .rooms
.state_cache .state_cache
.room_servers(&room_id) .room_servers(&room_id)
.map(ToOwned::to_owned) .collect();
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::ServerRooms { server } => { RoomStateCache::ServerRooms {
server,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Result<Vec<_>> = services().rooms.state_cache.server_rooms(&server).collect();
.rooms
.state_cache
.server_rooms(&server)
.map(ToOwned::to_owned)
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::RoomMembers { room_id } => { RoomStateCache::RoomMembers {
room_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Result<Vec<_>> = services()
.rooms .rooms
.state_cache .state_cache
.room_members(&room_id) .room_members(&room_id)
.map(ToOwned::to_owned) .collect();
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::LocalUsersInRoom { room_id } => { RoomStateCache::LocalUsersInRoom {
room_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Vec<_> = services()
.rooms .rooms
.state_cache .state_cache
.local_users_in_room(&room_id) .local_users_in_room(&room_id)
.map(ToOwned::to_owned) .collect();
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::ActiveLocalUsersInRoom { room_id } => { RoomStateCache::ActiveLocalUsersInRoom {
room_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Vec<_> = services()
.rooms .rooms
.state_cache .state_cache
.active_local_users_in_room(&room_id) .active_local_users_in_room(&room_id)
.map(ToOwned::to_owned) .collect();
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::RoomJoinedCount { room_id } => { RoomStateCache::RoomJoinedCount {
room_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services.rooms.state_cache.room_joined_count(&room_id).await; let results = services().rooms.state_cache.room_joined_count(&room_id);
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::RoomInvitedCount { room_id } => { RoomStateCache::RoomInvitedCount {
room_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services let results = services().rooms.state_cache.room_invited_count(&room_id);
.rooms
.state_cache
.room_invited_count(&room_id)
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::RoomUserOnceJoined { room_id } => { RoomStateCache::RoomUserOnceJoined {
room_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Result<Vec<_>> = services()
.rooms .rooms
.state_cache .state_cache
.room_useroncejoined(&room_id) .room_useroncejoined(&room_id)
.map(ToOwned::to_owned) .collect();
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::RoomMembersInvited { room_id } => { RoomStateCache::RoomMembersInvited {
room_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Result<Vec<_>> = services()
.rooms .rooms
.state_cache .state_cache
.room_members_invited(&room_id) .room_members_invited(&room_id)
.map(ToOwned::to_owned) .collect();
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::GetInviteCount { room_id, user_id } => { RoomStateCache::GetInviteCount {
room_id,
user_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services let results = services()
.rooms .rooms
.state_cache .state_cache
.get_invite_count(&room_id, &user_id) .get_invite_count(&room_id, &user_id);
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::GetLeftCount { room_id, user_id } => { RoomStateCache::GetLeftCount {
room_id,
user_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results = services let results = services()
.rooms .rooms
.state_cache .state_cache
.get_left_count(&room_id, &user_id) .get_left_count(&room_id, &user_id);
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::RoomsJoined { user_id } => { RoomStateCache::RoomsJoined {
user_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Result<Vec<_>> = services()
.rooms .rooms
.state_cache .state_cache
.rooms_joined(&user_id) .rooms_joined(&user_id)
.map(ToOwned::to_owned) .collect();
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::RoomsInvited { user_id } => { RoomStateCache::RoomsInvited {
user_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Result<Vec<_>> = services()
.rooms .rooms
.state_cache .state_cache
.rooms_invited(&user_id) .rooms_invited(&user_id)
.collect() .collect();
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::RoomsLeft { user_id } => { RoomStateCache::RoomsLeft {
user_id,
} => {
let timer = tokio::time::Instant::now(); let timer = tokio::time::Instant::now();
let results: Vec<_> = services let results: Result<Vec<_>> = services().rooms.state_cache.rooms_left(&user_id).collect();
let query_time = timer.elapsed();
Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCache::InviteState {
user_id,
room_id,
} => {
let timer = tokio::time::Instant::now();
let results = services()
.rooms .rooms
.state_cache .state_cache
.rooms_left(&user_id) .invite_state(&user_id, &room_id);
.collect()
.await;
let query_time = timer.elapsed(); let query_time = timer.elapsed();
Result::<_, Error>::Ok(RoomMessageEventContent::notice_markdown(format!( Ok(RoomMessageEventContent::notice_markdown(format!(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```" "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
))) )))
}, },
| RoomStateCacheCommand::InviteState { user_id, room_id } => { }
let timer = tokio::time::Instant::now();
let results = services
.rooms
.state_cache
.invite_state(&user_id, &room_id)
.await;
let query_time = timer.elapsed();
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
@@ -1,61 +0,0 @@
use clap::Subcommand;
use conduwuit::{PduCount, Result, utils::stream::TryTools};
use futures::TryStreamExt;
use ruma::{OwnedRoomOrAliasId, events::room::message::RoomMessageEventContent};
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:#?}")))
}

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