diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1c091183..51609d5f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,25 +1,15 @@ # Contributing guide This page is about contributing to Continuwuity. The -[development](./development.md) page may be of interest for you as well. +[development](./development.md) and [code style guide](./development/code_style.md) pages may be of interest for you as well. If you would like to work on an [issue][issues] that is not assigned, preferably ask in the Matrix room first at [#continuwuity:continuwuity.org][continuwuity-matrix], and comment on it. -### Linting and Formatting +### Code Style -It is mandatory all your changes satisfy the lints (clippy, rustc, rustdoc, etc) -and your code is formatted via the **nightly** rustfmt (`cargo +nightly fmt`). A lot of the -`rustfmt.toml` features depend on nightly toolchain. It would be ideal if they -weren't nightly-exclusive features, but they currently still are. CI's rustfmt -uses nightly. - -If you need to allow a lint, please make sure it's either obvious as to why -(e.g. clippy saying redundant clone but it's actually required) or it has a -comment saying why. Do not write inefficient code for the sake of satisfying -lints. If a lint is wrong and provides a more inefficient solution or -suggestion, allow the lint and mention that in a comment. +Please review and follow the [code style guide](./development/code_style.md) for formatting, linting, naming conventions, and other code standards. ### Pre-commit Checks @@ -36,6 +26,10 @@ You can run these checks locally by installing [prefligit](https://github.com/j1 ```bash +# Requires UV: https://docs.astral.sh/uv/getting-started/installation/ +# Mac/linux: curl -LsSf https://astral.sh/uv/install.sh | sh +# Windows: powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" + # Install prefligit using cargo-binstall cargo binstall prefligit @@ -48,6 +42,8 @@ prefligit --all-files Alternatively, you can use [pre-commit](https://pre-commit.com/): ```bash +# Requires python + # Install pre-commit pip install pre-commit @@ -58,7 +54,7 @@ pre-commit install pre-commit run --all-files ``` -These same checks are run in CI via the prefligit-checks workflow to ensure consistency. +These same checks are run in CI via the prefligit-checks workflow to ensure consistency. These must pass before the PR is merged. ### Running tests locally @@ -107,37 +103,13 @@ To build the documentation locally: The output of the mdbook generation is in `public/`. You can open the HTML files directly in your browser without needing a web server. -### Inclusivity and Diversity - -All **MUST** code and write with inclusivity and diversity in mind. See the -[following page by Google on writing inclusive code and -documentation](https://developers.google.com/style/inclusive-documentation). - -This **EXPLICITLY** forbids usage of terms like "blacklist"/"whitelist" and -"master"/"slave", [forbids gender-specific words and -phrases](https://developers.google.com/style/pronouns#gender-neutral-pronouns), -forbids ableist language like "sanity-check", "cripple", or "insane", and -forbids culture-specific language (e.g. US-only holidays or cultures). - -No exceptions are allowed. Dependencies that may use these terms are allowed but -[do not replicate the name in your functions or -variables](https://developers.google.com/style/inclusive-documentation#write-around). - -In addition to language, write and code with the user experience in mind. This -is software that intends to be used by everyone, so make it easy and comfortable -for everyone to use. 🏳️‍⚧️ - -### Variable, comment, function, etc standards - -Rust's default style and standards with regards to [function names, variable -names, comments](https://rust-lang.github.io/api-guidelines/naming.html), etc -applies here. ### Commit Messages Continuwuity follows the [Conventional Commits](https://www.conventionalcommits.org/) specification for commit messages. This provides a standardized format that makes the commit history more readable and enables automated tools to generate changelogs. The basic structure is: + ``` [(optional scope)]: @@ -178,11 +150,10 @@ of it, especially when the CI completed successfully and everything so it Before submitting a pull request, please ensure: 1. Your code passes all CI checks (formatting, linting, typo detection, etc.) -2. Your commit messages follow the conventional commits format -3. Tests are added for new functionality -4. Documentation is updated if needed - - +2. Your code follows the [code style guide](./development/code_style.md) +3. Your commit messages follow the conventional commits format +4. Tests are added for new functionality +5. Documentation is updated if needed Direct all PRs/MRs to the `main` branch. diff --git a/arch/conduwuit.service b/arch/conduwuit.service index b66bc1da..f7100179 100644 --- a/arch/conduwuit.service +++ b/arch/conduwuit.service @@ -18,7 +18,7 @@ StandardInput=tty-force StandardOutput=tty StandardError=journal+console -Environment="CONTINUWUITY_LOG_TO_JOURNALD=1" +Environment="CONTINUWUITY_LOG_TO_JOURNALD=true" Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N" TTYReset=yes diff --git a/debian/README.md b/debian/README.md index 4a8e58d2..b605b198 100644 --- a/debian/README.md +++ b/debian/README.md @@ -1,29 +1,23 @@ # Continuwuity for Debian -Information about downloading and deploying the Debian package. This may also be -referenced for other `apt`-based distros such as Ubuntu. +This document provides information about downloading and deploying the Debian package. You can also use this guide for other `apt`-based distributions such as Ubuntu. ### Installation -It is recommended to see the [generic deployment guide](../deploying/generic.md) -for further information if needed as usage of the Debian package is generally -related. +See the [generic deployment guide](../deploying/generic.md) for additional information about using the Debian package. -No `apt` repository is currently offered yet, it is in the works/development. +No `apt` repository is currently available. This feature is in development. ### Configuration -When installed, the example config is placed at `/etc/conduwuit/conduwuit.toml` -as the default config. The config mentions things required to be changed before -starting. +After installation, Continuwuity places the example configuration at `/etc/conduwuit/conduwuit.toml` as the default configuration file. The configuration file indicates which settings you must change before starting the service. -You can tweak more detailed settings by uncommenting and setting the config -options in `/etc/conduwuit/conduwuit.toml`. +You can customize additional settings by uncommenting and modifying the configuration options in `/etc/conduwuit/conduwuit.toml`. ### Running -The package uses the [`conduwuit.service`](../configuration/examples.md#example-systemd-unit-file) systemd unit file to start and stop Continuwuity. The binary is installed at `/usr/sbin/conduwuit`. +The package uses the [`conduwuit.service`](../configuration/examples.md#example-systemd-unit-file) systemd unit file to start and stop Continuwuity. The binary installs at `/usr/sbin/conduwuit`. -This package assumes by default that conduwuit will be placed behind a reverse proxy. The default config options apply (listening on `localhost` and TCP port `6167`). Matrix federation requires a valid domain name and TLS, so you will need to set up TLS certificates and renewal for it to work properly if you intend to federate. +By default, this package assumes that Continuwuity runs behind a reverse proxy. The default configuration options apply (listening on `localhost` and TCP port `6167`). Matrix federation requires a valid domain name and TLS. To federate properly, you must set up TLS certificates and certificate renewal. -Consult various online documentation and guides on setting up a reverse proxy and TLS. Caddy is documented at the [generic deployment guide](../deploying/generic.md#setting-up-the-reverse-proxy) as it's the easiest and most user friendly. +For information about setting up a reverse proxy and TLS, consult online documentation and guides. The [generic deployment guide](../deploying/generic.md#setting-up-the-reverse-proxy) documents Caddy, which is the most user-friendly option for reverse proxy configuration. diff --git a/debian/conduwuit.service b/debian/conduwuit.service index b95804d3..da78f09f 100644 --- a/debian/conduwuit.service +++ b/debian/conduwuit.service @@ -14,7 +14,7 @@ Type=notify Environment="CONTINUWUITY_CONFIG=/etc/conduwuit/conduwuit.toml" -Environment="CONTINUWUITY_LOG_TO_JOURNALD=1" +Environment="CONTINUWUITY_LOG_TO_JOURNALD=true" Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N" ExecStart=/usr/sbin/conduwuit diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index b38009a1..fa097238 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -18,6 +18,7 @@ - [Admin Command Reference](admin_reference.md) - [Development](development.md) - [Contributing](contributing.md) + - [Code Style Guide](development/code_style.md) - [Testing](development/testing.md) - [Hot Reloading ("Live" Development)](development/hot_reload.md) - [Community (and Guidelines)](community.md) diff --git a/docs/deploying/arch-linux.md b/docs/deploying/arch-linux.md index 6e50410d..70067abc 100644 --- a/docs/deploying/arch-linux.md +++ b/docs/deploying/arch-linux.md @@ -1,5 +1,5 @@ # Continuwuity for Arch Linux -Continuwuity is available on the `archlinuxcn` repository and AUR, with the same package name `continuwuity`, which includes latest taggged version. The development version is available on AUR as `continuwuity-git` +Continuwuity is available in the `archlinuxcn` repository and AUR with the same package name `continuwuity`, which includes the latest tagged version. The development version is available on AUR as `continuwuity-git`. -Simply install the `continuwuity` package. Configure the service in `/etc/conduwuit/conduwuit.toml`, then enable/start the continuwuity.service. +Simply install the `continuwuity` package. Configure the service in `/etc/conduwuit/conduwuit.toml`, then enable and start the continuwuity.service. diff --git a/docs/deploying/docker.md b/docs/deploying/docker.md index 051ed89b..a928d081 100644 --- a/docs/deploying/docker.md +++ b/docs/deploying/docker.md @@ -2,7 +2,7 @@ ## Docker -To run Continuwuity with Docker you can either build the image yourself or pull it +To run Continuwuity with Docker, you can either build the image yourself or pull it from a registry. ### Use a registry @@ -26,7 +26,7 @@ to pull it to your machine. ### Run -When you have the image you can simply run it with +When you have the image, you can simply run it with ```bash docker run -d -p 8448:6167 \ @@ -36,7 +36,7 @@ docker run -d -p 8448:6167 \ --name continuwuity $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 optional `continuwuity.toml` config file, the example config can be found @@ -46,15 +46,15 @@ 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 Continuwuity for a short time, you can use the `--rm` -flag, which will clean up everything related to your container after you stop +flag, which cleans up everything related to your container after you stop it. ### 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 suitable for you or your setup, you can also use one of the provided `docker-compose` files. -Depending on your proxy setup, you can use one of the following files; +Depending on your proxy setup, you can use one of the following files: - If you already have a `traefik` instance set up, use [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml) @@ -65,7 +65,7 @@ Depending on your proxy setup, you can use one of the following files; `example.com` placeholders with your own domain - 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 to `docker-compose.yml`, and rename the override file to `docker-compose.override.yml`. Edit the latter with the values you want for your server. @@ -77,18 +77,18 @@ create the `caddy` network before spinning up the containers: 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 to `docker-compose.yml` and spin up the containers! Additional info about deploying Continuwuity can be found [here](generic.md). ### Build -Official Continuwuity images are built using **Docker Buildx** and the Dockerfile found at [`docker/Dockerfile`][dockerfile-path]. This approach uses common Docker tooling and enables multi-platform builds efficiently. +Official Continuwuity images are built using **Docker Buildx** and the Dockerfile found at [`docker/Dockerfile`][dockerfile-path]. This approach uses common Docker tooling and enables efficient multi-platform builds. -The resulting images are broadly compatible with Docker and other container runtimes like Podman or containerd. +The resulting images are widely compatible with Docker and other container runtimes like Podman or containerd. -The images *do not contain a shell*. They contain only the Continuwuity binary, required libraries, TLS certificates and metadata. Please refer to the [`docker/Dockerfile`][dockerfile-path] for the specific details of the image composition. +The images *do not contain a shell*. They contain only the Continuwuity binary, required libraries, TLS certificates, and metadata. Please refer to the [`docker/Dockerfile`][dockerfile-path] for the specific details of the image composition. To build an image locally using Docker Buildx, you can typically run a command like: @@ -109,8 +109,8 @@ Refer to the Docker Buildx documentation for more advanced build options. ### Run -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 +If you have already built the image or want to use one from the registries, you +can start the container and everything else in the compose file in detached mode with: ```bash @@ -121,22 +121,24 @@ docker compose up -d ### Use Traefik as Proxy -As a container user, you probably know about Traefik. It is a easy to use -reverse proxy for making containerized app and services available through the +As a container user, you probably know about Traefik. It is an easy-to-use +reverse proxy for making containerized apps and services available through the web. With the two provided files, [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml) (or [`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)) and [`docker-compose.override.yml`](docker-compose.override.yml), it is equally easy -to deploy and use Continuwuity, with a little caveat. If you already took a look at -the files, then you should have seen the `well-known` service, and that is the -little caveat. Traefik is simply a proxy and loadbalancer and is not able to -serve any kind of content, but for Continuwuity to federate, we need to either -expose ports `443` and `8448` or serve two endpoints `.well-known/matrix/client` +to deploy and use Continuwuity, with a small caveat. If you have already looked at +the files, you should have seen the `well-known` service, which is the +small caveat. Traefik is simply a proxy and load balancer and cannot +serve any kind of content. For Continuwuity to federate, we need to either +expose ports `443` and `8448` or serve two endpoints: `.well-known/matrix/client` 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 serves those two files. +Alternatively, you can use Continuwuity's built-in delegation file capability. Set up the delegation files in the configuration file, and then proxy paths under `/.well-known/matrix` to continuwuity. For example, the label ``traefik.http.routers.continuwuity.rule=(Host(`matrix.ellis.link`) || (Host(`ellis.link`) && PathPrefix(`/.well-known/matrix`)))`` does this for the domain `ellis.link`. + ## Voice communication See the [TURN](../turn.md) page. diff --git a/docs/deploying/freebsd.md b/docs/deploying/freebsd.md index 3764ffa8..c637e0d9 100644 --- a/docs/deploying/freebsd.md +++ b/docs/deploying/freebsd.md @@ -1,5 +1,5 @@ # Continuwuity for FreeBSD -Continuwuity at the moment does not provide FreeBSD builds or have FreeBSD packaging, however Continuwuity does build and work on FreeBSD using the system-provided RocksDB. +Continuwuity currently does not provide FreeBSD builds or FreeBSD packaging. However, Continuwuity does build and work on FreeBSD using the system-provided RocksDB. -Contributions for getting Continuwuity packaged are welcome. +Contributions to get Continuwuity packaged for FreeBSD are welcome. diff --git a/docs/deploying/generic.md b/docs/deploying/generic.md index 9128f346..3f9d1a16 100644 --- a/docs/deploying/generic.md +++ b/docs/deploying/generic.md @@ -13,31 +13,42 @@ You may simply download the binary that fits your machine architecture (x86_64 or aarch64). Run `uname -m` to see what you need. -Prebuilt fully static musl binaries can be downloaded from the latest tagged +You can download prebuilt fully static musl binaries from the latest tagged release [here](https://forgejo.ellis.link/continuwuation/continuwuity/releases/latest) or -`main` CI branch workflow artifact output. These also include Debian/Ubuntu +from the `main` CI branch workflow artifact output. These also include Debian/Ubuntu packages. -These can be curl'd directly from. `ci-bins` are CI workflow binaries by commit +You can download these directly using curl. The `ci-bins` are CI workflow binaries organized by commit hash/revision, and `releases` are tagged releases. Sort by descending last -modified for the latest. +modified date to find 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 the **best** performance: if you are using an `x86_64` CPU made in the last ~15 years, +we recommend using the `-haswell-` optimized binaries. These set +`-march=haswell`, which provides the most compatible and highest performance with +optimized binaries. The database backend, RocksDB, benefits most from this as it +uses 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 Continuwuity as this has the most -guaranteed reproducibiltiy and easiest to get a build environment and output -going. This also allows easy cross-compilation. +Alternatively, you may compile the binary yourself. + +### Building with the Rust toolchain + +If wanting to build using standard Rust toolchains, make sure you install: + +- (On linux) `liburing-dev` on the compiling machine, and `liburing` on the target host +- (On linux) `pkg-config` on the compiling machine to allow finding `liburing` +- A C++ compiler and (on linux) `libclang` for RocksDB + +You can build Continuwuity using `cargo build --release --all-features`. + +### Building with Nix + +If you prefer, you can use Nix (or [Lix](https://lix.systems)) to build Continuwuity. This provides improved reproducibility and makes it easy to set up a build environment and generate output. This approach also allows for 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 @@ -45,17 +56,11 @@ 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 Continuwuity using `cargo build --release --all-features` - ## Adding a Continuwuity user -While Continuwuity can run as any user it is better to use dedicated users for -different services. This also allows you to make sure that the file permissions -are correctly set up. +While Continuwuity can run as any user, it is better to use dedicated users for +different services. This also ensures that the file permissions +are set up correctly. In Debian, you can use this command to create a Continuwuity user: @@ -71,18 +76,18 @@ sudo useradd -r --shell /usr/bin/nologin --no-create-home continuwuity ## Forwarding ports in the firewall or the router -Matrix's default federation port is port 8448, and clients must be using port 443. -If you would like to use only port 443, or a different port, you will need to setup -delegation. Continuwuity has config options for doing delegation, or you can configure -your reverse proxy to manually serve the necessary JSON files to do delegation +Matrix's default federation port is 8448, and clients must use port 443. +If you would like to use only port 443 or a different port, you will need to set up +delegation. Continuwuity has configuration options for delegation, or you can configure +your reverse proxy to manually serve the necessary JSON files for delegation (see the `[global.well_known]` config section). If Continuwuity 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, you need to forward these public ports directly +or indirectly to the port mentioned in the configuration. -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 +Note for NAT users: if you have trouble connecting to your server from inside +your network, check if your router supports "NAT hairpinning" or "NAT loopback". If your router does not support this feature, you need to research doing local @@ -92,19 +97,19 @@ on the network level, consider something like NextDNS or Pi-Hole. ## Setting up a systemd service -Two example systemd units for Continuwuity can be found +You can find two example systemd units for Continuwuity [on the configuration page](../configuration/examples.md#debian-systemd-unit-file). -You may need to change the `ExecStart=` path to where you placed the Continuwuity -binary if it is not `/usr/bin/conduwuit`. +You may need to change the `ExecStart=` path to match where you placed the Continuwuity +binary if it is not in `/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 +If you are using a different `database_path` than the systemd unit's 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` +systemd unit's `ReadWritePaths=`. You can do this by either directly editing +`conduwuit.service` and reloading systemd, or by running `systemctl edit conduwuit.service` and entering the following: ``` @@ -114,8 +119,8 @@ ReadWritePaths=/path/to/custom/database/path ## Creating the Continuwuity configuration file -Now we need to create the Continuwuity's config file in -`/etc/continuwuity/continuwuity.toml`. The example config can be found at +Now you need to create the Continuwuity configuration file in +`/etc/continuwuity/continuwuity.toml`. You can find an example configuration at [conduwuit-example.toml](../configuration/examples.md). **Please take a moment to read the config. You need to change at least the @@ -125,8 +130,8 @@ RocksDB is the only supported database backend. ## Setting the correct file permissions -If you are using a dedicated user for Continuwuity, you will need to allow it to -read the config. To do that you can run this: +If you are using a dedicated user for Continuwuity, you need to allow it to +read the configuration. To do this, run: ```bash sudo chown -R root:root /etc/conduwuit @@ -143,13 +148,13 @@ sudo chmod 700 /var/lib/conduwuit/ ## 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. +We recommend Caddy as a reverse proxy because it is trivial to use and handles TLS certificates, reverse proxy headers, etc. transparently with proper defaults. For other software, please refer to their respective documentation or online guides. ### Caddy After installing Caddy via your preferred method, create `/etc/caddy/conf.d/conduwuit_caddyfile` -and enter this (substitute for your server name). +and enter the following (substitute your actual server name): ```caddyfile your.server.name, your.server.name:8448 { @@ -168,11 +173,11 @@ 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. +As we prefer our users to use Caddy, we do not provide configuration files for other proxies. -You will need to reverse proxy everything under following routes: +You will need to reverse proxy everything under the following routes: - `/_matrix/` - core Matrix C-S and S-S APIs -- `/_conduwuit/` - ad-hoc Continuwuity routes such as `/local_user_count` and +- `/_conduwuit/` and/or `/_continuwuity/` - ad-hoc Continuwuity routes such as `/local_user_count` and `/server_version` You can optionally reverse proxy the following individual routes: @@ -193,16 +198,16 @@ Examples of delegation: 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. +Lighttpd is not supported as it appears to interfere with the `X-Matrix` Authorization +header, making federation non-functional. If you find a workaround, please share it so we can add it to this documentation. -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 Apache, you need to use `nocanon` in your `ProxyPass` directive to prevent httpd from interfering with the `X-Matrix` header (note that Apache is not ideal as a general reverse proxy, so we discourage using it if alternatives are available). -If using Nginx, you need to give Continuwuity the request URI using `$request_uri`, or like so: +If using Nginx, you need to pass the request URI to Continuwuity using `$request_uri`, like this: - `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 +Nginx users need to increase the `client_max_body_size` setting (default is 1M) to match the `max_request_size` defined in conduwuit.toml. ## You're done @@ -222,7 +227,7 @@ sudo systemctl enable conduwuit ## How do I know it works? You can open [a Matrix client](https://matrix.org/ecosystem/clients), enter your -homeserver and try to register. +homeserver address, and try to register. You can also use these commands as a quick health check (replace `your.server.name`). @@ -237,10 +242,10 @@ curl https://your.server.name:8448/_conduwuit/server_version 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 communicate with other homeservers, use the [Matrix Federation Tester](https://federationtester.matrix.org/). 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 configuration and verify +that port 8448 is open and forwarded correctly. # What's next? diff --git a/docs/deploying/kubernetes.md b/docs/deploying/kubernetes.md index 0cbfbbc0..2750e3fb 100644 --- a/docs/deploying/kubernetes.md +++ b/docs/deploying/kubernetes.md @@ -1,9 +1,9 @@ # Continuwuity for Kubernetes Continuwuity doesn't support horizontal scalability or distributed loading -natively, however a community maintained Helm Chart is available here to run +natively. However, a community-maintained Helm Chart is available here to run conduwuit on Kubernetes: -This should be compatible with continuwuity, but you will need to change the image reference. +This should be compatible with Continuwuity, but you will need to change the image reference. -Should changes need to be made, please reach out to the maintainer as this is not maintained/controlled by the Continuwuity maintainers. +If changes need to be made, please reach out to the maintainer, as this is not maintained or controlled by the Continuwuity maintainers. diff --git a/docs/deploying/nixos.md b/docs/deploying/nixos.md index 2fdcbe5c..29517416 100644 --- a/docs/deploying/nixos.md +++ b/docs/deploying/nixos.md @@ -1,75 +1,130 @@ # Continuwuity for NixOS -Continuwuity can be acquired by Nix (or [Lix][lix]) from various places: +NixOS packages Continuwuity as `matrix-continuwuity`. This package includes both the Continuwuity software and a dedicated NixOS module for configuration and deployment. -* The `flake.nix` at the root of the repo -* The `default.nix` at the root of the repo -* From Continuwuity's binary cache +## Installation methods -### NixOS module +You can acquire Continuwuity with Nix (or [Lix][lix]) from these sources: -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 -Continuwuity. +* Directly from Nixpkgs using the official package (`pkgs.matrix-continuwuity`) +* The `flake.nix` at the root of the Continuwuity repo +* The `default.nix` at the root of the Continuwuity repo -### Conduit NixOS Config Module and SQLite +## NixOS module -Beware! The [`services.matrix-conduit`][module] module defaults to SQLite as a database backend. -Continuwuity dropped SQLite support in favor of exclusively supporting the much faster RocksDB. -Make sure that you are using the RocksDB backend before migrating! +Continuwuity now has an official NixOS module that simplifies configuration and deployment. The module is available in Nixpkgs as `services.matrix-continuwuity` from NixOS 25.05. -There is a [tool to migrate a Conduit SQLite database to -RocksDB](https://github.com/ShadowJonathan/conduit_toolbox/). +Here's a basic example of how to use the module: -If you want to run the latest code, you should get Continuwuity from the `flake.nix` -or `default.nix` and set [`services.matrix-conduit.package`][package] -appropriately to use Continuwuity instead of Conduit. +```nix +{ config, pkgs, ... }: + +{ + services.matrix-continuwuity = { + enable = true; + settings = { + global = { + server_name = "example.com"; + # Listening on localhost by default + # address and port are handled automatically + allow_registration = false; + allow_encryption = true; + allow_federation = true; + trusted_servers = [ "matrix.org" ]; + }; + }; + }; +} +``` + +### Available options + +The NixOS module provides these configuration options: + +- `enable`: Enable the Continuwuity service +- `user`: The user to run Continuwuity as (defaults to "continuwuity") +- `group`: The group to run Continuwuity as (defaults to "continuwuity") +- `extraEnvironment`: Extra environment variables to pass to the Continuwuity server +- `package`: The Continuwuity package to use +- `settings`: The Continuwuity configuration (in TOML format) + +Use the `settings` option to configure Continuwuity itself. See the [example configuration file](../configuration/examples.md#example-configuration) for all available options. ### UNIX sockets -Due to the lack of a Continuwuity 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. +The NixOS module natively supports UNIX sockets through the `global.unix_socket_path` option. When using UNIX sockets, set `global.address` to `null`: ```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 { } - ); +services.matrix-continuwuity = { + enable = true; + settings = { + global = { + server_name = "example.com"; + address = null; # Must be null when using unix_socket_path + unix_socket_path = "/run/continuwuity/continuwuity.sock"; + unix_socket_perms = 660; # Default permissions for the socket + # ... + }; + }; }; - ``` -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: +The module automatically sets the correct `RestrictAddressFamilies` in the systemd service configuration to allow access to UNIX sockets. -```nix -systemd.services.conduit.serviceConfig.RestrictAddressFamilies = [ "AF_UNIX" ]; -``` +### RocksDB database -Even though those workarounds are feasible a Continuwuity NixOS configuration module, developed and -published by the community, would be appreciated. +Continuwuity exclusively uses RocksDB as its database backend. The system configures the database path automatically to `/var/lib/continuwuity/` and you cannot change it due to the service's reliance on systemd's StateDir. + +If you're migrating from Conduit with SQLite, use this [tool to migrate a Conduit SQLite database to RocksDB](https://github.com/ShadowJonathan/conduit_toolbox/). ### jemalloc and hardened profile -Continuwuity 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 Continuwuity, or -disable jemalloc like so: +Continuwuity uses jemalloc by default. This may interfere with the [`hardened.nix` profile][hardened.nix] because it uses `scudo` by default. Either disable/hide `scudo` from Continuwuity or disable jemalloc like this: ```nix -let - conduwuit = pkgs.unstable.conduwuit.override { - enableJemalloc = false; - }; -in +services.matrix-continuwuity = { + enable = true; + package = pkgs.matrix-continuwuity.override { + enableJemalloc = false; + }; + # ... +}; +``` + +## Upgrading from Conduit + +If you previously used Conduit with the `services.matrix-conduit` module: + +1. Ensure your Conduit uses the RocksDB backend, or migrate from SQLite using the [migration tool](https://github.com/ShadowJonathan/conduit_toolbox/) +2. Switch to the new module by changing `services.matrix-conduit` to `services.matrix-continuwuity` in your configuration +3. Update any custom configuration to match the new module's structure + +## Reverse proxy configuration + +You'll need to set up a reverse proxy (like nginx or caddy) to expose Continuwuity to the internet. Configure your reverse proxy to forward requests to `/_matrix` on port 443 and 8448 to your Continuwuity instance. + +Here's an example nginx configuration: + +```nginx +server { + listen 443 ssl; + listen [::]:443 ssl; + listen 8448 ssl; + listen [::]:8448 ssl; + + server_name example.com; + + # SSL configuration here... + + location /_matrix/ { + proxy_pass http://127.0.0.1:6167$request_uri; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} ``` [lix]: https://lix.systems/ -[module]: https://search.nixos.org/options?channel=unstable&query=services.matrix-conduit -[package]: https://search.nixos.org/options?channel=unstable&query=services.matrix-conduit.package -[hardened.nix]: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix#L22 -[systemd-unit]: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/matrix/conduit.nix#L132 +[hardened.nix]: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix diff --git a/docs/development.md b/docs/development.md index 68b963c8..dd587da4 100644 --- a/docs/development.md +++ b/docs/development.md @@ -2,7 +2,7 @@ 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 -[contributor's guide](./contributing.md). +[contributor's guide](./contributing.md) and [code style guide](./development/code_style.md). ## Continuwuity project layout diff --git a/docs/development/code_style.md b/docs/development/code_style.md new file mode 100644 index 00000000..7fa9d6bb --- /dev/null +++ b/docs/development/code_style.md @@ -0,0 +1,331 @@ +# Code Style Guide + +This guide outlines the coding standards and best practices for Continuwuity development. These guidelines help avoid bugs and maintain code consistency, readability, and quality across the project. + +These guidelines apply to new code on a best-effort basis. When modifying existing code, follow existing patterns in the immediate area you're changing and then gradually improve code style when making substantial changes. + +## General Principles + +- **Clarity over cleverness**: Write code that is easy to understand and maintain +- **Consistency**: Pragmatically follow existing patterns in the codebase, rather than adding new dependencies. +- **Safety**: Prefer safe, explicit code over unsafe code with implicit requirements +- **Performance**: Consider performance implications, but not at the expense of correctness or maintainability + +## Formatting and Linting + +All code must satisfy lints (clippy, rustc, rustdoc, etc) and be formatted using **nightly** rustfmt (`cargo +nightly fmt`). Many of the `rustfmt.toml` features depend on the nightly toolchain. + +If you need to allow a lint, ensure it's either obvious why (e.g. clippy saying redundant clone but it's actually required) or add a comment explaining the reason. Do not write inefficient code just to satisfy lints. If a lint is wrong and provides a less efficient solution, allow the lint and mention that in a comment. + +If making large formatting changes across unrelated files, create a separate commit so it can be added to the `.git-blame-ignore-revs` file. + +## Rust-Specific Guidelines + +### Naming Conventions + +Follow standard Rust naming conventions as outlined in the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/naming.html): + +- Use `snake_case` for functions, variables, and modules +- Use `PascalCase` for types, traits, and enum variants +- Use `SCREAMING_SNAKE_CASE` for constants and statics +- Use descriptive names that clearly indicate purpose + +```rs +// Good +fn process_user_request(user_id: &UserId) -> Result { ... } + +const MAX_RETRY_ATTEMPTS: usize = 3; + +struct UserSession { + session_id: String, + created_at: SystemTime, +} + +// Avoid +fn proc_reqw(id: &str) -> Result { ... } +``` + +### Error Handling + +- Use `Result` for operations that can fail +- Prefer specific error types over generic ones +- Use `?` operator for error propagation +- Provide meaningful error messages +- If needed, create or use an error enum. + +```rs +// Good +fn parse_server_name(input: &str) -> Result { + ServerName::parse(input) + .map_err(|_| InvalidServerNameError::new(input)) +} + +// Avoid +fn parse_server_name(input: &str) -> Result> { + Ok(ServerName::parse(input).unwrap()) +} +``` + +### Option Handling + +- Prefer explicit `Option` handling over unwrapping +- Use combinators like `map`, `and_then`, `unwrap_or_else` when appropriate + +```rs +// Good +let display_name = user.display_name + .as_ref() + .map(|name| name.trim()) + .filter(|name| !name.is_empty()) + .unwrap_or(&user.localpart); + +// Avoid +let display_name = if user.display_name.is_some() { + user.display_name.as_ref().unwrap() +} else { + &user.localpart +}; +``` + +## Logging Guidelines + +### Structured Logging + +**Always use structured logging instead of string interpolation.** This improves log parsing, filtering, and observability. + +```rs +// Good - structured parameters +debug!( + room_id = %room_id, + user_id = %user_id, + event_type = ?event.event_type(), + "Processing room event" +); + +info!( + server_name = %server_name, + response_time_ms = response_time.as_millis(), + "Federation request completed successfully" +); + +// Avoid - string interpolation +debug!("Processing room event for {room_id} from {user_id}"); +info!("Federation request to {server_name} took {response_time:?}"); +``` + +### Log Levels + +Use appropriate log levels: + +- `error!`: Unrecoverable errors that affect functionality +- `warn!`: Potentially problematic situations that don't stop execution +- `info!`: General information about application flow +- `debug!`: Detailed information for debugging +- `trace!`: Very detailed information, typically only useful during development + +Keep in mind the frequency that the log will be reached, and the relevancy to a server operator. + +```rs +// Good +error!( + error = %err, + room_id = %room_id, + "Failed to send event to room" +); + +warn!( + server_name = %server_name, + attempt = retry_count, + "Federation request failed, retrying" +); + +info!( + user_id = %user_id, + "User registered successfully" +); + +debug!( + event_id = %event_id, + auth_events = ?auth_event_ids, + "Validating event authorization" +); +``` + +### Sensitive Information + +Never log sensitive information such as: +- Access tokens +- Passwords +- Private keys +- Personal user data (unless specifically needed for debugging) + +```rs +// Good +debug!( + user_id = %user_id, + session_id = %session_id, + "Processing authenticated request" +); + +// Avoid +debug!( + user_id = %user_id, + access_token = %access_token, + "Processing authenticated request" +); +``` + +## Lock Management + +### Explicit Lock Scopes + +**Always use closure guards instead of implicitly dropped guards.** This makes lock scopes explicit and helps prevent deadlocks. + +Use the `WithLock` trait from `core::utils::with_lock`: + +```rs +use conduwuit::utils::with_lock::WithLock; + +// Good - explicit closure guard +shared_data.with_lock(|data| { + data.counter += 1; + data.last_updated = SystemTime::now(); + // Lock is explicitly released here +}); + +// Avoid - implicit guard +{ + let mut data = shared_data.lock().unwrap(); + data.counter += 1; + data.last_updated = SystemTime::now(); + // Lock released when guard goes out of scope - less explicit +} +``` + +For async contexts, use the async variant: + +```rs +use conduwuit::utils::with_lock::WithLockAsync; + +// Good - async closure guard +async_shared_data.with_lock(|data| { + data.process_async_update(); +}).await; +``` + +### Lock Ordering + +When acquiring multiple locks, always acquire them in a consistent order to prevent deadlocks: + +```rs +// Good - consistent ordering (e.g., by memory address or logical hierarchy) +let locks = [&lock_a, &lock_b, &lock_c]; +locks.sort_by_key(|lock| lock as *const _ as usize); + +for lock in locks { + lock.with_lock(|data| { + // Process data + }); +} + +// Avoid - inconsistent ordering that can cause deadlocks +lock_b.with_lock(|data_b| { + lock_a.with_lock(|data_a| { + // Deadlock risk if another thread acquires in A->B order + }); +}); +``` + +## Documentation + +### Code Comments + +- Reference related documentation or parts of the specification +- When a task has multiple ways of being acheved, explain your reasoning for your decision +- Update comments when code changes + +```rs +/// Processes a federation request with automatic retries and backoff. +/// +/// Implements exponential backoff to handle temporary +/// network issues and server overload gracefully. +pub async fn send_federation_request( + destination: &ServerName, + request: FederationRequest, +) -> Result { + // Retry with exponential backoff because federation can be flaky + // due to network issues or temporary server overload + let mut retry_delay = Duration::from_millis(100); + + for attempt in 1..=MAX_RETRIES { + match try_send_request(destination, &request).await { + Ok(response) => return Ok(response), + Err(err) if err.is_retriable() && attempt < MAX_RETRIES => { + warn!( + destination = %destination, + attempt = attempt, + error = %err, + retry_delay_ms = retry_delay.as_millis(), + "Federation request failed, retrying" + ); + + tokio::time::sleep(retry_delay).await; + retry_delay *= 2; // Exponential backoff + } + Err(err) => return Err(err), + } + } + + unreachable!("Loop should have returned or failed by now") +} +``` + +### Async Patterns + +- Use `async`/`await` appropriately +- Avoid blocking operations in async contexts +- Consider using `tokio::task::spawn_blocking` for CPU-intensive work + +```rs +// Good - non-blocking async operation +pub async fn fetch_user_profile( + &self, + user_id: &UserId, +) -> Result { + let profile = self.db + .get_user_profile(user_id) + .await?; + + Ok(profile) +} + +// Good - CPU-intensive work moved to blocking thread +pub async fn generate_thumbnail( + &self, + image_data: Vec, +) -> Result, Error> { + tokio::task::spawn_blocking(move || { + image::generate_thumbnail(image_data) + }) + .await + .map_err(|_| Error::TaskJoinError)? +} +``` + +## Inclusivity and Diversity Guidelines + +All code and documentation must be written with inclusivity and diversity in mind. This ensures our software is welcoming and accessible to all users and contributors. Follow the [Google guide on writing inclusive code and documentation](https://developers.google.com/style/inclusive-documentation) for comprehensive guidance. + +The following types of language are explicitly forbidden in all code, comments, documentation, and commit messages: + +**Ableist language:** Avoid terms like "sanity check", "crazy", "insane", "cripple", or "blind to". Use alternatives like "validation", "unexpected", "disable", or "unaware of". + +**Socially-charged technical terms:** Replace overly divisive terminology with neutral alternatives: +- "whitelist/blacklist" → "allowlist/denylist" or "permitted/blocked" +- "master/slave" → "primary/replica", "controller/worker", or "parent/child" + +When working with external dependencies that use non-inclusive terminology, avoid propagating them in your own APIs and variable names. + +Use diverse examples in documentation that avoid culturally-specific references, assumptions about user demographics, or unnecessarily gendered language. Design with accessibility and inclusivity in mind by providing clear error messages and considering diverse user needs. + +This software is intended to be used by everyone regardless of background, identity, or ability. Write code and documentation that reflects this commitment to inclusivity. diff --git a/docs/turn.md b/docs/turn.md index 5dba823c..cccb1cb3 100644 --- a/docs/turn.md +++ b/docs/turn.md @@ -68,3 +68,27 @@ documentation](https://github.com/coturn/coturn/blob/master/docker/coturn/README For security recommendations see Synapse's [Coturn documentation](https://element-hq.github.io/synapse/latest/turn-howto.html). + +### Testing + +To make sure turn credentials are being correctly served to clients, you can manually make a HTTP request to the turnServer endpoint. + +`curl "https:///_matrix/client/r0/voip/turnServer" -H 'Authorization: Bearer ' | jq` + +You should get a response like this: + +```json +{ + "username": "1752792167:@jade:example.com", + "password": "KjlDlawdPbU9mvP4bhdV/2c/h65=", + "uris": [ + "turns:coturn.example.com?transport=udp", + "turns:coturn.example.com?transport=tcp", + "turn:coturn.example.com?transport=udp", + "turn:coturn.example.com?transport=tcp" + ], + "ttl": 86400 +} +``` + +You can test these credentials work using [Trickle ICE](https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/) diff --git a/src/api/router.rs b/src/api/router.rs index d1b05a91..8072fa5b 100644 --- a/src/api/router.rs +++ b/src/api/router.rs @@ -187,6 +187,7 @@ pub fn build(router: Router, server: &Server) -> Router { .ruma_route(&client::well_known_support) .ruma_route(&client::well_known_client) .route("/_conduwuit/server_version", get(client::conduwuit_server_version)) + .route("/_continuwuity/server_version", get(client::conduwuit_server_version)) .ruma_route(&client::room_initial_sync_route) .route("/client/server.json", get(client::syncv3_client_server_json)); @@ -226,13 +227,15 @@ pub fn build(router: Router, server: &Server) -> Router { .ruma_route(&server::well_known_server) .ruma_route(&server::get_content_route) .ruma_route(&server::get_content_thumbnail_route) - .route("/_conduwuit/local_user_count", get(client::conduwuit_local_user_count)); + .route("/_conduwuit/local_user_count", get(client::conduwuit_local_user_count)) + .route("/_continuwuity/local_user_count", get(client::conduwuit_local_user_count)); } else { router = router .route("/_matrix/federation/*path", any(federation_disabled)) .route("/.well-known/matrix/server", any(federation_disabled)) .route("/_matrix/key/*path", any(federation_disabled)) - .route("/_conduwuit/local_user_count", any(federation_disabled)); + .route("/_conduwuit/local_user_count", any(federation_disabled)) + .route("/_continuwuity/local_user_count", any(federation_disabled)); } if config.allow_legacy_media { diff --git a/src/core/utils/mod.rs b/src/core/utils/mod.rs index 54404e4c..329e2ea2 100644 --- a/src/core/utils/mod.rs +++ b/src/core/utils/mod.rs @@ -19,6 +19,7 @@ pub mod sys; #[cfg(test)] mod tests; pub mod time; +pub mod with_lock; pub use ::conduwuit_macros::implement; pub use ::ctor::{ctor, dtor}; diff --git a/src/core/utils/with_lock.rs b/src/core/utils/with_lock.rs new file mode 100644 index 00000000..76f014d1 --- /dev/null +++ b/src/core/utils/with_lock.rs @@ -0,0 +1,65 @@ +//! Traits for explicitly scoping the lifetime of locks. + +use std::sync::{Arc, Mutex}; + +pub trait WithLock { + /// Acquires a lock and executes the given closure with the locked data. + fn with_lock(&self, f: F) + where + F: FnMut(&mut T); +} + +impl WithLock for Mutex { + fn with_lock(&self, mut f: F) + where + F: FnMut(&mut T), + { + // The locking and unlocking logic is hidden inside this function. + let mut data_guard = self.lock().unwrap(); + f(&mut data_guard); + // Lock is released here when `data_guard` goes out of scope. + } +} + +impl WithLock for Arc> { + fn with_lock(&self, mut f: F) + where + F: FnMut(&mut T), + { + // The locking and unlocking logic is hidden inside this function. + let mut data_guard = self.lock().unwrap(); + f(&mut data_guard); + // Lock is released here when `data_guard` goes out of scope. + } +} + +pub trait WithLockAsync { + /// Acquires a lock and executes the given closure with the locked data. + fn with_lock(&self, f: F) -> impl Future + where + F: FnMut(&mut T); +} + +impl WithLockAsync for futures::lock::Mutex { + async fn with_lock(&self, mut f: F) + where + F: FnMut(&mut T), + { + // The locking and unlocking logic is hidden inside this function. + let mut data_guard = self.lock().await; + f(&mut data_guard); + // Lock is released here when `data_guard` goes out of scope. + } +} + +impl WithLockAsync for Arc> { + async fn with_lock(&self, mut f: F) + where + F: FnMut(&mut T), + { + // The locking and unlocking logic is hidden inside this function. + let mut data_guard = self.lock().await; + f(&mut data_guard); + // Lock is released here when `data_guard` goes out of scope. + } +}