mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5bae8b4f6c |
@@ -1,2 +0,0 @@
|
|||||||
[alias]
|
|
||||||
xtask = "run --package xtask --"
|
|
||||||
@@ -19,20 +19,11 @@ outputs:
|
|||||||
rustc_version:
|
rustc_version:
|
||||||
description: The rustc version installed
|
description: The rustc version installed
|
||||||
value: ${{ steps.rustc-version.outputs.version }}
|
value: ${{ steps.rustc-version.outputs.version }}
|
||||||
rustup_version:
|
|
||||||
description: The rustup version installed
|
|
||||||
value: ${{ steps.rustup-version.outputs.version }}
|
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
- name: Check if rustup is already installed
|
|
||||||
shell: bash
|
|
||||||
id: rustup-version
|
|
||||||
run: |
|
|
||||||
echo "version=$(rustup --version)" >> $GITHUB_OUTPUT
|
|
||||||
- name: Cache rustup toolchains
|
- name: Cache rustup toolchains
|
||||||
if: steps.rustup-version.outputs.version == ''
|
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@@ -42,7 +33,6 @@ runs:
|
|||||||
# Requires repo to be cloned if toolchain is not specified
|
# Requires repo to be cloned if toolchain is not specified
|
||||||
key: ${{ runner.os }}-rustup-${{ inputs.toolchain || hashFiles('**/rust-toolchain.toml') }}
|
key: ${{ runner.os }}-rustup-${{ inputs.toolchain || hashFiles('**/rust-toolchain.toml') }}
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
if: steps.rustup-version.outputs.version == ''
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if ! command -v rustup &> /dev/null ; then
|
if ! command -v rustup &> /dev/null ; then
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ jobs:
|
|||||||
|
|
||||||
build-image:
|
build-image:
|
||||||
runs-on: dind
|
runs-on: dind
|
||||||
|
container: ghcr.io/catthehacker/ubuntu:act-latest
|
||||||
needs: define-variables
|
needs: define-variables
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -180,14 +181,14 @@ jobs:
|
|||||||
file: "docker/Dockerfile"
|
file: "docker/Dockerfile"
|
||||||
build-args: |
|
build-args: |
|
||||||
GIT_COMMIT_HASH=${{ github.sha }})
|
GIT_COMMIT_HASH=${{ github.sha }})
|
||||||
GIT_COMMIT_HASH_SHORT=${{ env.COMMIT_SHORT_SHA }}
|
GIT_COMMIT_HASH_SHORT=${{ env.COMMIT_SHORT_SHA }})
|
||||||
GIT_REMOTE_URL=${{github.event.repository.html_url }}
|
GIT_REMOTE_URL=${{github.event.repository.html_url }}
|
||||||
GIT_REMOTE_COMMIT_URL=${{github.event.head_commit.url }}
|
GIT_REMOTE_COMMIT_URL=${{github.event.head_commit.url }}
|
||||||
platforms: ${{ matrix.platform }}
|
platforms: ${{ matrix.platform }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
annotations: ${{ steps.meta.outputs.annotations }}
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
# cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
sbom: true
|
sbom: true
|
||||||
outputs: type=image,"name=${{ needs.define-variables.outputs.images_list }}",push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,"name=${{ needs.define-variables.outputs.images_list }}",push-by-digest=true,name-canonical=true,push=true
|
||||||
env:
|
env:
|
||||||
@@ -210,6 +211,7 @@ jobs:
|
|||||||
|
|
||||||
merge:
|
merge:
|
||||||
runs-on: dind
|
runs-on: dind
|
||||||
|
container: ghcr.io/catthehacker/ubuntu:act-latest
|
||||||
needs: [define-variables, build-image]
|
needs: [define-variables, build-image]
|
||||||
steps:
|
steps:
|
||||||
- name: Download digests
|
- name: Download digests
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ jobs:
|
|||||||
-D warnings
|
-D warnings
|
||||||
|
|
||||||
- name: Show sccache stats
|
- name: Show sccache stats
|
||||||
if: always()
|
|
||||||
run: sccache --show-stats
|
run: sccache --show-stats
|
||||||
|
|
||||||
cargo-test:
|
cargo-test:
|
||||||
@@ -138,5 +137,4 @@ jobs:
|
|||||||
--no-fail-fast
|
--no-fail-fast
|
||||||
|
|
||||||
- name: Show sccache stats
|
- name: Show sccache stats
|
||||||
if: always()
|
|
||||||
run: sccache --show-stats
|
run: sccache --show-stats
|
||||||
|
|||||||
Generated
+278
-333
File diff suppressed because it is too large
Load Diff
+2
-9
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["src/*", "xtask/*"]
|
members = ["src/*"]
|
||||||
default-members = ["src/*"]
|
default-members = ["src/*"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
@@ -213,8 +213,6 @@ default-features = false
|
|||||||
version = "0.3.19"
|
version = "0.3.19"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["env-filter", "std", "tracing", "tracing-log", "ansi", "fmt"]
|
features = ["env-filter", "std", "tracing", "tracing-log", "ansi", "fmt"]
|
||||||
[workspace.dependencies.tracing-journald]
|
|
||||||
version = "0.3.1"
|
|
||||||
[workspace.dependencies.tracing-core]
|
[workspace.dependencies.tracing-core]
|
||||||
version = "0.1.33"
|
version = "0.1.33"
|
||||||
default-features = false
|
default-features = false
|
||||||
@@ -383,7 +381,7 @@ features = [
|
|||||||
"unstable-msc4121",
|
"unstable-msc4121",
|
||||||
"unstable-msc4125",
|
"unstable-msc4125",
|
||||||
"unstable-msc4186",
|
"unstable-msc4186",
|
||||||
"unstable-msc4203", # sending to-device events to appservices
|
"unstable-msc4203", # sending to-device events to appservices
|
||||||
"unstable-msc4210", # remove legacy mentions
|
"unstable-msc4210", # remove legacy mentions
|
||||||
"unstable-extensible-events",
|
"unstable-extensible-events",
|
||||||
"unstable-pdu",
|
"unstable-pdu",
|
||||||
@@ -639,11 +637,6 @@ package = "conduwuit_build_metadata"
|
|||||||
path = "src/build_metadata"
|
path = "src/build_metadata"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
|
|
||||||
[workspace.dependencies.conduwuit]
|
|
||||||
package = "conduwuit"
|
|
||||||
path = "src/main"
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
#
|
||||||
# Release profiles
|
# Release profiles
|
||||||
|
|||||||
-63
@@ -1,63 +0,0 @@
|
|||||||
# Security Policy for Continuwuity
|
|
||||||
|
|
||||||
This document outlines the security policy for Continuwuity. Our goal is to maintain a secure platform for all users, and we take security matters seriously.
|
|
||||||
|
|
||||||
## Supported Versions
|
|
||||||
|
|
||||||
We provide security updates for the following versions of Continuwuity:
|
|
||||||
|
|
||||||
| Version | Supported |
|
|
||||||
| -------------- |:----------------:|
|
|
||||||
| Latest release | ✅ |
|
|
||||||
| Main branch | ✅ |
|
|
||||||
| Older releases | ❌ |
|
|
||||||
|
|
||||||
We may backport fixes to the previous release at our discretion, but we don't guarantee this.
|
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
|
||||||
|
|
||||||
### Responsible Disclosure
|
|
||||||
|
|
||||||
We appreciate the efforts of security researchers and the community in identifying and reporting vulnerabilities. To ensure that potential vulnerabilities are addressed properly, please follow these guidelines:
|
|
||||||
|
|
||||||
1. **Contact members of the team directly** over E2EE private message.
|
|
||||||
- [@jade:ellis.link](https://matrix.to/#/@jade:ellis.link)
|
|
||||||
- [@nex:nexy7574.co.uk](https://matrix.to/#/@nex:nexy7574.co.uk) <!-- ? -->
|
|
||||||
2. **Email the security team** at [security@continuwuity.org](mailto:security@continuwuity.org). This is not E2EE, so don't include sensitive details.
|
|
||||||
3. **Do not disclose the vulnerability publicly** until it has been addressed
|
|
||||||
4. **Provide detailed information** about the vulnerability, including:
|
|
||||||
- A clear description of the issue
|
|
||||||
- Steps to reproduce
|
|
||||||
- Potential impact
|
|
||||||
- Any possible mitigations
|
|
||||||
- Version(s) affected, including specific commits if possible
|
|
||||||
|
|
||||||
If you have any doubts about a potential security vulnerability, contact us via private channels first! We'd prefer that you bother us, instead of having a vulnerability disclosed without a fix.
|
|
||||||
|
|
||||||
### What to Expect
|
|
||||||
|
|
||||||
When you report a security vulnerability:
|
|
||||||
|
|
||||||
1. **Acknowledgment**: We will acknowledge receipt of your report.
|
|
||||||
2. **Assessment**: We will assess the vulnerability and determine its impact on our users
|
|
||||||
3. **Updates**: We will provide updates on our progress in addressing the vulnerability, and may request you help test mitigations
|
|
||||||
4. **Resolution**: Once resolved, we will notify you and discuss coordinated disclosure
|
|
||||||
5. **Credit**: We will recognize your contribution (unless you prefer to remain anonymous)
|
|
||||||
|
|
||||||
## Security Update Process
|
|
||||||
|
|
||||||
When security vulnerabilities are identified:
|
|
||||||
|
|
||||||
1. We will develop and test fixes in a private fork
|
|
||||||
2. Security updates will be released as soon as possible
|
|
||||||
3. Release notes will include information about the vulnerabilities, avoiding details that could facilitate exploitation where possible
|
|
||||||
4. Critical security updates may be backported to the previous stable release
|
|
||||||
|
|
||||||
## Additional Resources
|
|
||||||
|
|
||||||
- [Matrix Security Disclosure Policy](https://matrix.org/security-disclosure-policy/)
|
|
||||||
- [Continuwuity Documentation](https://continuwuity.org/introduction)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
This security policy was last updated on May 25, 2025.
|
|
||||||
@@ -16,10 +16,6 @@ DeviceAllow=char-tty
|
|||||||
StandardInput=tty-force
|
StandardInput=tty-force
|
||||||
StandardOutput=tty
|
StandardOutput=tty
|
||||||
StandardError=journal+console
|
StandardError=journal+console
|
||||||
|
|
||||||
Environment="CONTINUWUITY_LOG_TO_JOURNALD=1"
|
|
||||||
Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N"
|
|
||||||
|
|
||||||
TTYReset=yes
|
TTYReset=yes
|
||||||
# uncomment to allow buffer to be cleared every restart
|
# uncomment to allow buffer to be cleared every restart
|
||||||
TTYVTDisallocate=no
|
TTYVTDisallocate=no
|
||||||
|
|||||||
+5
-30
@@ -660,21 +660,6 @@
|
|||||||
#
|
#
|
||||||
#log_thread_ids = false
|
#log_thread_ids = false
|
||||||
|
|
||||||
# Enable journald logging on Unix platforms
|
|
||||||
#
|
|
||||||
# When enabled, log output will be sent to the systemd journal
|
|
||||||
# This is only supported on Unix platforms
|
|
||||||
#
|
|
||||||
#log_to_journald = false
|
|
||||||
|
|
||||||
# The syslog identifier to use with journald logging
|
|
||||||
#
|
|
||||||
# Only used when journald logging is enabled
|
|
||||||
#
|
|
||||||
# Defaults to the binary name
|
|
||||||
#
|
|
||||||
#journald_identifier =
|
|
||||||
|
|
||||||
# OpenID token expiration/TTL in seconds.
|
# OpenID token expiration/TTL in seconds.
|
||||||
#
|
#
|
||||||
# These are the OpenID tokens that are primarily used for Matrix account
|
# These are the OpenID tokens that are primarily used for Matrix account
|
||||||
@@ -1656,29 +1641,19 @@
|
|||||||
#
|
#
|
||||||
#server =
|
#server =
|
||||||
|
|
||||||
# URL to a support page for the server, which will be served as part of
|
# This item is undocumented. Please contribute documentation for it.
|
||||||
# the MSC1929 server support endpoint at /.well-known/matrix/support.
|
|
||||||
# Will be included alongside any contact information
|
|
||||||
#
|
#
|
||||||
#support_page =
|
#support_page =
|
||||||
|
|
||||||
# Role string for server support contacts, to be served as part of the
|
# This item is undocumented. Please contribute documentation for it.
|
||||||
# MSC1929 server support endpoint at /.well-known/matrix/support.
|
|
||||||
#
|
#
|
||||||
#support_role = "m.role.admin"
|
#support_role =
|
||||||
|
|
||||||
# Email address for server support contacts, to be served as part of the
|
# This item is undocumented. Please contribute documentation for it.
|
||||||
# MSC1929 server support endpoint.
|
|
||||||
# This will be used along with support_mxid if specified.
|
|
||||||
#
|
#
|
||||||
#support_email =
|
#support_email =
|
||||||
|
|
||||||
# Matrix ID for server support contacts, to be served as part of the
|
# This item is undocumented. Please contribute documentation for it.
|
||||||
# MSC1929 server support endpoint.
|
|
||||||
# This will be used along with support_email if specified.
|
|
||||||
#
|
|
||||||
# If no email or mxid is specified, all of the server's admins will be
|
|
||||||
# listed.
|
|
||||||
#
|
#
|
||||||
#support_mxid =
|
#support_mxid =
|
||||||
|
|
||||||
|
|||||||
Vendored
-3
@@ -14,9 +14,6 @@ Type=notify
|
|||||||
|
|
||||||
Environment="CONTINUWUITY_CONFIG=/etc/conduwuit/conduwuit.toml"
|
Environment="CONTINUWUITY_CONFIG=/etc/conduwuit/conduwuit.toml"
|
||||||
|
|
||||||
Environment="CONTINUWUITY_LOG_TO_JOURNALD=1"
|
|
||||||
Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N"
|
|
||||||
|
|
||||||
ExecStart=/usr/sbin/conduwuit
|
ExecStart=/usr/sbin/conduwuit
|
||||||
|
|
||||||
ReadWritePaths=/var/lib/conduwuit /etc/conduwuit
|
ReadWritePaths=/var/lib/conduwuit /etc/conduwuit
|
||||||
|
|||||||
@@ -20,4 +20,3 @@
|
|||||||
- [Testing](development/testing.md)
|
- [Testing](development/testing.md)
|
||||||
- [Hot Reloading ("Live" Development)](development/hot_reload.md)
|
- [Hot Reloading ("Live" Development)](development/hot_reload.md)
|
||||||
- [Community (and Guidelines)](community.md)
|
- [Community (and Guidelines)](community.md)
|
||||||
- [Security](security.md)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{{#include ../SECURITY.md}}
|
|
||||||
+1
-1
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[command(name = "conduwuit", version = conduwuit::version())]
|
#[command(name = "conduwuit", version = conduwuit::version())]
|
||||||
pub enum AdminCommand {
|
pub(super) enum AdminCommand {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
/// - Commands for managing appservices
|
/// - Commands for managing appservices
|
||||||
Appservices(AppserviceCommand),
|
Appservices(AppserviceCommand),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::admin_command_dispatch;
|
|||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
pub enum AppserviceCommand {
|
pub(super) enum AppserviceCommand {
|
||||||
/// - Register an appservice using its registration YAML
|
/// - Register an appservice using its registration YAML
|
||||||
///
|
///
|
||||||
/// This command needs a YAML generated by an appservice (such as a bridge),
|
/// This command needs a YAML generated by an appservice (such as a bridge),
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ use crate::admin_command_dispatch;
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum CheckCommand {
|
pub(super) enum CheckCommand {
|
||||||
CheckAllUsers,
|
CheckAllUsers,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::admin_command_dispatch;
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum DebugCommand {
|
pub(super) enum DebugCommand {
|
||||||
/// - Echo input of admin command
|
/// - Echo input of admin command
|
||||||
Echo {
|
Echo {
|
||||||
message: Vec<String>,
|
message: Vec<String>,
|
||||||
@@ -125,13 +125,13 @@ pub enum DebugCommand {
|
|||||||
reset: bool,
|
reset: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// - Sign JSON blob
|
/// - Verify json signatures
|
||||||
///
|
///
|
||||||
/// This command needs a JSON blob provided in a Markdown code block below
|
/// This command needs a JSON blob provided in a Markdown code block below
|
||||||
/// the command.
|
/// the command.
|
||||||
SignJson,
|
SignJson,
|
||||||
|
|
||||||
/// - Verify JSON signatures
|
/// - Verify json signatures
|
||||||
///
|
///
|
||||||
/// This command needs a JSON blob provided in a Markdown code block below
|
/// This command needs a JSON blob provided in a Markdown code block below
|
||||||
/// the command.
|
/// the command.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::{admin_command, admin_command_dispatch};
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, clap::Subcommand)]
|
#[derive(Debug, clap::Subcommand)]
|
||||||
pub enum TesterCommand {
|
pub(crate) enum TesterCommand {
|
||||||
Panic,
|
Panic,
|
||||||
Failure,
|
Failure,
|
||||||
Tester,
|
Tester,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::admin_command_dispatch;
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub 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,
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use crate::admin_command_dispatch;
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub 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 or event ID (not redacted)
|
||||||
Delete {
|
Delete {
|
||||||
@@ -90,10 +90,10 @@ pub enum MediaCommand {
|
|||||||
#[arg(short, long, default_value("10000"))]
|
#[arg(short, long, default_value("10000"))]
|
||||||
timeout: u32,
|
timeout: u32,
|
||||||
|
|
||||||
#[arg(long, default_value("800"))]
|
#[arg(short, long, default_value("800"))]
|
||||||
width: u32,
|
width: u32,
|
||||||
|
|
||||||
#[arg(long, default_value("800"))]
|
#[arg(short, long, default_value("800"))]
|
||||||
height: u32,
|
height: u32,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ conduwuit::mod_ctor! {}
|
|||||||
conduwuit::mod_dtor! {}
|
conduwuit::mod_dtor! {}
|
||||||
conduwuit::rustc_flags_capture! {}
|
conduwuit::rustc_flags_capture! {}
|
||||||
|
|
||||||
pub use crate::admin::AdminCommand;
|
|
||||||
|
|
||||||
/// Install the admin command processor
|
/// Install the admin command processor
|
||||||
pub async fn init(admin_service: &service::admin::Service) {
|
pub async fn init(admin_service: &service::admin::Service) {
|
||||||
_ = admin_service
|
_ = admin_service
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{admin_command, admin_command_dispatch};
|
|||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[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 enum AccountDataCommand {
|
pub(crate) enum AccountDataCommand {
|
||||||
/// - Returns all changes to the account data that happened after `since`.
|
/// - Returns all changes to the account data that happened after `since`.
|
||||||
ChangesSince {
|
ChangesSince {
|
||||||
/// Full user ID
|
/// Full user ID
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::Context;
|
|||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// 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 enum AppserviceCommand {
|
pub(crate) enum AppserviceCommand {
|
||||||
/// - Gets the appservice registration info/details from the ID as a string
|
/// - Gets the appservice registration info/details from the ID as a string
|
||||||
GetRegistration {
|
GetRegistration {
|
||||||
/// Appservice registration ID
|
/// Appservice registration ID
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::Context;
|
|||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// 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 enum GlobalsCommand {
|
pub(crate) enum GlobalsCommand {
|
||||||
DatabaseVersion,
|
DatabaseVersion,
|
||||||
|
|
||||||
CurrentCount,
|
CurrentCount,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use crate::admin_command_dispatch;
|
|||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// Query tables from database
|
/// Query tables from database
|
||||||
pub 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(AccountDataCommand),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::Context;
|
|||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// All the getters and iterators from src/database/key_value/presence.rs
|
/// All the getters and iterators from src/database/key_value/presence.rs
|
||||||
pub enum PresenceCommand {
|
pub(crate) enum PresenceCommand {
|
||||||
/// - Returns the latest presence event for the given user.
|
/// - Returns the latest presence event for the given user.
|
||||||
GetPresence {
|
GetPresence {
|
||||||
/// Full user ID
|
/// Full user ID
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use ruma::OwnedUserId;
|
|||||||
use crate::Context;
|
use crate::Context;
|
||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum PusherCommand {
|
pub(crate) enum PusherCommand {
|
||||||
/// - Returns all the pushers for the user.
|
/// - Returns all the pushers for the user.
|
||||||
GetPushers {
|
GetPushers {
|
||||||
/// Full user ID
|
/// Full user ID
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use crate::{admin_command, admin_command_dispatch};
|
|||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
#[allow(clippy::enum_variant_names)]
|
#[allow(clippy::enum_variant_names)]
|
||||||
/// Query tables from database
|
/// Query tables from database
|
||||||
pub enum RawCommand {
|
pub(crate) enum RawCommand {
|
||||||
/// - List database maps
|
/// - List database maps
|
||||||
RawMaps,
|
RawMaps,
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{admin_command, admin_command_dispatch};
|
|||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// Resolver service and caches
|
/// Resolver service and caches
|
||||||
pub enum ResolverCommand {
|
pub(crate) enum ResolverCommand {
|
||||||
/// Query the destinations cache
|
/// Query the destinations cache
|
||||||
DestinationsCache {
|
DestinationsCache {
|
||||||
server_name: Option<OwnedServerName>,
|
server_name: Option<OwnedServerName>,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::Context;
|
|||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// All the getters and iterators from src/database/key_value/rooms/alias.rs
|
/// All the getters and iterators from src/database/key_value/rooms/alias.rs
|
||||||
pub enum RoomAliasCommand {
|
pub(crate) enum RoomAliasCommand {
|
||||||
ResolveLocalAlias {
|
ResolveLocalAlias {
|
||||||
/// Full room alias
|
/// Full room alias
|
||||||
alias: OwnedRoomAliasId,
|
alias: OwnedRoomAliasId,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use ruma::{OwnedRoomId, OwnedServerName, OwnedUserId};
|
|||||||
use crate::Context;
|
use crate::Context;
|
||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum RoomStateCacheCommand {
|
pub(crate) enum RoomStateCacheCommand {
|
||||||
ServerInRoom {
|
ServerInRoom {
|
||||||
server: OwnedServerName,
|
server: OwnedServerName,
|
||||||
room_id: OwnedRoomId,
|
room_id: OwnedRoomId,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{admin_command, admin_command_dispatch};
|
|||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// Query tables from database
|
/// Query tables from database
|
||||||
pub enum RoomTimelineCommand {
|
pub(crate) enum RoomTimelineCommand {
|
||||||
Pdus {
|
Pdus {
|
||||||
room_id: OwnedRoomOrAliasId,
|
room_id: OwnedRoomOrAliasId,
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::Context;
|
|||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// All the getters and iterators from src/database/key_value/sending.rs
|
/// All the getters and iterators from src/database/key_value/sending.rs
|
||||||
pub enum SendingCommand {
|
pub(crate) enum SendingCommand {
|
||||||
/// - Queries database for all `servercurrentevent_data`
|
/// - Queries database for all `servercurrentevent_data`
|
||||||
ActiveRequests,
|
ActiveRequests,
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::{admin_command, admin_command_dispatch};
|
|||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// Query tables from database
|
/// Query tables from database
|
||||||
pub enum ShortCommand {
|
pub(crate) enum ShortCommand {
|
||||||
ShortEventId {
|
ShortEventId {
|
||||||
event_id: OwnedEventId,
|
event_id: OwnedEventId,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{admin_command, admin_command_dispatch};
|
|||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
/// All the getters and iterators from src/database/key_value/users.rs
|
/// All the getters and iterators from src/database/key_value/users.rs
|
||||||
pub enum UsersCommand {
|
pub(crate) enum UsersCommand {
|
||||||
CountUsers,
|
CountUsers,
|
||||||
|
|
||||||
IterUsers,
|
IterUsers,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use ruma::{OwnedRoomAliasId, OwnedRoomId};
|
|||||||
use crate::Context;
|
use crate::Context;
|
||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum RoomAliasCommand {
|
pub(crate) enum RoomAliasCommand {
|
||||||
/// - Make an alias point to a room.
|
/// - Make an alias point to a room.
|
||||||
Set {
|
Set {
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use ruma::OwnedRoomId;
|
|||||||
use crate::{Context, PAGE_SIZE, get_room_info};
|
use crate::{Context, PAGE_SIZE, get_room_info};
|
||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum RoomDirectoryCommand {
|
pub(crate) enum RoomDirectoryCommand {
|
||||||
/// - Publish a room to the room directory
|
/// - Publish a room to the room directory
|
||||||
Publish {
|
Publish {
|
||||||
/// The room id of the room to publish
|
/// The room id of the room to publish
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::{admin_command, admin_command_dispatch};
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum RoomInfoCommand {
|
pub(crate) enum RoomInfoCommand {
|
||||||
/// - List joined members in a room
|
/// - List joined members in a room
|
||||||
ListJoinedMembers {
|
ListJoinedMembers {
|
||||||
room_id: OwnedRoomId,
|
room_id: OwnedRoomId,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use crate::admin_command_dispatch;
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum RoomCommand {
|
pub(super) enum RoomCommand {
|
||||||
/// - List all rooms the server knows about
|
/// - List all rooms the server knows about
|
||||||
#[clap(alias = "list")]
|
#[clap(alias = "list")]
|
||||||
ListRooms {
|
ListRooms {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::{admin_command, admin_command_dispatch, get_room_info};
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum RoomModerationCommand {
|
pub(crate) enum RoomModerationCommand {
|
||||||
/// - Bans a room from local users joining and evicts all our local users
|
/// - Bans a room from local users joining and evicts all our local users
|
||||||
/// (including server
|
/// (including server
|
||||||
/// admins)
|
/// admins)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use crate::admin_command_dispatch;
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum ServerCommand {
|
pub(super) enum ServerCommand {
|
||||||
/// - Time elapsed since startup
|
/// - Time elapsed since startup
|
||||||
Uptime,
|
Uptime,
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::admin_command_dispatch;
|
|||||||
|
|
||||||
#[admin_command_dispatch]
|
#[admin_command_dispatch]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum UserCommand {
|
pub(super) enum UserCommand {
|
||||||
/// - Create a new user
|
/// - Create a new user
|
||||||
#[clap(alias = "create")]
|
#[clap(alias = "create")]
|
||||||
CreateUser {
|
CreateUser {
|
||||||
|
|||||||
@@ -2162,109 +2162,6 @@ async fn knock_room_by_id_helper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For knock_restricted rooms, check if the user meets the restricted conditions
|
|
||||||
// If they do, attempt to join instead of knock
|
|
||||||
// This is not mentioned in the spec, but should be allowable (we're allowed to
|
|
||||||
// auto-join invites to knocked rooms)
|
|
||||||
let join_rule = services.rooms.state_accessor.get_join_rules(room_id).await;
|
|
||||||
if let JoinRule::KnockRestricted(restricted) = &join_rule {
|
|
||||||
let restriction_rooms: Vec<_> = restricted
|
|
||||||
.allow
|
|
||||||
.iter()
|
|
||||||
.filter_map(|a| match a {
|
|
||||||
| AllowRule::RoomMembership(r) => Some(&r.room_id),
|
|
||||||
| _ => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Check if the user is in any of the allowed rooms
|
|
||||||
let mut user_meets_restrictions = false;
|
|
||||||
for restriction_room_id in &restriction_rooms {
|
|
||||||
if services
|
|
||||||
.rooms
|
|
||||||
.state_cache
|
|
||||||
.is_joined(sender_user, restriction_room_id)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
user_meets_restrictions = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user meets the restrictions, try joining instead
|
|
||||||
if user_meets_restrictions {
|
|
||||||
debug_info!(
|
|
||||||
"{sender_user} meets the restricted criteria in knock_restricted room \
|
|
||||||
{room_id}, attempting to join instead of knock"
|
|
||||||
);
|
|
||||||
// For this case, we need to drop the state lock and get a new one in
|
|
||||||
// join_room_by_id_helper We need to release the lock here and let
|
|
||||||
// join_room_by_id_helper acquire it again
|
|
||||||
drop(state_lock);
|
|
||||||
match join_room_by_id_helper(
|
|
||||||
services,
|
|
||||||
sender_user,
|
|
||||||
room_id,
|
|
||||||
reason.clone(),
|
|
||||||
servers,
|
|
||||||
None,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
| Ok(_) => return Ok(knock_room::v3::Response::new(room_id.to_owned())),
|
|
||||||
| Err(e) => {
|
|
||||||
debug_warn!(
|
|
||||||
"Failed to convert knock to join for {sender_user} in {room_id}: {e:?}"
|
|
||||||
);
|
|
||||||
// Get a new state lock for the remaining knock logic
|
|
||||||
let new_state_lock = services.rooms.state.mutex.lock(room_id).await;
|
|
||||||
|
|
||||||
let server_in_room = services
|
|
||||||
.rooms
|
|
||||||
.state_cache
|
|
||||||
.server_in_room(services.globals.server_name(), room_id)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let local_knock = server_in_room
|
|
||||||
|| servers.is_empty()
|
|
||||||
|| (servers.len() == 1 && services.globals.server_is_ours(&servers[0]));
|
|
||||||
|
|
||||||
if local_knock {
|
|
||||||
knock_room_helper_local(
|
|
||||||
services,
|
|
||||||
sender_user,
|
|
||||||
room_id,
|
|
||||||
reason,
|
|
||||||
servers,
|
|
||||||
new_state_lock,
|
|
||||||
)
|
|
||||||
.boxed()
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
knock_room_helper_remote(
|
|
||||||
services,
|
|
||||||
sender_user,
|
|
||||||
room_id,
|
|
||||||
reason,
|
|
||||||
servers,
|
|
||||||
new_state_lock,
|
|
||||||
)
|
|
||||||
.boxed()
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(knock_room::v3::Response::new(room_id.to_owned()));
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if !matches!(join_rule, JoinRule::Knock | JoinRule::KnockRestricted(_)) {
|
|
||||||
debug_warn!(
|
|
||||||
"{sender_user} attempted to knock on room {room_id} but its join rule is \
|
|
||||||
{join_rule:?}, not knock or knock_restricted"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let server_in_room = services
|
let server_in_room = services
|
||||||
.rooms
|
.rooms
|
||||||
.state_cache
|
.state_cache
|
||||||
@@ -2312,12 +2209,6 @@ async fn knock_room_helper_local(
|
|||||||
return Err!(Request(Forbidden("This room does not support knocking.")));
|
return Err!(Request(Forbidden("This room does not support knocking.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that this room has a valid knock or knock_restricted join rule
|
|
||||||
let join_rule = services.rooms.state_accessor.get_join_rules(room_id).await;
|
|
||||||
if !matches!(join_rule, JoinRule::Knock | JoinRule::KnockRestricted(_)) {
|
|
||||||
return Err!(Request(Forbidden("This room's join rule does not allow knocking.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
let content = RoomMemberEventContent {
|
let content = RoomMemberEventContent {
|
||||||
displayname: services.users.displayname(sender_user).await.ok(),
|
displayname: services.users.displayname(sender_user).await.ok(),
|
||||||
avatar_url: services.users.avatar_url(sender_user).await.ok(),
|
avatar_url: services.users.avatar_url(sender_user).await.ok(),
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use axum::{Json, extract::State, response::IntoResponse};
|
use axum::{Json, extract::State, response::IntoResponse};
|
||||||
use conduwuit::{Error, Result};
|
use conduwuit::{Error, Result};
|
||||||
use futures::StreamExt;
|
|
||||||
use ruma::api::client::{
|
use ruma::api::client::{
|
||||||
discovery::{
|
discovery::{
|
||||||
discover_homeserver::{self, HomeserverInfo, SlidingSyncProxyInfo},
|
discover_homeserver::{self, HomeserverInfo, SlidingSyncProxyInfo},
|
||||||
@@ -18,7 +17,7 @@ pub(crate) async fn well_known_client(
|
|||||||
State(services): State<crate::State>,
|
State(services): State<crate::State>,
|
||||||
_body: Ruma<discover_homeserver::Request>,
|
_body: Ruma<discover_homeserver::Request>,
|
||||||
) -> Result<discover_homeserver::Response> {
|
) -> Result<discover_homeserver::Response> {
|
||||||
let client_url = match services.config.well_known.client.as_ref() {
|
let client_url = match services.server.config.well_known.client.as_ref() {
|
||||||
| Some(url) => url.to_string(),
|
| Some(url) => url.to_string(),
|
||||||
| None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
| None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
||||||
};
|
};
|
||||||
@@ -34,63 +33,44 @@ pub(crate) async fn well_known_client(
|
|||||||
/// # `GET /.well-known/matrix/support`
|
/// # `GET /.well-known/matrix/support`
|
||||||
///
|
///
|
||||||
/// Server support contact and support page of a homeserver's domain.
|
/// Server support contact and support page of a homeserver's domain.
|
||||||
/// Implements MSC1929 for server discovery.
|
|
||||||
/// If no configuration is set, uses admin users as contacts.
|
|
||||||
pub(crate) async fn well_known_support(
|
pub(crate) async fn well_known_support(
|
||||||
State(services): State<crate::State>,
|
State(services): State<crate::State>,
|
||||||
_body: Ruma<discover_support::Request>,
|
_body: Ruma<discover_support::Request>,
|
||||||
) -> Result<discover_support::Response> {
|
) -> Result<discover_support::Response> {
|
||||||
let support_page = services
|
let support_page = services
|
||||||
|
.server
|
||||||
.config
|
.config
|
||||||
.well_known
|
.well_known
|
||||||
.support_page
|
.support_page
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(ToString::to_string);
|
.map(ToString::to_string);
|
||||||
|
|
||||||
let email_address = services.config.well_known.support_email.clone();
|
let role = services.server.config.well_known.support_role.clone();
|
||||||
let matrix_id = services.config.well_known.support_mxid.clone();
|
|
||||||
|
// support page or role must be either defined for this to be valid
|
||||||
|
if support_page.is_none() && role.is_none() {
|
||||||
|
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let email_address = services.server.config.well_known.support_email.clone();
|
||||||
|
let matrix_id = services.server.config.well_known.support_mxid.clone();
|
||||||
|
|
||||||
|
// if a role is specified, an email address or matrix id is required
|
||||||
|
if role.is_some() && (email_address.is_none() && matrix_id.is_none()) {
|
||||||
|
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: support defining multiple contacts in the config
|
// TODO: support defining multiple contacts in the config
|
||||||
let mut contacts: Vec<Contact> = vec![];
|
let mut contacts: Vec<Contact> = vec![];
|
||||||
|
|
||||||
let role_value = services
|
if let Some(role) = role {
|
||||||
.config
|
let contact = Contact { role, email_address, matrix_id };
|
||||||
.well_known
|
|
||||||
.support_role
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| "m.role.admin".to_owned().into());
|
|
||||||
|
|
||||||
// Add configured contact if at least one contact method is specified
|
contacts.push(contact);
|
||||||
if email_address.is_some() || matrix_id.is_some() {
|
|
||||||
contacts.push(Contact {
|
|
||||||
role: role_value.clone(),
|
|
||||||
email_address: email_address.clone(),
|
|
||||||
matrix_id: matrix_id.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to add admin users as contacts if no contacts are configured
|
|
||||||
if contacts.is_empty() {
|
|
||||||
if let Ok(admin_room) = services.admin.get_admin_room().await {
|
|
||||||
let admin_users = services.rooms.state_cache.room_members(&admin_room);
|
|
||||||
let mut stream = admin_users;
|
|
||||||
|
|
||||||
while let Some(user_id) = stream.next().await {
|
|
||||||
// Skip server user
|
|
||||||
if *user_id == services.globals.server_user {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
contacts.push(Contact {
|
|
||||||
role: role_value.clone(),
|
|
||||||
email_address: None,
|
|
||||||
matrix_id: Some(user_id.to_owned()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// support page or role+contacts must be either defined for this to be valid
|
||||||
if contacts.is_empty() && support_page.is_none() {
|
if contacts.is_empty() && support_page.is_none() {
|
||||||
// No admin room, no configured contacts, and no support page
|
|
||||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,9 +84,9 @@ pub(crate) async fn well_known_support(
|
|||||||
pub(crate) async fn syncv3_client_server_json(
|
pub(crate) async fn syncv3_client_server_json(
|
||||||
State(services): State<crate::State>,
|
State(services): State<crate::State>,
|
||||||
) -> Result<impl IntoResponse> {
|
) -> Result<impl IntoResponse> {
|
||||||
let server_url = match services.config.well_known.client.as_ref() {
|
let server_url = match services.server.config.well_known.client.as_ref() {
|
||||||
| Some(url) => url.to_string(),
|
| Some(url) => url.to_string(),
|
||||||
| None => match services.config.well_known.server.as_ref() {
|
| None => match services.server.config.well_known.server.as_ref() {
|
||||||
| Some(url) => url.to_string(),
|
| Some(url) => url.to_string(),
|
||||||
| None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
| None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ version.workspace = true
|
|||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
# [[bin]]
|
# [[bin]]
|
||||||
# path = "main.rs"
|
# path = "main.rs"
|
||||||
# name = "conduwuit_build_metadata"
|
# name = "conduwuit_build_metadata"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "mod.rs"
|
path = "mod.rs"
|
||||||
crate-type = [
|
crate-type = [
|
||||||
"rlib",
|
"rlib",
|
||||||
# "dylib",
|
# "dylib",
|
||||||
]
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@@ -28,7 +28,7 @@ crate-type = [
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
built = { version = "0.8", features = [] }
|
built = {version = "0.7", features = ["cargo-lock", "dependency-tree"]}
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
@@ -78,13 +78,12 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Rerun Triggers ---
|
// --- Rerun Triggers ---
|
||||||
// TODO: The git rerun triggers seem to always run
|
// Rerun if the git HEAD changes
|
||||||
// // Rerun if the git HEAD changes
|
println!("cargo:rerun-if-changed=.git/HEAD");
|
||||||
// println!("cargo:rerun-if-changed=.git/HEAD");
|
// Rerun if the ref pointed to by HEAD changes (e.g., new commit on branch)
|
||||||
// // Rerun if the ref pointed to by HEAD changes (e.g., new commit on branch)
|
if let Some(ref_path) = run_git_command(&["symbolic-ref", "--quiet", "HEAD"]) {
|
||||||
// if let Some(ref_path) = run_git_command(&["symbolic-ref", "--quiet", "HEAD"])
|
println!("cargo:rerun-if-changed=.git/{ref_path}");
|
||||||
// { println!("cargo:rerun-if-changed=.git/{ref_path}");
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH");
|
println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH");
|
||||||
println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH_SHORT");
|
println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH_SHORT");
|
||||||
|
|||||||
@@ -12,17 +12,11 @@ pub static VERSION_EXTRA: Option<&str> =
|
|||||||
v
|
v
|
||||||
} else if let v @ Some(_) = option_env!("CONDUWUIT_VERSION_EXTRA") {
|
} else if let v @ Some(_) = option_env!("CONDUWUIT_VERSION_EXTRA") {
|
||||||
v
|
v
|
||||||
|
} else if let v @ Some(_) = option_env!("CONDUIT_VERSION_EXTRA") {
|
||||||
|
v
|
||||||
} else {
|
} else {
|
||||||
option_env!("CONDUIT_VERSION_EXTRA")
|
GIT_COMMIT_HASH_SHORT
|
||||||
};
|
};
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn version_tag() -> Option<&'static str> {
|
|
||||||
VERSION_EXTRA
|
|
||||||
.filter(|s| !s.is_empty())
|
|
||||||
.or(GIT_COMMIT_HASH_SHORT)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static GIT_REMOTE_WEB_URL: Option<&str> = option_env!("GIT_REMOTE_WEB_URL");
|
pub static GIT_REMOTE_WEB_URL: Option<&str> = option_env!("GIT_REMOTE_WEB_URL");
|
||||||
pub static GIT_REMOTE_COMMIT_URL: Option<&str> = option_env!("GIT_REMOTE_COMMIT_URL");
|
pub static GIT_REMOTE_COMMIT_URL: Option<&str> = option_env!("GIT_REMOTE_COMMIT_URL");
|
||||||
|
|
||||||
|
|||||||
@@ -274,10 +274,6 @@ pub fn set_dirty_decay<I: Into<Option<usize>>>(arena: I, decay_ms: isize) -> Res
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn background_thread_enable(enable: bool) -> Result<bool> {
|
|
||||||
set::<u8>(&mallctl!("background_thread"), enable.into()).map(is_nonzero!())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_affine_arena() -> bool { is_percpu_arena() || is_phycpu_arena() }
|
pub fn is_affine_arena() -> bool { is_percpu_arena() || is_phycpu_arena() }
|
||||||
|
|||||||
@@ -219,15 +219,6 @@ pub fn check(config: &Config) -> Result {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if support contact information is configured
|
|
||||||
if config.well_known.support_email.is_none() && config.well_known.support_mxid.is_none() {
|
|
||||||
warn!(
|
|
||||||
"No support contact information (support_email or support_mxid) is configured in \
|
|
||||||
the well_known section. Users in the admin room will be automatically listed as \
|
|
||||||
support contacts in the /.well-known/matrix/support endpoint."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if config
|
if config
|
||||||
.url_preview_domain_contains_allowlist
|
.url_preview_domain_contains_allowlist
|
||||||
.contains(&"*".to_owned())
|
.contains(&"*".to_owned())
|
||||||
|
|||||||
@@ -795,24 +795,6 @@ pub struct Config {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub log_thread_ids: bool,
|
pub log_thread_ids: bool,
|
||||||
|
|
||||||
/// Enable journald logging on Unix platforms
|
|
||||||
///
|
|
||||||
/// When enabled, log output will be sent to the systemd journal
|
|
||||||
/// This is only supported on Unix platforms
|
|
||||||
///
|
|
||||||
/// default: false
|
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
#[serde(default)]
|
|
||||||
pub log_to_journald: bool,
|
|
||||||
|
|
||||||
/// The syslog identifier to use with journald logging
|
|
||||||
///
|
|
||||||
/// Only used when journald logging is enabled
|
|
||||||
///
|
|
||||||
/// Defaults to the binary name
|
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
pub journald_identifier: Option<String>,
|
|
||||||
|
|
||||||
/// OpenID token expiration/TTL in seconds.
|
/// OpenID token expiration/TTL in seconds.
|
||||||
///
|
///
|
||||||
/// These are the OpenID tokens that are primarily used for Matrix account
|
/// These are the OpenID tokens that are primarily used for Matrix account
|
||||||
@@ -1915,28 +1897,12 @@ pub struct WellKnownConfig {
|
|||||||
/// example: "matrix.example.com:443"
|
/// example: "matrix.example.com:443"
|
||||||
pub server: Option<OwnedServerName>,
|
pub server: Option<OwnedServerName>,
|
||||||
|
|
||||||
/// URL to a support page for the server, which will be served as part of
|
|
||||||
/// the MSC1929 server support endpoint at /.well-known/matrix/support.
|
|
||||||
/// Will be included alongside any contact information
|
|
||||||
pub support_page: Option<Url>,
|
pub support_page: Option<Url>,
|
||||||
|
|
||||||
/// Role string for server support contacts, to be served as part of the
|
|
||||||
/// MSC1929 server support endpoint at /.well-known/matrix/support.
|
|
||||||
///
|
|
||||||
/// default: "m.role.admin"
|
|
||||||
pub support_role: Option<ContactRole>,
|
pub support_role: Option<ContactRole>,
|
||||||
|
|
||||||
/// Email address for server support contacts, to be served as part of the
|
|
||||||
/// MSC1929 server support endpoint.
|
|
||||||
/// This will be used along with support_mxid if specified.
|
|
||||||
pub support_email: Option<String>,
|
pub support_email: Option<String>,
|
||||||
|
|
||||||
/// Matrix ID for server support contacts, to be served as part of the
|
|
||||||
/// MSC1929 server support endpoint.
|
|
||||||
/// This will be used along with support_email if specified.
|
|
||||||
///
|
|
||||||
/// If no email or mxid is specified, all of the server's admins will be
|
|
||||||
/// listed.
|
|
||||||
pub support_mxid: Option<OwnedUserId>,
|
pub support_mxid: Option<OwnedUserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ pub fn user_agent() -> &'static str { USER_AGENT.get_or_init(init_user_agent) }
|
|||||||
fn init_user_agent() -> String { format!("{}/{}", name(), version()) }
|
fn init_user_agent() -> String { format!("{}/{}", name(), version()) }
|
||||||
|
|
||||||
fn init_version() -> String {
|
fn init_version() -> String {
|
||||||
conduwuit_build_metadata::version_tag()
|
conduwuit_build_metadata::VERSION_EXTRA
|
||||||
.map_or(SEMANTIC.to_owned(), |extra| format!("{SEMANTIC} ({extra})"))
|
.map_or(SEMANTIC.to_owned(), |extra| format!("{SEMANTIC} ({extra})"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
|
fmt::{Debug, Display},
|
||||||
|
hash::Hash,
|
||||||
|
};
|
||||||
|
|
||||||
use ruma::{EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId, events::TimelineEventType};
|
use ruma::{EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId, events::TimelineEventType};
|
||||||
use serde_json::value::RawValue as RawJsonValue;
|
use serde_json::value::RawValue as RawJsonValue;
|
||||||
|
|
||||||
/// Abstraction of a PDU so users can have their own PDU types.
|
/// Abstraction of a PDU so users can have their own PDU types.
|
||||||
pub trait Event {
|
pub trait Event {
|
||||||
|
type Id: Clone + Debug + Display + Eq + Ord + Hash + Send + Borrow<EventId>;
|
||||||
|
|
||||||
/// The `EventId` of this event.
|
/// The `EventId` of this event.
|
||||||
fn event_id(&self) -> &EventId;
|
fn event_id(&self) -> &Self::Id;
|
||||||
|
|
||||||
/// The `RoomId` of this event.
|
/// The `RoomId` of this event.
|
||||||
fn room_id(&self) -> &RoomId;
|
fn room_id(&self) -> &RoomId;
|
||||||
@@ -26,18 +34,20 @@ pub trait Event {
|
|||||||
|
|
||||||
/// The events before this event.
|
/// The events before this event.
|
||||||
// Requires GATs to avoid boxing (and TAIT for making it convenient).
|
// Requires GATs to avoid boxing (and TAIT for making it convenient).
|
||||||
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
|
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &Self::Id> + Send + '_;
|
||||||
|
|
||||||
/// All the authenticating events for this event.
|
/// All the authenticating events for this event.
|
||||||
// Requires GATs to avoid boxing (and TAIT for making it convenient).
|
// Requires GATs to avoid boxing (and TAIT for making it convenient).
|
||||||
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
|
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &Self::Id> + Send + '_;
|
||||||
|
|
||||||
/// If this event is a redaction event this is the event it redacts.
|
/// If this event is a redaction event this is the event it redacts.
|
||||||
fn redacts(&self) -> Option<&EventId>;
|
fn redacts(&self) -> Option<&Self::Id>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Event> Event for &T {
|
impl<T: Event> Event for &T {
|
||||||
fn event_id(&self) -> &EventId { (*self).event_id() }
|
type Id = T::Id;
|
||||||
|
|
||||||
|
fn event_id(&self) -> &Self::Id { (*self).event_id() }
|
||||||
|
|
||||||
fn room_id(&self) -> &RoomId { (*self).room_id() }
|
fn room_id(&self) -> &RoomId { (*self).room_id() }
|
||||||
|
|
||||||
@@ -51,13 +61,13 @@ impl<T: Event> Event for &T {
|
|||||||
|
|
||||||
fn state_key(&self) -> Option<&str> { (*self).state_key() }
|
fn state_key(&self) -> Option<&str> { (*self).state_key() }
|
||||||
|
|
||||||
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &Self::Id> + Send + '_ {
|
||||||
(*self).prev_events()
|
(*self).prev_events()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &Self::Id> + Send + '_ {
|
||||||
(*self).auth_events()
|
(*self).auth_events()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redacts(&self) -> Option<&EventId> { (*self).redacts() }
|
fn redacts(&self) -> Option<&Self::Id> { (*self).redacts() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,9 @@ impl Pdu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Event for Pdu {
|
impl Event for Pdu {
|
||||||
fn event_id(&self) -> &EventId { &self.event_id }
|
type Id = OwnedEventId;
|
||||||
|
|
||||||
|
fn event_id(&self) -> &Self::Id { &self.event_id }
|
||||||
|
|
||||||
fn room_id(&self) -> &RoomId { &self.room_id }
|
fn room_id(&self) -> &RoomId { &self.room_id }
|
||||||
|
|
||||||
@@ -95,15 +97,15 @@ impl Event for Pdu {
|
|||||||
|
|
||||||
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
|
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
|
||||||
|
|
||||||
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &Self::Id> + Send + '_ {
|
||||||
self.prev_events.iter().map(AsRef::as_ref)
|
self.prev_events.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &Self::Id> + Send + '_ {
|
||||||
self.auth_events.iter().map(AsRef::as_ref)
|
self.auth_events.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redacts(&self) -> Option<&EventId> { self.redacts.as_deref() }
|
fn redacts(&self) -> Option<&Self::Id> { self.redacts.as_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prevent derived equality which wouldn't limit itself to event_id
|
/// Prevent derived equality which wouldn't limit itself to event_id
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use ruma::{
|
use ruma::{
|
||||||
events::{
|
events::{
|
||||||
AnyMessageLikeEvent, AnyStateEvent, AnyStrippedStateEvent, AnySyncStateEvent,
|
AnyEphemeralRoomEvent, AnyMessageLikeEvent, AnyStateEvent, AnyStrippedStateEvent,
|
||||||
AnySyncTimelineEvent, AnyTimelineEvent, StateEvent, room::member::RoomMemberEventContent,
|
AnySyncStateEvent, AnySyncTimelineEvent, AnyTimelineEvent, StateEvent,
|
||||||
space::child::HierarchySpaceChildEvent,
|
room::member::RoomMemberEventContent, space::child::HierarchySpaceChildEvent,
|
||||||
},
|
},
|
||||||
serde::Raw,
|
serde::Raw,
|
||||||
};
|
};
|
||||||
@@ -10,6 +10,41 @@ use serde_json::{json, value::Value as JsonValue};
|
|||||||
|
|
||||||
use crate::implement;
|
use crate::implement;
|
||||||
|
|
||||||
|
/// This only works for events that are also AnyRoomEvents.
|
||||||
|
#[must_use]
|
||||||
|
#[implement(super::Pdu)]
|
||||||
|
pub fn into_any_event(self) -> Raw<AnyEphemeralRoomEvent> {
|
||||||
|
serde_json::from_value(self.into_any_event_value()).expect("Raw::from_value always works")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This only works for events that are also AnyRoomEvents.
|
||||||
|
#[implement(super::Pdu)]
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
pub fn into_any_event_value(self) -> JsonValue {
|
||||||
|
let (redacts, content) = self.copy_redacts();
|
||||||
|
let mut json = json!({
|
||||||
|
"content": content,
|
||||||
|
"type": self.kind,
|
||||||
|
"event_id": self.event_id,
|
||||||
|
"sender": self.sender,
|
||||||
|
"origin_server_ts": self.origin_server_ts,
|
||||||
|
"room_id": self.room_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(unsigned) = &self.unsigned {
|
||||||
|
json["unsigned"] = json!(unsigned);
|
||||||
|
}
|
||||||
|
if let Some(state_key) = &self.state_key {
|
||||||
|
json["state_key"] = json!(state_key);
|
||||||
|
}
|
||||||
|
if let Some(redacts) = &redacts {
|
||||||
|
json["redacts"] = json!(redacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
json
|
||||||
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -18,8 +53,7 @@ pub fn into_room_event(self) -> Raw<AnyTimelineEvent> { self.to_room_event() }
|
|||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_room_event(&self) -> Raw<AnyTimelineEvent> {
|
pub fn to_room_event(&self) -> Raw<AnyTimelineEvent> {
|
||||||
let value = self.to_room_event_value();
|
serde_json::from_value(self.to_room_event_value()).expect("Raw::from_value always works")
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
@@ -57,8 +91,8 @@ pub fn into_message_like_event(self) -> Raw<AnyMessageLikeEvent> { self.to_messa
|
|||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_message_like_event(&self) -> Raw<AnyMessageLikeEvent> {
|
pub fn to_message_like_event(&self) -> Raw<AnyMessageLikeEvent> {
|
||||||
let value = self.to_message_like_event_value();
|
serde_json::from_value(self.to_message_like_event_value())
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
.expect("Raw::from_value always works")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
@@ -96,8 +130,7 @@ pub fn into_sync_room_event(self) -> Raw<AnySyncTimelineEvent> { self.to_sync_ro
|
|||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_sync_room_event(&self) -> Raw<AnySyncTimelineEvent> {
|
pub fn to_sync_room_event(&self) -> Raw<AnySyncTimelineEvent> {
|
||||||
let value = self.to_sync_room_event_value();
|
serde_json::from_value(self.to_sync_room_event_value()).expect("Raw::from_value always works")
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
@@ -129,8 +162,7 @@ pub fn to_sync_room_event_value(&self) -> JsonValue {
|
|||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn into_state_event(self) -> Raw<AnyStateEvent> {
|
pub fn into_state_event(self) -> Raw<AnyStateEvent> {
|
||||||
let value = self.into_state_event_value();
|
serde_json::from_value(self.into_state_event_value()).expect("Raw::from_value always works")
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
@@ -157,8 +189,8 @@ pub fn into_state_event_value(self) -> JsonValue {
|
|||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn into_sync_state_event(self) -> Raw<AnySyncStateEvent> {
|
pub fn into_sync_state_event(self) -> Raw<AnySyncStateEvent> {
|
||||||
let value = self.into_sync_state_event_value();
|
serde_json::from_value(self.into_sync_state_event_value())
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
.expect("Raw::from_value always works")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
@@ -191,8 +223,8 @@ pub fn into_stripped_state_event(self) -> Raw<AnyStrippedStateEvent> {
|
|||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_stripped_state_event(&self) -> Raw<AnyStrippedStateEvent> {
|
pub fn to_stripped_state_event(&self) -> Raw<AnyStrippedStateEvent> {
|
||||||
let value = self.to_stripped_state_event_value();
|
serde_json::from_value(self.to_stripped_state_event_value())
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
.expect("Raw::from_value always works")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
@@ -210,8 +242,8 @@ pub fn to_stripped_state_event_value(&self) -> JsonValue {
|
|||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn into_stripped_spacechild_state_event(self) -> Raw<HierarchySpaceChildEvent> {
|
pub fn into_stripped_spacechild_state_event(self) -> Raw<HierarchySpaceChildEvent> {
|
||||||
let value = self.into_stripped_spacechild_state_event_value();
|
serde_json::from_value(self.into_stripped_spacechild_state_event_value())
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
.expect("Raw::from_value always works")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
@@ -230,8 +262,7 @@ pub fn into_stripped_spacechild_state_event_value(self) -> JsonValue {
|
|||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn into_member_event(self) -> Raw<StateEvent<RoomMemberEventContent>> {
|
pub fn into_member_event(self) -> Raw<StateEvent<RoomMemberEventContent>> {
|
||||||
let value = self.into_member_event_value();
|
serde_json::from_value(self.into_member_event_value()).expect("Raw::from_value always works")
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ fn lexico_topo_sort(c: &mut test::Bencher) {
|
|||||||
#[cfg(conduwuit_bench)]
|
#[cfg(conduwuit_bench)]
|
||||||
#[cfg_attr(conduwuit_bench, bench)]
|
#[cfg_attr(conduwuit_bench, bench)]
|
||||||
fn resolution_shallow_auth_chain(c: &mut test::Bencher) {
|
fn resolution_shallow_auth_chain(c: &mut test::Bencher) {
|
||||||
|
let parallel_fetches = 32;
|
||||||
let mut store = TestStore(hashmap! {});
|
let mut store = TestStore(hashmap! {});
|
||||||
|
|
||||||
// build up the DAG
|
// build up the DAG
|
||||||
@@ -77,6 +78,7 @@ fn resolution_shallow_auth_chain(c: &mut test::Bencher) {
|
|||||||
&auth_chain_sets,
|
&auth_chain_sets,
|
||||||
&fetch,
|
&fetch,
|
||||||
&exists,
|
&exists,
|
||||||
|
parallel_fetches,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@@ -89,6 +91,7 @@ fn resolution_shallow_auth_chain(c: &mut test::Bencher) {
|
|||||||
#[cfg(conduwuit_bench)]
|
#[cfg(conduwuit_bench)]
|
||||||
#[cfg_attr(conduwuit_bench, bench)]
|
#[cfg_attr(conduwuit_bench, bench)]
|
||||||
fn resolve_deeper_event_set(c: &mut test::Bencher) {
|
fn resolve_deeper_event_set(c: &mut test::Bencher) {
|
||||||
|
let parallel_fetches = 32;
|
||||||
let mut inner = INITIAL_EVENTS();
|
let mut inner = INITIAL_EVENTS();
|
||||||
let ban = BAN_STATE_SET();
|
let ban = BAN_STATE_SET();
|
||||||
|
|
||||||
@@ -150,6 +153,7 @@ fn resolve_deeper_event_set(c: &mut test::Bencher) {
|
|||||||
&auth_chain_sets,
|
&auth_chain_sets,
|
||||||
&fetch,
|
&fetch,
|
||||||
&exists,
|
&exists,
|
||||||
|
parallel_fetches,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@@ -186,11 +190,7 @@ impl<E: Event + Clone> TestStore<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a Vec of the related auth events to the given `event`.
|
/// Returns a Vec of the related auth events to the given `event`.
|
||||||
fn auth_event_ids(
|
fn auth_event_ids(&self, room_id: &RoomId, event_ids: Vec<E::Id>) -> Result<HashSet<E::Id>> {
|
||||||
&self,
|
|
||||||
room_id: &RoomId,
|
|
||||||
event_ids: Vec<OwnedEventId>,
|
|
||||||
) -> Result<HashSet<OwnedEventId>> {
|
|
||||||
let mut result = HashSet::new();
|
let mut result = HashSet::new();
|
||||||
let mut stack = event_ids;
|
let mut stack = event_ids;
|
||||||
|
|
||||||
@@ -216,8 +216,8 @@ impl<E: Event + Clone> TestStore<E> {
|
|||||||
fn auth_chain_diff(
|
fn auth_chain_diff(
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
event_ids: Vec<Vec<OwnedEventId>>,
|
event_ids: Vec<Vec<E::Id>>,
|
||||||
) -> Result<Vec<OwnedEventId>> {
|
) -> Result<Vec<E::Id>> {
|
||||||
let mut auth_chain_sets = vec![];
|
let mut auth_chain_sets = vec![];
|
||||||
for ids in event_ids {
|
for ids in event_ids {
|
||||||
// TODO state store `auth_event_ids` returns self in the event ids list
|
// TODO state store `auth_event_ids` returns self in the event ids list
|
||||||
@@ -238,7 +238,7 @@ impl<E: Event + Clone> TestStore<E> {
|
|||||||
Ok(auth_chain_sets
|
Ok(auth_chain_sets
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.filter(|id| !common.contains(id))
|
.filter(|id| !common.contains(id.borrow()))
|
||||||
.collect())
|
.collect())
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
@@ -565,7 +565,7 @@ impl EventTypeExt for &TimelineEventType {
|
|||||||
|
|
||||||
mod event {
|
mod event {
|
||||||
use ruma::{
|
use ruma::{
|
||||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId,
|
MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId,
|
||||||
events::{TimelineEventType, pdu::Pdu},
|
events::{TimelineEventType, pdu::Pdu},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -574,7 +574,9 @@ mod event {
|
|||||||
use super::Event;
|
use super::Event;
|
||||||
|
|
||||||
impl Event for PduEvent {
|
impl Event for PduEvent {
|
||||||
fn event_id(&self) -> &EventId { &self.event_id }
|
type Id = OwnedEventId;
|
||||||
|
|
||||||
|
fn event_id(&self) -> &Self::Id { &self.event_id }
|
||||||
|
|
||||||
fn room_id(&self) -> &RoomId {
|
fn room_id(&self) -> &RoomId {
|
||||||
match &self.rest {
|
match &self.rest {
|
||||||
@@ -630,30 +632,28 @@ mod event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
|
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &Self::Id> + Send + '_> {
|
||||||
match &self.rest {
|
match &self.rest {
|
||||||
| Pdu::RoomV1Pdu(ev) =>
|
| Pdu::RoomV1Pdu(ev) => Box::new(ev.prev_events.iter().map(|(id, _)| id)),
|
||||||
Box::new(ev.prev_events.iter().map(|(id, _)| id.as_ref())),
|
| Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter()),
|
||||||
| Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter().map(AsRef::as_ref)),
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
||||||
| _ => unreachable!("new PDU version"),
|
| _ => unreachable!("new PDU version"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
|
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &Self::Id> + Send + '_> {
|
||||||
match &self.rest {
|
match &self.rest {
|
||||||
| Pdu::RoomV1Pdu(ev) =>
|
| Pdu::RoomV1Pdu(ev) => Box::new(ev.auth_events.iter().map(|(id, _)| id)),
|
||||||
Box::new(ev.auth_events.iter().map(|(id, _)| id.as_ref())),
|
| Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter()),
|
||||||
| Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter().map(AsRef::as_ref)),
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
||||||
| _ => unreachable!("new PDU version"),
|
| _ => unreachable!("new PDU version"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redacts(&self) -> Option<&EventId> {
|
fn redacts(&self) -> Option<&Self::Id> {
|
||||||
match &self.rest {
|
match &self.rest {
|
||||||
| Pdu::RoomV1Pdu(ev) => ev.redacts.as_deref(),
|
| Pdu::RoomV1Pdu(ev) => ev.redacts.as_ref(),
|
||||||
| Pdu::RoomV3Pdu(ev) => ev.redacts.as_deref(),
|
| Pdu::RoomV3Pdu(ev) => ev.redacts.as_ref(),
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
||||||
| _ => unreachable!("new PDU version"),
|
| _ => unreachable!("new PDU version"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ pub fn auth_types_for_event(
|
|||||||
level = "debug",
|
level = "debug",
|
||||||
skip_all,
|
skip_all,
|
||||||
fields(
|
fields(
|
||||||
event_id = incoming_event.event_id().as_str(),
|
event_id = incoming_event.event_id().borrow().as_str()
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
pub async fn auth_check<F, Fut, Fetched, Incoming>(
|
pub async fn auth_check<F, Fut, Fetched, Incoming>(
|
||||||
@@ -259,7 +259,7 @@ where
|
|||||||
// 3. If event does not have m.room.create in auth_events reject
|
// 3. If event does not have m.room.create in auth_events reject
|
||||||
if !incoming_event
|
if !incoming_event
|
||||||
.auth_events()
|
.auth_events()
|
||||||
.any(|id| id == room_create_event.event_id())
|
.any(|id| id.borrow() == room_create_event.event_id().borrow())
|
||||||
{
|
{
|
||||||
warn!("no m.room.create event in auth events");
|
warn!("no m.room.create event in auth events");
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
@@ -638,7 +638,7 @@ fn valid_membership_change(
|
|||||||
warn!(?target_user_membership_event_id, "Banned user can't join");
|
warn!(?target_user_membership_event_id, "Banned user can't join");
|
||||||
false
|
false
|
||||||
} else if (join_rules == JoinRule::Invite
|
} else if (join_rules == JoinRule::Invite
|
||||||
|| room_version.allow_knocking && (join_rules == JoinRule::Knock || matches!(join_rules, JoinRule::KnockRestricted(_))))
|
|| room_version.allow_knocking && join_rules == JoinRule::Knock)
|
||||||
// If the join_rule is invite then allow if membership state is invite or join
|
// If the join_rule is invite then allow if membership state is invite or join
|
||||||
&& (target_user_current_membership == MembershipState::Join
|
&& (target_user_current_membership == MembershipState::Join
|
||||||
|| target_user_current_membership == MembershipState::Invite)
|
|| target_user_current_membership == MembershipState::Invite)
|
||||||
@@ -1021,11 +1021,11 @@ fn check_redaction(
|
|||||||
|
|
||||||
// If the domain of the event_id of the event being redacted is the same as the
|
// If the domain of the event_id of the event being redacted is the same as the
|
||||||
// domain of the event_id of the m.room.redaction, allow
|
// domain of the event_id of the m.room.redaction, allow
|
||||||
if redaction_event.event_id().server_name()
|
if redaction_event.event_id().borrow().server_name()
|
||||||
== redaction_event
|
== redaction_event
|
||||||
.redacts()
|
.redacts()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|&id| id.server_name())
|
.and_then(|&id| id.borrow().server_name())
|
||||||
{
|
{
|
||||||
debug!("redaction event allowed via room version 1 rules");
|
debug!("redaction event allowed via room version 1 rules");
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use std::{
|
|||||||
|
|
||||||
use futures::{Future, FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future};
|
use futures::{Future, FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
EventId, Int, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomVersionId,
|
EventId, Int, MilliSecondsSinceUnixEpoch, RoomVersionId,
|
||||||
events::{
|
events::{
|
||||||
StateEventType, TimelineEventType,
|
StateEventType, TimelineEventType,
|
||||||
room::member::{MembershipState, RoomMemberEventContent},
|
room::member::{MembershipState, RoomMemberEventContent},
|
||||||
@@ -39,7 +39,9 @@ use crate::{
|
|||||||
debug, debug_error,
|
debug, debug_error,
|
||||||
matrix::{event::Event, pdu::StateKey},
|
matrix::{event::Event, pdu::StateKey},
|
||||||
trace,
|
trace,
|
||||||
utils::stream::{BroadbandExt, IterStream, ReadyExt, TryBroadbandExt, WidebandExt},
|
utils::stream::{
|
||||||
|
BroadbandExt, IterStream, ReadyExt, TryBroadbandExt, TryReadyExt, WidebandExt,
|
||||||
|
},
|
||||||
warn,
|
warn,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,6 +69,9 @@ type Result<T, E = Error> = crate::Result<T, E>;
|
|||||||
/// * `event_fetch` - Any event not found in the `event_map` will defer to this
|
/// * `event_fetch` - Any event not found in the `event_map` will defer to this
|
||||||
/// closure to find the event.
|
/// closure to find the event.
|
||||||
///
|
///
|
||||||
|
/// * `parallel_fetches` - The number of asynchronous fetch requests in-flight
|
||||||
|
/// for any given operation.
|
||||||
|
///
|
||||||
/// ## Invariants
|
/// ## Invariants
|
||||||
///
|
///
|
||||||
/// The caller of `resolve` must ensure that all the events are from the same
|
/// The caller of `resolve` must ensure that all the events are from the same
|
||||||
@@ -77,19 +82,21 @@ type Result<T, E = Error> = crate::Result<T, E>;
|
|||||||
pub async fn resolve<'a, E, Sets, SetIter, Hasher, Fetch, FetchFut, Exists, ExistsFut>(
|
pub async fn resolve<'a, E, Sets, SetIter, Hasher, Fetch, FetchFut, Exists, ExistsFut>(
|
||||||
room_version: &RoomVersionId,
|
room_version: &RoomVersionId,
|
||||||
state_sets: Sets,
|
state_sets: Sets,
|
||||||
auth_chain_sets: &'a [HashSet<OwnedEventId, Hasher>],
|
auth_chain_sets: &'a [HashSet<E::Id, Hasher>],
|
||||||
event_fetch: &Fetch,
|
event_fetch: &Fetch,
|
||||||
event_exists: &Exists,
|
event_exists: &Exists,
|
||||||
) -> Result<StateMap<OwnedEventId>>
|
parallel_fetches: usize,
|
||||||
|
) -> Result<StateMap<E::Id>>
|
||||||
where
|
where
|
||||||
Fetch: Fn(OwnedEventId) -> FetchFut + Sync,
|
Fetch: Fn(E::Id) -> FetchFut + Sync,
|
||||||
FetchFut: Future<Output = Option<E>> + Send,
|
FetchFut: Future<Output = Option<E>> + Send,
|
||||||
Exists: Fn(OwnedEventId) -> ExistsFut + Sync,
|
Exists: Fn(E::Id) -> ExistsFut + Sync,
|
||||||
ExistsFut: Future<Output = bool> + Send,
|
ExistsFut: Future<Output = bool> + Send,
|
||||||
Sets: IntoIterator<IntoIter = SetIter> + Send,
|
Sets: IntoIterator<IntoIter = SetIter> + Send,
|
||||||
SetIter: Iterator<Item = &'a StateMap<OwnedEventId>> + Clone + Send,
|
SetIter: Iterator<Item = &'a StateMap<E::Id>> + Clone + Send,
|
||||||
Hasher: BuildHasher + Send + Sync,
|
Hasher: BuildHasher + Send + Sync,
|
||||||
E: Event + Clone + Send + Sync,
|
E: Event + Clone + Send + Sync,
|
||||||
|
E::Id: Borrow<EventId> + Send + Sync,
|
||||||
for<'b> &'b E: Send,
|
for<'b> &'b E: Send,
|
||||||
{
|
{
|
||||||
debug!("State resolution starting");
|
debug!("State resolution starting");
|
||||||
@@ -140,8 +147,13 @@ where
|
|||||||
|
|
||||||
// Sort the control events based on power_level/clock/event_id and
|
// Sort the control events based on power_level/clock/event_id and
|
||||||
// outgoing/incoming edges
|
// outgoing/incoming edges
|
||||||
let sorted_control_levels =
|
let sorted_control_levels = reverse_topological_power_sort(
|
||||||
reverse_topological_power_sort(control_events, &all_conflicted, &event_fetch).await?;
|
control_events,
|
||||||
|
&all_conflicted,
|
||||||
|
&event_fetch,
|
||||||
|
parallel_fetches,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
debug!(count = sorted_control_levels.len(), "power events");
|
debug!(count = sorted_control_levels.len(), "power events");
|
||||||
trace!(list = ?sorted_control_levels, "sorted power events");
|
trace!(list = ?sorted_control_levels, "sorted power events");
|
||||||
@@ -150,7 +162,7 @@ where
|
|||||||
// Sequentially auth check each control event.
|
// Sequentially auth check each control event.
|
||||||
let resolved_control = iterative_auth_check(
|
let resolved_control = iterative_auth_check(
|
||||||
&room_version,
|
&room_version,
|
||||||
sorted_control_levels.iter().stream().map(AsRef::as_ref),
|
sorted_control_levels.iter().stream(),
|
||||||
clean.clone(),
|
clean.clone(),
|
||||||
&event_fetch,
|
&event_fetch,
|
||||||
)
|
)
|
||||||
@@ -167,7 +179,7 @@ where
|
|||||||
// that failed auth
|
// that failed auth
|
||||||
let events_to_resolve: Vec<_> = all_conflicted
|
let events_to_resolve: Vec<_> = all_conflicted
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&id| !deduped_power_ev.contains(id))
|
.filter(|&id| !deduped_power_ev.contains(id.borrow()))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -187,7 +199,7 @@ where
|
|||||||
|
|
||||||
let mut resolved_state = iterative_auth_check(
|
let mut resolved_state = iterative_auth_check(
|
||||||
&room_version,
|
&room_version,
|
||||||
sorted_left_events.iter().stream().map(AsRef::as_ref),
|
sorted_left_events.iter().stream(),
|
||||||
resolved_control, // The control events are added to the final resolved state
|
resolved_control, // The control events are added to the final resolved state
|
||||||
&event_fetch,
|
&event_fetch,
|
||||||
)
|
)
|
||||||
@@ -280,14 +292,16 @@ where
|
|||||||
/// earlier (further back in time) origin server timestamp.
|
/// earlier (further back in time) origin server timestamp.
|
||||||
#[tracing::instrument(level = "debug", skip_all)]
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
async fn reverse_topological_power_sort<E, F, Fut>(
|
async fn reverse_topological_power_sort<E, F, Fut>(
|
||||||
events_to_sort: Vec<OwnedEventId>,
|
events_to_sort: Vec<E::Id>,
|
||||||
auth_diff: &HashSet<OwnedEventId>,
|
auth_diff: &HashSet<E::Id>,
|
||||||
fetch_event: &F,
|
fetch_event: &F,
|
||||||
) -> Result<Vec<OwnedEventId>>
|
parallel_fetches: usize,
|
||||||
|
) -> Result<Vec<E::Id>>
|
||||||
where
|
where
|
||||||
F: Fn(OwnedEventId) -> Fut + Sync,
|
F: Fn(E::Id) -> Fut + Sync,
|
||||||
Fut: Future<Output = Option<E>> + Send,
|
Fut: Future<Output = Option<E>> + Send,
|
||||||
E: Event + Send + Sync,
|
E: Event + Send + Sync,
|
||||||
|
E::Id: Borrow<EventId> + Send + Sync,
|
||||||
{
|
{
|
||||||
debug!("reverse topological sort of power events");
|
debug!("reverse topological sort of power events");
|
||||||
|
|
||||||
@@ -297,36 +311,35 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is used in the `key_fn` passed to the lexico_topo_sort fn
|
// This is used in the `key_fn` passed to the lexico_topo_sort fn
|
||||||
let event_to_pl: HashMap<_, _> = graph
|
let event_to_pl = graph
|
||||||
.keys()
|
.keys()
|
||||||
.cloned()
|
|
||||||
.stream()
|
.stream()
|
||||||
.broad_filter_map(async |event_id| {
|
.map(|event_id| {
|
||||||
let pl = get_power_level_for_sender(&event_id, fetch_event)
|
get_power_level_for_sender(event_id.clone(), fetch_event)
|
||||||
.await
|
.map(move |res| res.map(|pl| (event_id, pl)))
|
||||||
.ok()?;
|
|
||||||
Some((event_id, pl))
|
|
||||||
})
|
})
|
||||||
.inspect(|(event_id, pl)| {
|
.buffer_unordered(parallel_fetches)
|
||||||
|
.ready_try_fold(HashMap::new(), |mut event_to_pl, (event_id, pl)| {
|
||||||
debug!(
|
debug!(
|
||||||
event_id = event_id.as_str(),
|
event_id = event_id.borrow().as_str(),
|
||||||
power_level = i64::from(*pl),
|
power_level = i64::from(pl),
|
||||||
"found the power level of an event's sender",
|
"found the power level of an event's sender",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
event_to_pl.insert(event_id.clone(), pl);
|
||||||
|
Ok(event_to_pl)
|
||||||
})
|
})
|
||||||
.collect()
|
|
||||||
.boxed()
|
.boxed()
|
||||||
.await;
|
.await?;
|
||||||
|
|
||||||
let fetcher = async |event_id: OwnedEventId| {
|
let event_to_pl = &event_to_pl;
|
||||||
|
let fetcher = |event_id: E::Id| async move {
|
||||||
let pl = *event_to_pl
|
let pl = *event_to_pl
|
||||||
.get(&event_id)
|
.get(event_id.borrow())
|
||||||
.ok_or_else(|| Error::NotFound(String::new()))?;
|
.ok_or_else(|| Error::NotFound(String::new()))?;
|
||||||
|
|
||||||
let ev = fetch_event(event_id)
|
let ev = fetch_event(event_id)
|
||||||
.await
|
.await
|
||||||
.ok_or_else(|| Error::NotFound(String::new()))?;
|
.ok_or_else(|| Error::NotFound(String::new()))?;
|
||||||
|
|
||||||
Ok((pl, ev.origin_server_ts()))
|
Ok((pl, ev.origin_server_ts()))
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -463,17 +476,18 @@ where
|
|||||||
/// the eventId at the eventId's generation (we walk backwards to `EventId`s
|
/// the eventId at the eventId's generation (we walk backwards to `EventId`s
|
||||||
/// most recent previous power level event).
|
/// most recent previous power level event).
|
||||||
async fn get_power_level_for_sender<E, F, Fut>(
|
async fn get_power_level_for_sender<E, F, Fut>(
|
||||||
event_id: &EventId,
|
event_id: E::Id,
|
||||||
fetch_event: &F,
|
fetch_event: &F,
|
||||||
) -> serde_json::Result<Int>
|
) -> serde_json::Result<Int>
|
||||||
where
|
where
|
||||||
F: Fn(OwnedEventId) -> Fut + Sync,
|
F: Fn(E::Id) -> Fut + Sync,
|
||||||
Fut: Future<Output = Option<E>> + Send,
|
Fut: Future<Output = Option<E>> + Send,
|
||||||
E: Event + Send,
|
E: Event + Send,
|
||||||
|
E::Id: Borrow<EventId> + Send,
|
||||||
{
|
{
|
||||||
debug!("fetch event ({event_id}) senders power level");
|
debug!("fetch event ({event_id}) senders power level");
|
||||||
|
|
||||||
let event = fetch_event(event_id.to_owned()).await;
|
let event = fetch_event(event_id).await;
|
||||||
|
|
||||||
let auth_events = event.as_ref().map(Event::auth_events);
|
let auth_events = event.as_ref().map(Event::auth_events);
|
||||||
|
|
||||||
@@ -481,7 +495,7 @@ where
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.stream()
|
.stream()
|
||||||
.broadn_filter_map(5, |aid| fetch_event(aid.to_owned()))
|
.broadn_filter_map(5, |aid| fetch_event(aid.clone()))
|
||||||
.ready_find(|aev| is_type_and_key(aev, &TimelineEventType::RoomPowerLevels, ""))
|
.ready_find(|aev| is_type_and_key(aev, &TimelineEventType::RoomPowerLevels, ""))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@@ -514,13 +528,14 @@ where
|
|||||||
async fn iterative_auth_check<'a, E, F, Fut, S>(
|
async fn iterative_auth_check<'a, E, F, Fut, S>(
|
||||||
room_version: &RoomVersion,
|
room_version: &RoomVersion,
|
||||||
events_to_check: S,
|
events_to_check: S,
|
||||||
unconflicted_state: StateMap<OwnedEventId>,
|
unconflicted_state: StateMap<E::Id>,
|
||||||
fetch_event: &F,
|
fetch_event: &F,
|
||||||
) -> Result<StateMap<OwnedEventId>>
|
) -> Result<StateMap<E::Id>>
|
||||||
where
|
where
|
||||||
F: Fn(OwnedEventId) -> Fut + Sync,
|
F: Fn(E::Id) -> Fut + Sync,
|
||||||
Fut: Future<Output = Option<E>> + Send,
|
Fut: Future<Output = Option<E>> + Send,
|
||||||
S: Stream<Item = &'a EventId> + Send + 'a,
|
E::Id: Borrow<EventId> + Clone + Eq + Ord + Send + Sync + 'a,
|
||||||
|
S: Stream<Item = &'a E::Id> + Send + 'a,
|
||||||
E: Event + Clone + Send + Sync,
|
E: Event + Clone + Send + Sync,
|
||||||
{
|
{
|
||||||
debug!("starting iterative auth check");
|
debug!("starting iterative auth check");
|
||||||
@@ -528,7 +543,7 @@ where
|
|||||||
let events_to_check: Vec<_> = events_to_check
|
let events_to_check: Vec<_> = events_to_check
|
||||||
.map(Result::Ok)
|
.map(Result::Ok)
|
||||||
.broad_and_then(async |event_id| {
|
.broad_and_then(async |event_id| {
|
||||||
fetch_event(event_id.to_owned())
|
fetch_event(event_id.clone())
|
||||||
.await
|
.await
|
||||||
.ok_or_else(|| Error::NotFound(format!("Failed to find {event_id}")))
|
.ok_or_else(|| Error::NotFound(format!("Failed to find {event_id}")))
|
||||||
})
|
})
|
||||||
@@ -536,16 +551,16 @@ where
|
|||||||
.boxed()
|
.boxed()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let auth_event_ids: HashSet<OwnedEventId> = events_to_check
|
let auth_event_ids: HashSet<E::Id> = events_to_check
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|event: &E| event.auth_events().map(ToOwned::to_owned))
|
.flat_map(|event: &E| event.auth_events().map(Clone::clone))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let auth_events: HashMap<OwnedEventId, E> = auth_event_ids
|
let auth_events: HashMap<E::Id, E> = auth_event_ids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.stream()
|
.stream()
|
||||||
.broad_filter_map(fetch_event)
|
.broad_filter_map(fetch_event)
|
||||||
.map(|auth_event| (auth_event.event_id().to_owned(), auth_event))
|
.map(|auth_event| (auth_event.event_id().clone(), auth_event))
|
||||||
.collect()
|
.collect()
|
||||||
.boxed()
|
.boxed()
|
||||||
.await;
|
.await;
|
||||||
@@ -566,7 +581,7 @@ where
|
|||||||
|
|
||||||
let mut auth_state = StateMap::new();
|
let mut auth_state = StateMap::new();
|
||||||
for aid in event.auth_events() {
|
for aid in event.auth_events() {
|
||||||
if let Some(ev) = auth_events.get(aid) {
|
if let Some(ev) = auth_events.get(aid.borrow()) {
|
||||||
//TODO: synapse checks "rejected_reason" which is most likely related to
|
//TODO: synapse checks "rejected_reason" which is most likely related to
|
||||||
// soft-failing
|
// soft-failing
|
||||||
auth_state.insert(
|
auth_state.insert(
|
||||||
@@ -577,7 +592,7 @@ where
|
|||||||
ev.clone(),
|
ev.clone(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
warn!(event_id = aid.as_str(), "missing auth event");
|
warn!(event_id = aid.borrow().as_str(), "missing auth event");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,7 +601,7 @@ where
|
|||||||
.stream()
|
.stream()
|
||||||
.ready_filter_map(|key| Some((key, resolved_state.get(key)?)))
|
.ready_filter_map(|key| Some((key, resolved_state.get(key)?)))
|
||||||
.filter_map(|(key, ev_id)| async move {
|
.filter_map(|(key, ev_id)| async move {
|
||||||
if let Some(event) = auth_events.get(ev_id) {
|
if let Some(event) = auth_events.get(ev_id.borrow()) {
|
||||||
Some((key, event.clone()))
|
Some((key, event.clone()))
|
||||||
} else {
|
} else {
|
||||||
Some((key, fetch_event(ev_id.clone()).await?))
|
Some((key, fetch_event(ev_id.clone()).await?))
|
||||||
@@ -618,7 +633,7 @@ where
|
|||||||
// add event to resolved state map
|
// add event to resolved state map
|
||||||
resolved_state.insert(
|
resolved_state.insert(
|
||||||
event.event_type().with_state_key(state_key),
|
event.event_type().with_state_key(state_key),
|
||||||
event.event_id().to_owned(),
|
event.event_id().clone(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
| Ok(false) => {
|
| Ok(false) => {
|
||||||
@@ -645,14 +660,15 @@ where
|
|||||||
/// level as a parent) will be marked as depth 1. depth 1 is "older" than depth
|
/// level as a parent) will be marked as depth 1. depth 1 is "older" than depth
|
||||||
/// 0.
|
/// 0.
|
||||||
async fn mainline_sort<E, F, Fut>(
|
async fn mainline_sort<E, F, Fut>(
|
||||||
to_sort: &[OwnedEventId],
|
to_sort: &[E::Id],
|
||||||
resolved_power_level: Option<OwnedEventId>,
|
resolved_power_level: Option<E::Id>,
|
||||||
fetch_event: &F,
|
fetch_event: &F,
|
||||||
) -> Result<Vec<OwnedEventId>>
|
) -> Result<Vec<E::Id>>
|
||||||
where
|
where
|
||||||
F: Fn(OwnedEventId) -> Fut + Sync,
|
F: Fn(E::Id) -> Fut + Sync,
|
||||||
Fut: Future<Output = Option<E>> + Send,
|
Fut: Future<Output = Option<E>> + Send,
|
||||||
E: Event + Clone + Send + Sync,
|
E: Event + Clone + Send + Sync,
|
||||||
|
E::Id: Borrow<EventId> + Clone + Send + Sync,
|
||||||
{
|
{
|
||||||
debug!("mainline sort of events");
|
debug!("mainline sort of events");
|
||||||
|
|
||||||
@@ -672,7 +688,7 @@ where
|
|||||||
|
|
||||||
pl = None;
|
pl = None;
|
||||||
for aid in event.auth_events() {
|
for aid in event.auth_events() {
|
||||||
let ev = fetch_event(aid.to_owned())
|
let ev = fetch_event(aid.clone())
|
||||||
.await
|
.await
|
||||||
.ok_or_else(|| Error::NotFound(format!("Failed to find {aid}")))?;
|
.ok_or_else(|| Error::NotFound(format!("Failed to find {aid}")))?;
|
||||||
|
|
||||||
@@ -718,25 +734,26 @@ where
|
|||||||
/// that has an associated mainline depth.
|
/// that has an associated mainline depth.
|
||||||
async fn get_mainline_depth<E, F, Fut>(
|
async fn get_mainline_depth<E, F, Fut>(
|
||||||
mut event: Option<E>,
|
mut event: Option<E>,
|
||||||
mainline_map: &HashMap<OwnedEventId, usize>,
|
mainline_map: &HashMap<E::Id, usize>,
|
||||||
fetch_event: &F,
|
fetch_event: &F,
|
||||||
) -> Result<usize>
|
) -> Result<usize>
|
||||||
where
|
where
|
||||||
F: Fn(OwnedEventId) -> Fut + Sync,
|
F: Fn(E::Id) -> Fut + Sync,
|
||||||
Fut: Future<Output = Option<E>> + Send,
|
Fut: Future<Output = Option<E>> + Send,
|
||||||
E: Event + Send + Sync,
|
E: Event + Send + Sync,
|
||||||
|
E::Id: Borrow<EventId> + Send + Sync,
|
||||||
{
|
{
|
||||||
while let Some(sort_ev) = event {
|
while let Some(sort_ev) = event {
|
||||||
debug!(event_id = sort_ev.event_id().as_str(), "mainline");
|
debug!(event_id = sort_ev.event_id().borrow().as_str(), "mainline");
|
||||||
|
|
||||||
let id = sort_ev.event_id();
|
let id = sort_ev.event_id();
|
||||||
if let Some(depth) = mainline_map.get(id) {
|
if let Some(depth) = mainline_map.get(id.borrow()) {
|
||||||
return Ok(*depth);
|
return Ok(*depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
event = None;
|
event = None;
|
||||||
for aid in sort_ev.auth_events() {
|
for aid in sort_ev.auth_events() {
|
||||||
let aev = fetch_event(aid.to_owned())
|
let aev = fetch_event(aid.clone())
|
||||||
.await
|
.await
|
||||||
.ok_or_else(|| Error::NotFound(format!("Failed to find {aid}")))?;
|
.ok_or_else(|| Error::NotFound(format!("Failed to find {aid}")))?;
|
||||||
|
|
||||||
@@ -751,14 +768,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn add_event_and_auth_chain_to_graph<E, F, Fut>(
|
async fn add_event_and_auth_chain_to_graph<E, F, Fut>(
|
||||||
graph: &mut HashMap<OwnedEventId, HashSet<OwnedEventId>>,
|
graph: &mut HashMap<E::Id, HashSet<E::Id>>,
|
||||||
event_id: OwnedEventId,
|
event_id: E::Id,
|
||||||
auth_diff: &HashSet<OwnedEventId>,
|
auth_diff: &HashSet<E::Id>,
|
||||||
fetch_event: &F,
|
fetch_event: &F,
|
||||||
) where
|
) where
|
||||||
F: Fn(OwnedEventId) -> Fut + Sync,
|
F: Fn(E::Id) -> Fut + Sync,
|
||||||
Fut: Future<Output = Option<E>> + Send,
|
Fut: Future<Output = Option<E>> + Send,
|
||||||
E: Event + Send + Sync,
|
E: Event + Send + Sync,
|
||||||
|
E::Id: Borrow<EventId> + Clone + Send + Sync,
|
||||||
{
|
{
|
||||||
let mut state = vec![event_id];
|
let mut state = vec![event_id];
|
||||||
while let Some(eid) = state.pop() {
|
while let Some(eid) = state.pop() {
|
||||||
@@ -768,27 +786,26 @@ async fn add_event_and_auth_chain_to_graph<E, F, Fut>(
|
|||||||
|
|
||||||
// Prefer the store to event as the store filters dedups the events
|
// Prefer the store to event as the store filters dedups the events
|
||||||
for aid in auth_events {
|
for aid in auth_events {
|
||||||
if auth_diff.contains(aid) {
|
if auth_diff.contains(aid.borrow()) {
|
||||||
if !graph.contains_key(aid) {
|
if !graph.contains_key(aid.borrow()) {
|
||||||
state.push(aid.to_owned());
|
state.push(aid.to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
graph
|
// We just inserted this at the start of the while loop
|
||||||
.get_mut(&eid)
|
graph.get_mut(eid.borrow()).unwrap().insert(aid.to_owned());
|
||||||
.expect("We just inserted this at the start of the while loop")
|
|
||||||
.insert(aid.to_owned());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_power_event_id<E, F, Fut>(event_id: &EventId, fetch: &F) -> bool
|
async fn is_power_event_id<E, F, Fut>(event_id: &E::Id, fetch: &F) -> bool
|
||||||
where
|
where
|
||||||
F: Fn(OwnedEventId) -> Fut + Sync,
|
F: Fn(E::Id) -> Fut + Sync,
|
||||||
Fut: Future<Output = Option<E>> + Send,
|
Fut: Future<Output = Option<E>> + Send,
|
||||||
E: Event + Send,
|
E: Event + Send,
|
||||||
|
E::Id: Borrow<EventId> + Send + Sync,
|
||||||
{
|
{
|
||||||
match fetch(event_id.to_owned()).await.as_ref() {
|
match fetch(event_id.clone()).await.as_ref() {
|
||||||
| Some(state) => is_power_event(state),
|
| Some(state) => is_power_event(state),
|
||||||
| _ => false,
|
| _ => false,
|
||||||
}
|
}
|
||||||
@@ -892,13 +909,13 @@ mod tests {
|
|||||||
|
|
||||||
let fetcher = |id| ready(events.get(&id).cloned());
|
let fetcher = |id| ready(events.get(&id).cloned());
|
||||||
let sorted_power_events =
|
let sorted_power_events =
|
||||||
super::reverse_topological_power_sort(power_events, &auth_chain, &fetcher)
|
super::reverse_topological_power_sort(power_events, &auth_chain, &fetcher, 1)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let resolved_power = super::iterative_auth_check(
|
let resolved_power = super::iterative_auth_check(
|
||||||
&RoomVersion::V6,
|
&RoomVersion::V6,
|
||||||
sorted_power_events.iter().map(AsRef::as_ref).stream(),
|
sorted_power_events.iter().stream(),
|
||||||
HashMap::new(), // unconflicted events
|
HashMap::new(), // unconflicted events
|
||||||
&fetcher,
|
&fetcher,
|
||||||
)
|
)
|
||||||
@@ -1283,7 +1300,7 @@ mod tests {
|
|||||||
let ev_map = store.0.clone();
|
let ev_map = store.0.clone();
|
||||||
let fetcher = |id| ready(ev_map.get(&id).cloned());
|
let fetcher = |id| ready(ev_map.get(&id).cloned());
|
||||||
|
|
||||||
let exists = |id: OwnedEventId| ready(ev_map.get(&*id).is_some());
|
let exists = |id: <PduEvent as Event>::Id| ready(ev_map.get(&*id).is_some());
|
||||||
|
|
||||||
let state_sets = [state_at_bob, state_at_charlie];
|
let state_sets = [state_at_bob, state_at_charlie];
|
||||||
let auth_chain: Vec<_> = state_sets
|
let auth_chain: Vec<_> = state_sets
|
||||||
@@ -1295,13 +1312,19 @@ mod tests {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let resolved =
|
let resolved = match super::resolve(
|
||||||
match super::resolve(&RoomVersionId::V2, &state_sets, &auth_chain, &fetcher, &exists)
|
&RoomVersionId::V2,
|
||||||
.await
|
&state_sets,
|
||||||
{
|
&auth_chain,
|
||||||
| Ok(state) => state,
|
&fetcher,
|
||||||
| Err(e) => panic!("{e}"),
|
&exists,
|
||||||
};
|
1,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
| Ok(state) => state,
|
||||||
|
| Err(e) => panic!("{e}"),
|
||||||
|
};
|
||||||
|
|
||||||
assert_eq!(expected, resolved);
|
assert_eq!(expected, resolved);
|
||||||
}
|
}
|
||||||
@@ -1406,15 +1429,21 @@ mod tests {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let fetcher = |id: OwnedEventId| ready(ev_map.get(&id).cloned());
|
let fetcher = |id: <PduEvent as Event>::Id| ready(ev_map.get(&id).cloned());
|
||||||
let exists = |id: OwnedEventId| ready(ev_map.get(&id).is_some());
|
let exists = |id: <PduEvent as Event>::Id| ready(ev_map.get(&id).is_some());
|
||||||
let resolved =
|
let resolved = match super::resolve(
|
||||||
match super::resolve(&RoomVersionId::V6, &state_sets, &auth_chain, &fetcher, &exists)
|
&RoomVersionId::V6,
|
||||||
.await
|
&state_sets,
|
||||||
{
|
&auth_chain,
|
||||||
| Ok(state) => state,
|
&fetcher,
|
||||||
| Err(e) => panic!("{e}"),
|
&exists,
|
||||||
};
|
1,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
| Ok(state) => state,
|
||||||
|
| Err(e) => panic!("{e}"),
|
||||||
|
};
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
resolved = ?resolved
|
resolved = ?resolved
|
||||||
|
|||||||
@@ -133,11 +133,17 @@ pub(crate) async fn do_check(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let event_map = &event_map;
|
let event_map = &event_map;
|
||||||
let fetch = |id: OwnedEventId| ready(event_map.get(&id).cloned());
|
let fetch = |id: <PduEvent as Event>::Id| ready(event_map.get(&id).cloned());
|
||||||
let exists = |id: OwnedEventId| ready(event_map.get(&id).is_some());
|
let exists = |id: <PduEvent as Event>::Id| ready(event_map.get(&id).is_some());
|
||||||
let resolved =
|
let resolved = super::resolve(
|
||||||
super::resolve(&RoomVersionId::V6, state_sets, &auth_chain_sets, &fetch, &exists)
|
&RoomVersionId::V6,
|
||||||
.await;
|
state_sets,
|
||||||
|
&auth_chain_sets,
|
||||||
|
&fetch,
|
||||||
|
&exists,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
match resolved {
|
match resolved {
|
||||||
| Ok(state) => state,
|
| Ok(state) => state,
|
||||||
@@ -241,8 +247,8 @@ impl<E: Event + Clone> TestStore<E> {
|
|||||||
pub(crate) fn auth_event_ids(
|
pub(crate) fn auth_event_ids(
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
event_ids: Vec<OwnedEventId>,
|
event_ids: Vec<E::Id>,
|
||||||
) -> Result<HashSet<OwnedEventId>> {
|
) -> Result<HashSet<E::Id>> {
|
||||||
let mut result = HashSet::new();
|
let mut result = HashSet::new();
|
||||||
let mut stack = event_ids;
|
let mut stack = event_ids;
|
||||||
|
|
||||||
@@ -578,7 +584,7 @@ pub(crate) fn INITIAL_EDGES() -> Vec<OwnedEventId> {
|
|||||||
|
|
||||||
pub(crate) mod event {
|
pub(crate) mod event {
|
||||||
use ruma::{
|
use ruma::{
|
||||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId,
|
MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId,
|
||||||
events::{TimelineEventType, pdu::Pdu},
|
events::{TimelineEventType, pdu::Pdu},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -587,7 +593,9 @@ pub(crate) mod event {
|
|||||||
use crate::Event;
|
use crate::Event;
|
||||||
|
|
||||||
impl Event for PduEvent {
|
impl Event for PduEvent {
|
||||||
fn event_id(&self) -> &EventId { &self.event_id }
|
type Id = OwnedEventId;
|
||||||
|
|
||||||
|
fn event_id(&self) -> &Self::Id { &self.event_id }
|
||||||
|
|
||||||
fn room_id(&self) -> &RoomId {
|
fn room_id(&self) -> &RoomId {
|
||||||
match &self.rest {
|
match &self.rest {
|
||||||
@@ -644,31 +652,29 @@ pub(crate) mod event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(refining_impl_trait)]
|
#[allow(refining_impl_trait)]
|
||||||
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
|
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &Self::Id> + Send + '_> {
|
||||||
match &self.rest {
|
match &self.rest {
|
||||||
| Pdu::RoomV1Pdu(ev) =>
|
| Pdu::RoomV1Pdu(ev) => Box::new(ev.prev_events.iter().map(|(id, _)| id)),
|
||||||
Box::new(ev.prev_events.iter().map(|(id, _)| id.as_ref())),
|
| Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter()),
|
||||||
| Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter().map(AsRef::as_ref)),
|
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
| _ => unreachable!("new PDU version"),
|
| _ => unreachable!("new PDU version"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(refining_impl_trait)]
|
#[allow(refining_impl_trait)]
|
||||||
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
|
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &Self::Id> + Send + '_> {
|
||||||
match &self.rest {
|
match &self.rest {
|
||||||
| Pdu::RoomV1Pdu(ev) =>
|
| Pdu::RoomV1Pdu(ev) => Box::new(ev.auth_events.iter().map(|(id, _)| id)),
|
||||||
Box::new(ev.auth_events.iter().map(|(id, _)| id.as_ref())),
|
| Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter()),
|
||||||
| Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter().map(AsRef::as_ref)),
|
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
| _ => unreachable!("new PDU version"),
|
| _ => unreachable!("new PDU version"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redacts(&self) -> Option<&EventId> {
|
fn redacts(&self) -> Option<&Self::Id> {
|
||||||
match &self.rest {
|
match &self.rest {
|
||||||
| Pdu::RoomV1Pdu(ev) => ev.redacts.as_deref(),
|
| Pdu::RoomV1Pdu(ev) => ev.redacts.as_ref(),
|
||||||
| Pdu::RoomV3Pdu(ev) => ev.redacts.as_deref(),
|
| Pdu::RoomV3Pdu(ev) => ev.redacts.as_ref(),
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
| _ => unreachable!("new PDU version"),
|
| _ => unreachable!("new PDU version"),
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-4
@@ -21,10 +21,7 @@ pub use ::toml;
|
|||||||
pub use ::tracing;
|
pub use ::tracing;
|
||||||
pub use config::Config;
|
pub use config::Config;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use info::{
|
pub use info::{rustc_flags_capture, version, version::version};
|
||||||
rustc_flags_capture, version,
|
|
||||||
version::{name, version},
|
|
||||||
};
|
|
||||||
pub use matrix::{Event, EventTypeExt, PduCount, PduEvent, PduId, RoomVersion, pdu, state_res};
|
pub use matrix::{Event, EventTypeExt, PduCount, PduEvent, PduId, RoomVersion, pdu, state_res};
|
||||||
pub use server::Server;
|
pub use server::Server;
|
||||||
pub use utils::{ctor, dtor, implement, result, result::Result};
|
pub use utils::{ctor, dtor, implement, result, result::Result};
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ default = [
|
|||||||
"io_uring",
|
"io_uring",
|
||||||
"jemalloc",
|
"jemalloc",
|
||||||
"jemalloc_conf",
|
"jemalloc_conf",
|
||||||
"journald",
|
|
||||||
"media_thumbnail",
|
"media_thumbnail",
|
||||||
"release_max_log_level",
|
"release_max_log_level",
|
||||||
"systemd",
|
"systemd",
|
||||||
@@ -131,11 +130,6 @@ sentry_telemetry = [
|
|||||||
systemd = [
|
systemd = [
|
||||||
"conduwuit-router/systemd",
|
"conduwuit-router/systemd",
|
||||||
]
|
]
|
||||||
journald = [ # This is a stub on non-unix platforms
|
|
||||||
"dep:tracing-journald",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# enable the tokio_console server ncompatible with release_max_log_level
|
# enable the tokio_console server ncompatible with release_max_log_level
|
||||||
tokio_console = [
|
tokio_console = [
|
||||||
"dep:console-subscriber",
|
"dep:console-subscriber",
|
||||||
@@ -189,7 +183,6 @@ tracing-opentelemetry.optional = true
|
|||||||
tracing-opentelemetry.workspace = true
|
tracing-opentelemetry.workspace = true
|
||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-journald = { workspace = true, optional = true }
|
|
||||||
|
|
||||||
[target.'cfg(all(not(target_env = "msvc"), target_os = "linux"))'.dependencies]
|
[target.'cfg(all(not(target_env = "msvc"), target_os = "linux"))'.dependencies]
|
||||||
hardened_malloc-rs.workspace = true
|
hardened_malloc-rs.workspace = true
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ use conduwuit_core::{
|
|||||||
#[clap(
|
#[clap(
|
||||||
about,
|
about,
|
||||||
long_about = None,
|
long_about = None,
|
||||||
name = conduwuit_core::name(),
|
name = "conduwuit",
|
||||||
version = conduwuit_core::version(),
|
version = conduwuit_core::version(),
|
||||||
)]
|
)]
|
||||||
pub(crate) struct Args {
|
pub(crate) struct Args {
|
||||||
|
|||||||
+1
-36
@@ -43,16 +43,6 @@ pub(crate) fn init(
|
|||||||
.with(console_layer.with_filter(console_reload_filter))
|
.with(console_layer.with_filter(console_reload_filter))
|
||||||
.with(cap_layer);
|
.with(cap_layer);
|
||||||
|
|
||||||
// If journald logging is enabled on Unix platforms, create a separate
|
|
||||||
// subscriber for it
|
|
||||||
#[cfg(all(target_family = "unix", feature = "journald"))]
|
|
||||||
if config.log_to_journald {
|
|
||||||
println!("Initialising journald logging");
|
|
||||||
if let Err(e) = init_journald_logging(config) {
|
|
||||||
eprintln!("Failed to initialize journald logging: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "sentry_telemetry")]
|
#[cfg(feature = "sentry_telemetry")]
|
||||||
let subscriber = {
|
let subscriber = {
|
||||||
let sentry_filter = EnvFilter::try_new(&config.sentry_filter)
|
let sentry_filter = EnvFilter::try_new(&config.sentry_filter)
|
||||||
@@ -132,28 +122,6 @@ pub(crate) fn init(
|
|||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_family = "unix", feature = "journald"))]
|
|
||||||
fn init_journald_logging(config: &Config) -> Result<()> {
|
|
||||||
use tracing_journald::Layer as JournaldLayer;
|
|
||||||
|
|
||||||
let journald_filter =
|
|
||||||
EnvFilter::try_new(&config.log).map_err(|e| err!(Config("log", "{e}.")))?;
|
|
||||||
|
|
||||||
let mut journald_layer = JournaldLayer::new()
|
|
||||||
.map_err(|e| err!(Config("journald", "Failed to initialize journald layer: {e}.")))?;
|
|
||||||
|
|
||||||
if let Some(ref identifier) = config.journald_identifier {
|
|
||||||
journald_layer = journald_layer.with_syslog_identifier(identifier.to_owned());
|
|
||||||
}
|
|
||||||
|
|
||||||
let journald_subscriber =
|
|
||||||
Registry::default().with(journald_layer.with_filter(journald_filter));
|
|
||||||
|
|
||||||
let _guard = tracing::subscriber::set_default(journald_subscriber);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tokio_console_enabled(config: &Config) -> (bool, &'static str) {
|
fn tokio_console_enabled(config: &Config) -> (bool, &'static str) {
|
||||||
if !cfg!(all(feature = "tokio_console", tokio_unstable)) {
|
if !cfg!(all(feature = "tokio_console", tokio_unstable)) {
|
||||||
return (false, "");
|
return (false, "");
|
||||||
@@ -173,10 +141,7 @@ fn tokio_console_enabled(config: &Config) -> (bool, &'static str) {
|
|||||||
(true, "")
|
(true, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_global_default<S>(subscriber: S)
|
fn set_global_default<S: SubscriberExt + Send + Sync>(subscriber: S) {
|
||||||
where
|
|
||||||
S: tracing::Subscriber + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
tracing::subscriber::set_global_default(subscriber)
|
tracing::subscriber::set_global_default(subscriber)
|
||||||
.expect("the global default tracing subscriber failed to be initialized");
|
.expect("the global default tracing subscriber failed to be initialized");
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-12
@@ -98,7 +98,12 @@ pub(super) fn shutdown(server: &Arc<Server>, runtime: tokio::runtime::Runtime) {
|
|||||||
Level::INFO
|
Level::INFO
|
||||||
};
|
};
|
||||||
|
|
||||||
wait_shutdown(server, runtime);
|
debug!(
|
||||||
|
timeout = ?SHUTDOWN_TIMEOUT,
|
||||||
|
"Waiting for runtime..."
|
||||||
|
);
|
||||||
|
|
||||||
|
runtime.shutdown_timeout(SHUTDOWN_TIMEOUT);
|
||||||
let runtime_metrics = server.server.metrics.runtime_interval().unwrap_or_default();
|
let runtime_metrics = server.server.metrics.runtime_interval().unwrap_or_default();
|
||||||
|
|
||||||
event!(LEVEL, ?runtime_metrics, "Final runtime metrics");
|
event!(LEVEL, ?runtime_metrics, "Final runtime metrics");
|
||||||
@@ -106,23 +111,13 @@ pub(super) fn shutdown(server: &Arc<Server>, runtime: tokio::runtime::Runtime) {
|
|||||||
|
|
||||||
#[cfg(not(tokio_unstable))]
|
#[cfg(not(tokio_unstable))]
|
||||||
#[tracing::instrument(name = "stop", level = "info", skip_all)]
|
#[tracing::instrument(name = "stop", level = "info", skip_all)]
|
||||||
pub(super) fn shutdown(server: &Arc<Server>, runtime: tokio::runtime::Runtime) {
|
pub(super) fn shutdown(_server: &Arc<Server>, runtime: tokio::runtime::Runtime) {
|
||||||
wait_shutdown(server, runtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wait_shutdown(_server: &Arc<Server>, runtime: tokio::runtime::Runtime) {
|
|
||||||
debug!(
|
debug!(
|
||||||
timeout = ?SHUTDOWN_TIMEOUT,
|
timeout = ?SHUTDOWN_TIMEOUT,
|
||||||
"Waiting for runtime..."
|
"Waiting for runtime..."
|
||||||
);
|
);
|
||||||
|
|
||||||
runtime.shutdown_timeout(SHUTDOWN_TIMEOUT);
|
runtime.shutdown_timeout(SHUTDOWN_TIMEOUT);
|
||||||
|
|
||||||
// Join any jemalloc threads so they don't appear in use at exit.
|
|
||||||
#[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))]
|
|
||||||
conduwuit_core::alloc::je::background_thread_enable(false)
|
|
||||||
.log_debug_err()
|
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(
|
#[tracing::instrument(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use conduwuit::{
|
|||||||
Error, Result, err, implement,
|
Error, Result, err, implement,
|
||||||
state_res::{self, StateMap},
|
state_res::{self, StateMap},
|
||||||
trace,
|
trace,
|
||||||
utils::stream::{IterStream, ReadyExt, TryWidebandExt, WidebandExt},
|
utils::stream::{IterStream, ReadyExt, TryWidebandExt, WidebandExt, automatic_width},
|
||||||
};
|
};
|
||||||
use futures::{FutureExt, StreamExt, TryFutureExt, TryStreamExt, future::try_join};
|
use futures::{FutureExt, StreamExt, TryFutureExt, TryStreamExt, future::try_join};
|
||||||
use ruma::{OwnedEventId, RoomId, RoomVersionId};
|
use ruma::{OwnedEventId, RoomId, RoomVersionId};
|
||||||
@@ -112,7 +112,14 @@ where
|
|||||||
{
|
{
|
||||||
let event_fetch = |event_id| self.event_fetch(event_id);
|
let event_fetch = |event_id| self.event_fetch(event_id);
|
||||||
let event_exists = |event_id| self.event_exists(event_id);
|
let event_exists = |event_id| self.event_exists(event_id);
|
||||||
state_res::resolve(room_version, state_sets, auth_chain_sets, &event_fetch, &event_exists)
|
state_res::resolve(
|
||||||
.map_err(|e| err!(error!("State resolution failed: {e:?}")))
|
room_version,
|
||||||
.await
|
state_sets,
|
||||||
|
auth_chain_sets,
|
||||||
|
&event_fetch,
|
||||||
|
&event_exists,
|
||||||
|
automatic_width(),
|
||||||
|
)
|
||||||
|
.map_err(|e| err!(error!("State resolution failed: {e:?}")))
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
+64
-47
@@ -1,68 +1,85 @@
|
|||||||
:root {
|
:root {
|
||||||
color-scheme: light;
|
color-scheme: light;
|
||||||
--font-stack: sans-serif;
|
--font-stack: sans-serif;
|
||||||
|
|
||||||
--background-color: #fff;
|
--background-color: #fff;
|
||||||
--text-color: #000;
|
--text-color: #000;
|
||||||
|
|
||||||
--bg: oklch(0.76 0.0854 317.27);
|
--bg: oklch(0.76 0.0854 317.27);
|
||||||
--panel-bg: oklch(0.91 0.042 317.27);
|
--panel-bg: oklch(0.91 0.042 317.27);
|
||||||
|
|
||||||
--name-lightness: 0.45;
|
--name-lightness: 0.45;
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
--text-color: #fff;
|
--text-color: #fff;
|
||||||
--bg: oklch(0.15 0.042 317.27);
|
--bg: oklch(0.15 0.042 317.27);
|
||||||
--panel-bg: oklch(0.24 0.03 317.27);
|
--panel-bg: oklch(0.24 0.03 317.27);
|
||||||
|
|
||||||
--name-lightness: 0.8;
|
--name-lightness: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
--c1: oklch(0.44 0.177 353.06);
|
--c1: oklch(0.44 0.177 353.06);
|
||||||
--c2: oklch(0.59 0.158 150.88);
|
--c2: oklch(0.59 0.158 150.88);
|
||||||
|
|
||||||
--normal-font-size: 1rem;
|
--normal-font-size: 1rem;
|
||||||
--small-font-size: 0.8rem;
|
--small-font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
font-family: var(--font-stack);
|
font-family: var(--font-stack);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
background-color: var(--bg);
|
background-color: var(--bg);
|
||||||
background-image: linear-gradient(
|
background-image: linear-gradient(
|
||||||
70deg,
|
70deg,
|
||||||
oklch(from var(--bg) l + 0.2 c h),
|
oklch(from var(--bg) l + 0.2 c h),
|
||||||
oklch(from var(--bg) l - 0.2 c h)
|
oklch(from var(--bg) l - 0.2 c h)
|
||||||
);
|
);
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
width: min(clamp(24rem, 12rem + 40vw, 48rem), 100vw);
|
width: min(clamp(24rem, 12rem + 40vw, 48rem), calc(100vw - 3rem));
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
background-color: var(--panel-bg);
|
background-color: var(--panel-bg);
|
||||||
padding-inline: 1.5rem;
|
padding-inline: 1.5rem;
|
||||||
padding-block: 1rem;
|
padding-block: 1rem;
|
||||||
box-shadow: 0 0.25em 0.375em hsla(0, 0%, 0%, 0.1);
|
box-shadow: 0 0.25em 0.375em hsla(0, 0%, 0%, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 24rem) {
|
||||||
|
.panel {
|
||||||
|
padding-inline: 0.25rem;
|
||||||
|
width: calc(100vw - 0.5rem);
|
||||||
|
border-radius: 0;
|
||||||
|
margin-block-start: 0.2rem;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
padding-inline: 0.25rem;
|
||||||
|
height: max(fit-content, 2rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-name {
|
.project-name {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
130deg,
|
130deg,
|
||||||
oklch(from var(--c1) var(--name-lightness) c h),
|
oklch(from var(--c1) var(--name-lightness) c h),
|
||||||
oklch(from var(--c2) var(--name-lightness) c h)
|
oklch(from var(--c2) var(--name-lightness) c h)
|
||||||
);
|
);
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
filter: brightness(1.2);
|
filter: brightness(1.2);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ use axum::{
|
|||||||
response::{Html, IntoResponse, Response},
|
response::{Html, IntoResponse, Response},
|
||||||
routing::get,
|
routing::get,
|
||||||
};
|
};
|
||||||
use conduwuit_build_metadata::{GIT_REMOTE_COMMIT_URL, GIT_REMOTE_WEB_URL, version_tag};
|
use conduwuit_build_metadata::{GIT_REMOTE_COMMIT_URL, GIT_REMOTE_WEB_URL, VERSION_EXTRA};
|
||||||
use conduwuit_service::state;
|
use conduwuit_service::state;
|
||||||
|
|
||||||
pub fn build() -> Router<state::State> {
|
pub fn build() -> Router<state::State> {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
{%~ block footer ~%}
|
{%~ block footer ~%}
|
||||||
<footer>
|
<footer>
|
||||||
<p>Powered by <a href="https://continuwuity.org">Continuwuity</a>
|
<p>Powered by <a href="https://continuwuity.org">Continuwuity</a>
|
||||||
{%~ if let Some(version_info) = self::version_tag() ~%}
|
{%~ if let Some(version_info) = VERSION_EXTRA ~%}
|
||||||
{%~ if let Some(url) = GIT_REMOTE_COMMIT_URL.or(GIT_REMOTE_WEB_URL) ~%}
|
{%~ if let Some(url) = GIT_REMOTE_COMMIT_URL.or(GIT_REMOTE_WEB_URL) ~%}
|
||||||
(<a href="{{ url }}">{{ version_info }}</a>)
|
(<a href="{{ url }}">{{ version_info }}</a>)
|
||||||
{%~ else ~%}
|
{%~ else ~%}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "xtask-admin-command"
|
|
||||||
authors.workspace = true
|
|
||||||
categories.workspace = true
|
|
||||||
description.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
homepage.workspace = true
|
|
||||||
keywords.workspace = true
|
|
||||||
license.workspace = true
|
|
||||||
readme.workspace = true
|
|
||||||
repository.workspace = true
|
|
||||||
rust-version.workspace = true
|
|
||||||
version.workspace = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
clap-markdown = "0.1.5"
|
|
||||||
clap_builder = { version = "4.5.38", default-features = false }
|
|
||||||
clap_mangen = "0.2"
|
|
||||||
|
|
||||||
conduwuit-admin.workspace = true
|
|
||||||
|
|
||||||
# Hack to prevent rebuilds
|
|
||||||
conduwuit.workspace = true
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,58 +0,0 @@
|
|||||||
use std::{
|
|
||||||
fs::{self, File},
|
|
||||||
io,
|
|
||||||
path::Path,
|
|
||||||
};
|
|
||||||
|
|
||||||
use clap_builder::{Command, CommandFactory};
|
|
||||||
use conduwuit_admin::AdminCommand;
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mut args = std::env::args().skip(1);
|
|
||||||
let task = args.next();
|
|
||||||
match task {
|
|
||||||
| None => todo!(),
|
|
||||||
| Some(t) => match t.as_str() {
|
|
||||||
| "man" => {
|
|
||||||
let dir = Path::new("./admin-man");
|
|
||||||
gen_manpages(dir)?;
|
|
||||||
},
|
|
||||||
| "md" => {
|
|
||||||
let command = AdminCommand::command().name("admin");
|
|
||||||
|
|
||||||
let res = clap_markdown::help_markdown_command_custom(
|
|
||||||
&command,
|
|
||||||
&clap_markdown::MarkdownOptions::default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
println!("{res}");
|
|
||||||
},
|
|
||||||
| invalid => return Err(format!("Invalid task name: {invalid}").into()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_manpages(dir: &Path) -> Result<(), io::Error> {
|
|
||||||
fn r#gen(dir: &Path, c: &Command, prefix: Option<&str>) -> Result<(), io::Error> {
|
|
||||||
fs::create_dir_all(dir)?;
|
|
||||||
let sub_name = c.get_display_name().unwrap_or_else(|| c.get_name());
|
|
||||||
let name = if let Some(prefix) = prefix {
|
|
||||||
format!("{prefix}-{sub_name}")
|
|
||||||
} else {
|
|
||||||
sub_name.to_owned()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut out = File::create(dir.join(format!("{name}.1")))?;
|
|
||||||
let clap_mangen = clap_mangen::Man::new(c.to_owned().disable_help_flag(true));
|
|
||||||
clap_mangen.render(&mut out)?;
|
|
||||||
|
|
||||||
for sub in c.get_subcommands() {
|
|
||||||
r#gen(&dir.join(sub_name), sub, Some(&name))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
r#gen(dir, &AdminCommand::command().name("admin"), None)
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "xtask"
|
|
||||||
authors.workspace = true
|
|
||||||
categories.workspace = true
|
|
||||||
description.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
homepage.workspace = true
|
|
||||||
keywords.workspace = true
|
|
||||||
license.workspace = true
|
|
||||||
readme.workspace = true
|
|
||||||
repository.workspace = true
|
|
||||||
rust-version.workspace = true
|
|
||||||
version.workspace = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
clap.workspace = true
|
|
||||||
# Required for working with JSON output from cargo metadata
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
serde_json = "1.0"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
use std::{env, process::Command};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mut child = Command::new("cargo").args(["run", "--package", "xtask-admin-command", "--"].into_iter().map(ToOwned::to_owned).chain(env::args().skip(2)))
|
|
||||||
// .stdout(Stdio::piped())
|
|
||||||
// .stderr(Stdio::piped())
|
|
||||||
.spawn()
|
|
||||||
.expect("failed to execute child");
|
|
||||||
child.wait()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user