Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| af77615e8a | |||
| f91e40bc44 | |||
| 111f2223bd | |||
| 1d97858aa6 | |||
| 2834d50ddf | |||
| 3c9b702527 | |||
| a8c707d8a5 | |||
| 85c5b11e73 | |||
| e0d3180303 | |||
| 1e059d209c | |||
| 8e690f73d6 | |||
| 547bc2171c | |||
| 275075a2f5 | |||
| 335be12f79 | |||
| fd74a0ac3d | |||
| 5c258f41c8 | |||
| 15126ee1b2 | |||
| e37ac56dba | |||
| a74613be96 | |||
| a95ded167f | |||
| 95121b6e05 | |||
| e6884ef13a | |||
| 49033db2b8 | |||
| ddc8c3b46c | |||
| ea95627dce | |||
| c3e751542d |
@@ -29,8 +29,8 @@ concurrency:
|
||||
env:
|
||||
# sccache only on main repo
|
||||
SCCACHE_GHA_ENABLED: "${{ (github.event.pull_request.draft != true) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && (vars.SCCACHE_ENDPOINT != '') && (github.event.pull_request.user.login != 'renovate[bot]') && 'true' || 'false' }}"
|
||||
RUSTC_WRAPPER: "${{ (github.event.pull_request.draft != true) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && (vars.SCCACHE_ENDPOINT != '') && (github.event.pull_request.user.login != 'renovate[bot]') && 'sccache' }}"
|
||||
SCCACHE_BUCKET: "${{ (github.event.pull_request.draft != true) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && (vars.SCCACHE_ENDPOINT != '') && (github.event.pull_request.user.login != 'renovate[bot]') && 'sccache' }}"
|
||||
RUSTC_WRAPPER: "${{ (github.event.pull_request.draft != true) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && (vars.SCCACHE_ENDPOINT != '') && (github.event.pull_request.user.login != 'renovate[bot]') && 'sccache' || '' }}"
|
||||
SCCACHE_BUCKET: "${{ (github.event.pull_request.draft != true) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '') && (vars.SCCACHE_ENDPOINT != '') && (github.event.pull_request.user.login != 'renovate[bot]') && 'sccache' || '' }}"
|
||||
SCCACHE_S3_USE_SSL: ${{ vars.SCCACHE_S3_USE_SSL }}
|
||||
SCCACHE_REGION: ${{ vars.SCCACHE_REGION }}
|
||||
SCCACHE_ENDPOINT: ${{ vars.SCCACHE_ENDPOINT }}
|
||||
|
||||
Generated
+81
-195
@@ -153,34 +153,6 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.6.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core 0.3.4",
|
||||
"bitflags 1.3.2",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.30",
|
||||
"itoa",
|
||||
"matchit",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"sync_wrapper 0.1.2",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.5"
|
||||
@@ -188,13 +160,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core 0.4.3",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
@@ -221,28 +193,11 @@ version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72188bed20deb981f3a4a9fe674e5980fd9e9c2bd880baa94715ad5d60d64c67"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum",
|
||||
"forwarded-header-value",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"mime",
|
||||
"rustversion",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.4.3"
|
||||
@@ -252,8 +207,8 @@ dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
@@ -270,13 +225,13 @@ version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum-core 0.4.3",
|
||||
"axum",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
@@ -295,10 +250,10 @@ dependencies = [
|
||||
"arc-swap",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"rustls 0.21.12",
|
||||
@@ -317,7 +272,7 @@ checksum = "7ea4cd08ae2a5f075d28fa31190163c8106a1d2d3189442494bae22b39040a0d"
|
||||
dependencies = [
|
||||
"axum-server",
|
||||
"bytes",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"http-body-util",
|
||||
"pin-project",
|
||||
"tokio",
|
||||
@@ -639,7 +594,7 @@ dependencies = [
|
||||
name = "conduit_api"
|
||||
version = "0.4.6"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum",
|
||||
"axum-client-ip",
|
||||
"axum-extra",
|
||||
"base64 0.22.1",
|
||||
@@ -650,9 +605,9 @@ dependencies = [
|
||||
"const-str",
|
||||
"futures-util",
|
||||
"hmac",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper",
|
||||
"image",
|
||||
"ipaddress",
|
||||
"jsonwebtoken",
|
||||
@@ -674,7 +629,7 @@ name = "conduit_core"
|
||||
version = "0.4.6"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"axum 0.7.5",
|
||||
"axum",
|
||||
"bytes",
|
||||
"cargo_toml",
|
||||
"checked_ops",
|
||||
@@ -685,7 +640,7 @@ dependencies = [
|
||||
"either",
|
||||
"figment",
|
||||
"hardened_malloc-rs",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"http-body-util",
|
||||
"image",
|
||||
"ipaddress",
|
||||
@@ -741,7 +696,7 @@ dependencies = [
|
||||
name = "conduit_router"
|
||||
version = "0.4.6"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum",
|
||||
"axum-client-ip",
|
||||
"axum-server",
|
||||
"axum-server-dual-protocol",
|
||||
@@ -751,9 +706,9 @@ dependencies = [
|
||||
"conduit_core",
|
||||
"conduit_service",
|
||||
"const-str",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"log",
|
||||
"ruma",
|
||||
@@ -781,7 +736,7 @@ dependencies = [
|
||||
"cyborgtime",
|
||||
"futures-util",
|
||||
"hickory-resolver",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"image",
|
||||
"ipaddress",
|
||||
"itertools 0.13.0",
|
||||
@@ -806,9 +761,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console-api"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a257c22cd7e487dd4a13d413beabc512c5052f0bc048db0da6a84c3d8a6142fd"
|
||||
checksum = "86ed14aa9c9f927213c6e4f3ef75faaad3406134efe84ba2cb7983431d5f0931"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"prost",
|
||||
@@ -819,9 +774,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console-subscriber"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31c4cc54bae66f7d9188996404abdf7fdfa23034ef8e43478c8810828abad758"
|
||||
checksum = "e2e3a111a37f3333946ebf9da370ba5c5577b18eb342ec683eb488dd21980302"
|
||||
dependencies = [
|
||||
"console-api",
|
||||
"crossbeam-channel",
|
||||
@@ -829,6 +784,7 @@ dependencies = [
|
||||
"futures-task",
|
||||
"hdrhistogram",
|
||||
"humantime",
|
||||
"hyper-util",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"serde",
|
||||
@@ -1372,25 +1328,6 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"indexmap 2.2.6",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.5"
|
||||
@@ -1402,7 +1339,7 @@ dependencies = [
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"indexmap 2.2.6",
|
||||
"slab",
|
||||
"tokio",
|
||||
@@ -1450,7 +1387,7 @@ dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"headers-core",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"sha1",
|
||||
@@ -1462,7 +1399,7 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
|
||||
dependencies = [
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1579,17 +1516,6 @@ dependencies = [
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.1.0"
|
||||
@@ -1610,17 +1536,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 0.2.12",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
@@ -1628,7 +1543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1639,8 +1554,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@@ -1662,30 +1577,6 @@ version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.3.26",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.4.1"
|
||||
@@ -1695,9 +1586,9 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"h2 0.4.5",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
@@ -1714,8 +1605,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"hyper 1.4.1",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls 0.23.12",
|
||||
"rustls-native-certs",
|
||||
@@ -1728,14 +1619,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-timeout"
|
||||
version = "0.4.1"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1"
|
||||
checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793"
|
||||
dependencies = [
|
||||
"hyper 0.14.30",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-io-timeout",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1747,9 +1639,9 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"hyper 1.4.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
@@ -2694,9 +2586,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.12.6"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29"
|
||||
checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
@@ -2704,12 +2596,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.12.6"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1"
|
||||
checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.12.1",
|
||||
"itertools 0.13.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.72",
|
||||
@@ -2717,9 +2609,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.12.6"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0"
|
||||
checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2"
|
||||
dependencies = [
|
||||
"prost",
|
||||
]
|
||||
@@ -2904,12 +2796,12 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.4.5",
|
||||
"h2",
|
||||
"hickory-resolver",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
@@ -3009,7 +2901,7 @@ dependencies = [
|
||||
"assign",
|
||||
"bytes",
|
||||
"date_header",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"js_int",
|
||||
"js_option",
|
||||
"maplit",
|
||||
@@ -3032,7 +2924,7 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"form_urlencoded",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"indexmap 2.2.6",
|
||||
"js_int",
|
||||
"konst",
|
||||
@@ -3140,7 +3032,7 @@ version = "0.3.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c76e2873c1593a3308d4ba3e0e4a1db65acf8536#c76e2873c1593a3308d4ba3e0e4a1db65acf8536"
|
||||
dependencies = [
|
||||
"headers",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"http-auth",
|
||||
"ruma-common",
|
||||
"thiserror",
|
||||
@@ -3519,7 +3411,7 @@ version = "0.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c90802b38c899a2c9e557dff25ad186362eddf755d5f5244001b172dd03bead"
|
||||
dependencies = [
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
"pin-project",
|
||||
"sentry-core",
|
||||
"tower-layer",
|
||||
@@ -3591,11 +3483,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.120"
|
||||
version = "1.0.121"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||
checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
@@ -4055,9 +3948,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.39.1"
|
||||
version = "1.39.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a"
|
||||
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -4071,16 +3964,6 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-io-timeout"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.4.0"
|
||||
@@ -4208,23 +4091,26 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13"
|
||||
checksum = "38659f4a91aba8598d27821589f5db7dddd94601e7a01b1e485a50e5484c7401"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"axum 0.6.20",
|
||||
"base64 0.21.7",
|
||||
"axum",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"h2 0.3.26",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.30",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-timeout",
|
||||
"hyper-util",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
@@ -4264,8 +4150,8 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
|
||||
+19
-4
@@ -33,6 +33,7 @@ version = "0.2.8"
|
||||
|
||||
[workspace.dependencies.cargo_toml]
|
||||
version = "0.20"
|
||||
default-features = false
|
||||
features = ["features"]
|
||||
|
||||
[workspace.dependencies.toml]
|
||||
@@ -96,6 +97,7 @@ features = ["typed-header", "tracing"]
|
||||
|
||||
[workspace.dependencies.axum-server]
|
||||
version = "0.6.0"
|
||||
default-features = false
|
||||
features = ["tls-rustls"]
|
||||
|
||||
[workspace.dependencies.axum-client-ip]
|
||||
@@ -103,10 +105,12 @@ version = "0.6.0"
|
||||
|
||||
[workspace.dependencies.tower]
|
||||
version = "0.4.13"
|
||||
default-features = false
|
||||
features = ["util"]
|
||||
|
||||
[workspace.dependencies.tower-http]
|
||||
version = "0.5.2"
|
||||
default-features = false
|
||||
features = [
|
||||
"add-extension",
|
||||
"cors",
|
||||
@@ -129,10 +133,12 @@ features = [
|
||||
|
||||
[workspace.dependencies.serde]
|
||||
version = "1.0.204"
|
||||
default-features = false
|
||||
features = ["rc"]
|
||||
|
||||
[workspace.dependencies.serde_json]
|
||||
version = "1.0.120"
|
||||
version = "1.0.121"
|
||||
default-features = false
|
||||
features = ["raw_value"]
|
||||
|
||||
# Used for appservice registration files
|
||||
@@ -200,7 +206,8 @@ version = "0.3.30"
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.tokio]
|
||||
version = "1.39.1"
|
||||
version = "1.39.2"
|
||||
default-features = false
|
||||
features = [
|
||||
"fs",
|
||||
"net",
|
||||
@@ -221,6 +228,7 @@ version = "0.8.5"
|
||||
# Validating urls in config, was already a transitive dependency
|
||||
[workspace.dependencies.url]
|
||||
version = "2.5.0"
|
||||
default-features = false
|
||||
features = ["serde"]
|
||||
|
||||
# standard date and time tools
|
||||
@@ -231,6 +239,7 @@ default-features = false
|
||||
|
||||
[workspace.dependencies.hyper]
|
||||
version = "1.4.1"
|
||||
default-features = false
|
||||
features = [
|
||||
"server",
|
||||
"http1",
|
||||
@@ -239,6 +248,7 @@ features = [
|
||||
|
||||
[workspace.dependencies.hyper-util]
|
||||
version = "0.1.6"
|
||||
default-features = false
|
||||
features = [
|
||||
"client",
|
||||
"server-auto",
|
||||
@@ -250,11 +260,13 @@ features = [
|
||||
# to support multiple variations of setting a config option
|
||||
[workspace.dependencies.either]
|
||||
version = "1.11.0"
|
||||
default-features = false
|
||||
features = ["serde"]
|
||||
|
||||
# Used for reading the configuration from conduwuit.toml & environment variables
|
||||
[workspace.dependencies.figment]
|
||||
version = "0.10.18"
|
||||
default-features = false
|
||||
features = ["env", "toml"]
|
||||
|
||||
[workspace.dependencies.hickory-resolver]
|
||||
@@ -396,10 +408,11 @@ default-features = false
|
||||
features = ["use_std"]
|
||||
|
||||
[workspace.dependencies.console-subscriber]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
|
||||
[workspace.dependencies.nix]
|
||||
version = "0.29.0"
|
||||
default-features = false
|
||||
features = ["resource"]
|
||||
|
||||
[workspace.dependencies.sd-notify]
|
||||
@@ -427,6 +440,7 @@ version = "0.1"
|
||||
|
||||
[workspace.dependencies.syn]
|
||||
version = "2.0.72"
|
||||
default-features = false
|
||||
features = ["full", "extra-traits"]
|
||||
|
||||
[workspace.dependencies.quote]
|
||||
@@ -801,7 +815,7 @@ perf = { level = "warn", priority = -1 }
|
||||
###################
|
||||
#restriction = "warn"
|
||||
|
||||
allow_attributes = "warn"
|
||||
#allow_attributes = "warn" # UNSTABLE
|
||||
arithmetic_side_effects = "warn"
|
||||
as_conversions = "warn"
|
||||
as_underscore = "warn"
|
||||
@@ -851,6 +865,7 @@ style = { level = "warn", priority = -1 }
|
||||
## some sadness
|
||||
# trivial assertions are quite alright
|
||||
assertions_on_constants = { level = "allow", priority = 1 }
|
||||
module_inception = { level = "allow", priority = 1 }
|
||||
|
||||
###################
|
||||
suspicious = { level = "warn", priority = -1 }
|
||||
|
||||
@@ -224,9 +224,11 @@ registration_token = "change this token for something specific to your server"
|
||||
# No default.
|
||||
# forbidden_alias_names = []
|
||||
|
||||
# List of forbidden server names that we will block all client room joins, incoming federated room directory requests, incoming federated invites for, and incoming federated joins. This check is applied on the room ID, room alias, sender server name, and sender user's server name.
|
||||
# Basically "global" ACLs. For our user (client) checks, admin users are allowed.
|
||||
# No default.
|
||||
# List of forbidden server names that we will block incoming AND outgoing federation with, and block client room joins / remote user invites.
|
||||
#
|
||||
# This check is applied on the room ID, room alias, sender server name, sender user's server name, inbound federation X-Matrix origin, and outbound federation handler.
|
||||
#
|
||||
# Basically "global" ACLs. No default.
|
||||
# forbidden_remote_server_names = []
|
||||
|
||||
# List of forbidden server names that we will block all outgoing federated room directory requests for. Useful for preventing our users from wandering into bad servers or spaces.
|
||||
|
||||
Vendored
-1
@@ -16,7 +16,6 @@ case "$1" in
|
||||
--home "$CONDUWUIT_DATABASE_PATH" \
|
||||
--disabled-login \
|
||||
--shell "/usr/sbin/nologin" \
|
||||
--verbose \
|
||||
conduwuit
|
||||
fi
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
- [Docker](deploying/docker.md)
|
||||
- [Arch Linux](deploying/arch-linux.md)
|
||||
- [Debian](deploying/debian.md)
|
||||
- [FreeBSD](deploying/freebsd.md)
|
||||
- [TURN](turn.md)
|
||||
- [Appservices](appservices.md)
|
||||
- [Maintenance](maintenance.md)
|
||||
|
||||
+24
-4
@@ -4,15 +4,35 @@ This chapter describes various ways to configure conduwuit.
|
||||
|
||||
## Basics
|
||||
|
||||
Conduwuit uses a config file for the majority of the settings. Please refer to the
|
||||
[example config file](./configuration/examples.md#example-configuration) for all of those settings.
|
||||
The config file to use can either be specified on the command line when running conduwuit by specifying the
|
||||
conduwuit uses a config file for the majority of the settings, but also supports setting individual config options via commandline.
|
||||
|
||||
Please refer to the [example config file](./configuration/examples.md#example-configuration) for all of those settings.
|
||||
|
||||
The config file to use can be specified on the commandline when running conduwuit by specifying the
|
||||
`-c`, `--config` flag. Alternatively, you can use the environment variable `CONDUWUIT_CONFIG` to specify the config
|
||||
file to used.
|
||||
file to used. Conduit's environment variables are supported for backwards compatibility.
|
||||
|
||||
## Option commandline flag
|
||||
|
||||
conduwuit supports setting individual config options in TOML format from the `-O` / `--option` flag. For example, you can set your server name via `-O server_name=\"example.com\"`.
|
||||
|
||||
Note that the config is parsed as TOML, and shells like bash will remove quotes. So unfortunately it is required to escape quotes if the config option takes a string.
|
||||
This does not apply to options that take booleans or numbers:
|
||||
- `--option allow_registration=true` works ✅
|
||||
- `-O max_request_size=99999999` works ✅
|
||||
- `-O server_name=example.com` does not work ❌
|
||||
- `--option log=\"debug\"` works ✅
|
||||
- `--option server_name='"example.com'"` works ✅
|
||||
|
||||
|
||||
## Environment variables
|
||||
|
||||
All of the settings that are found in the config file can be specified by using environment variables.
|
||||
The environment variable names should be all caps and prefixed with `CONDUWUIT_`.
|
||||
|
||||
For example, if the setting you are changing is `max_request_size`, then the environment variable to set is
|
||||
`CONDUWUIT_MAX_REQUEST_SIZE`.
|
||||
|
||||
To modify config options not in the `[global]` context such as `[global.well_known]`, use the `__` suffix split: `CONDUWUIT_WELL_KNOWN__SERVER`
|
||||
|
||||
Conduit's environment variables are supported for backwards compatibility (e.g. `CONDUIT_SERVER_NAME`).
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# conduwuit for FreeBSD
|
||||
|
||||
conduwuit at the moment does not provide FreeBSD builds. Building conduwuit on FreeBSD requires a specific environment variable to use the
|
||||
system prebuilt RocksDB library instead of rust-rocksdb / rust-librocksdb-sys which does *not* work and will cause a build error or coredump.
|
||||
|
||||
Use the following environment variable: `ROCKSDB_LIB_DIR=/usr/local/lib`
|
||||
|
||||
Such example commandline with it can be: `ROCKSDB_LIB_DIR=/usr/local/lib cargo build --release`
|
||||
@@ -9,14 +9,12 @@
|
||||
|
||||
You may simply download the binary that fits your machine. Run `uname -m` to see what you need.
|
||||
|
||||
Prebuilt binaries can be downloaded from the latest tagged release [here](https://github.com/girlbossceo/conduwuit/releases/latest).
|
||||
|
||||
The latest tagged release also includes the Debian packages.
|
||||
Prebuilt fully static musl binaries can be downloaded from the latest tagged release [here](https://github.com/girlbossceo/conduwuit/releases/latest) or `main` CI branch workflow artifact output. These also include Debian packages. These binaries have jemalloc and io_uring statically linked and included with them.
|
||||
|
||||
Alternatively, you may compile the binary yourself. We recommend using [Lix](https://lix.systems) to build conduwuit as this has the most guaranteed
|
||||
reproducibiltiy and easiest to get a build environment and output going.
|
||||
|
||||
Otherwise, follow standard Rust project build guides (installing git and cloning the repo, getting the Rust toolchain via rustup, installing LLVM toolchain + libclang, installing liburing for io_uring and RocksDB, etc).
|
||||
Otherwise, follow standard Rust project build guides (installing git and cloning the repo, getting the Rust toolchain via rustup, installing LLVM toolchain + libclang for RocksDB, installing liburing for io_uring and RocksDB, etc).
|
||||
|
||||
## Adding a conduwuit user
|
||||
|
||||
|
||||
+11
-2
@@ -8,6 +8,17 @@
|
||||
>
|
||||
> If there are things like Compose file issues or Dockerhub image issues, those can still be mentioned as long as they're something we can fix.
|
||||
|
||||
## General potential issues
|
||||
|
||||
#### Potential DNS issues when using Docker
|
||||
|
||||
Docker has issues with its default DNS setup that may cause DNS to not be properly functional when running conduwuit, resulting in federation issues.
|
||||
The symptoms of this have shown in excessively long room joins (30+ minutes) from very long DNS timeouts, log entries of "mismatching responding nameservers", and/or partial or non-functional inbound/outbound federation.
|
||||
|
||||
This is **not** a conduwuit issue, and is purely a Docker issue. It is not sustainable for heavy DNS activity which is normal for Matrix federation. The workarounds for this are:
|
||||
- Use DNS over TCP via the config option `query_over_tcp_only = true`
|
||||
- Don't use Docker's default DNS setup and instead allow the container to use and communicate with your host's DNS servers (host's `/etc/resolv.conf`)
|
||||
|
||||
## Rocksdb / database issues
|
||||
|
||||
#### Direct IO
|
||||
@@ -38,8 +49,6 @@ With this in mind:
|
||||
- Leave your conduwuit running in `PointInTime` for at least 30-60 minutes so as much possible corruption is restored
|
||||
- If all goes will, you should be able to restore back to using `TolerateCorruptedTailRecords` and you have successfully recovered your database
|
||||
|
||||
## Media
|
||||
|
||||
## Debugging
|
||||
|
||||
Note that users should not really be debugging things. If you find yourself debugging and find the issue, please let us know and/or how we can fix it. Various debug commands can be found in `!admin debug`.
|
||||
|
||||
@@ -137,7 +137,11 @@
|
||||
# Useful for editing the book locally
|
||||
mdbook
|
||||
|
||||
# used for rust caching in CI to speed it up
|
||||
sccache
|
||||
|
||||
# needed so we can get rid of gcc and other unused deps that bloat OCI images
|
||||
removeReferencesTo
|
||||
])
|
||||
++ scope.main.buildInputs
|
||||
++ scope.main.propagatedBuildInputs
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
, liburing
|
||||
, pkgsBuildHost
|
||||
, rocksdb
|
||||
, removeReferencesTo
|
||||
, rust
|
||||
, rust-jemalloc-sys
|
||||
, stdenv
|
||||
@@ -94,8 +95,8 @@ buildDepsOnlyEnv =
|
||||
else if stdenv.targetPlatform.isAarch64
|
||||
then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags
|
||||
++ lib.optionals stdenv.targetPlatform.isAarch64 [
|
||||
# cortex-a55 == ARMv8.2-a
|
||||
"-DPORTABLE=armv8.2-a"
|
||||
# cortex-a73 == ARMv8-A
|
||||
"-DPORTABLE=armv8-a"
|
||||
]
|
||||
else old.cmakeFlags;
|
||||
});
|
||||
@@ -128,7 +129,7 @@ buildPackageEnv = {
|
||||
+ lib.optionalString stdenv.targetPlatform.isx86_64
|
||||
" -Ctarget-cpu=x86-64-v2"
|
||||
+ lib.optionalString stdenv.targetPlatform.isAarch64
|
||||
" -Ctarget-cpu=cortex-a55"; # cortex-a55 == ARMv8.2-a
|
||||
" -Ctarget-cpu=cortex-a73"; # cortex-a73 == ARMv8-A
|
||||
};
|
||||
|
||||
|
||||
@@ -154,6 +155,7 @@ commonAttrs = {
|
||||
};
|
||||
|
||||
dontStrip = profile == "dev" || profile == "test";
|
||||
dontPatchELF = profile == "dev" || profile == "test";
|
||||
|
||||
buildInputs = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys';
|
||||
|
||||
@@ -168,6 +170,9 @@ commonAttrs = {
|
||||
# differing values for `NIX_CFLAGS_COMPILE`, which contributes to spurious
|
||||
# rebuilds of bindgen and its depedents.
|
||||
jq
|
||||
|
||||
# needed so we can get rid of gcc and other unused deps that bloat OCI images
|
||||
removeReferencesTo
|
||||
]
|
||||
++ lib.optionals stdenv.isDarwin [
|
||||
# https://github.com/NixOS/nixpkgs/issues/206242
|
||||
@@ -177,6 +182,13 @@ commonAttrs = {
|
||||
# https://discourse.nixos.org/t/compile-a-rust-binary-on-macos-dbcrossbar/8612
|
||||
pkgsBuildHost.darwin.apple_sdk.frameworks.Security
|
||||
];
|
||||
|
||||
# for some reason gcc and other weird deps are added to OCI images and bloats it up
|
||||
#
|
||||
# <https://github.com/input-output-hk/haskell.nix/issues/829>
|
||||
postInstall = with pkgsBuildHost; ''
|
||||
find "$out" -type f -exec remove-references-to -t ${stdenv.cc} -t ${gcc} -t ${libgcc} -t ${linuxHeaders} -t ${libidn2} -t ${libunistring} '{}' +
|
||||
'';
|
||||
};
|
||||
in
|
||||
|
||||
|
||||
@@ -149,23 +149,32 @@ pub(super) async fn get_remote_pdu_list(
|
||||
.filter_map(|pdu| EventId::parse(pdu).ok())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut failed_count: usize = 0;
|
||||
let mut success_count: usize = 0;
|
||||
|
||||
for pdu in list {
|
||||
if force {
|
||||
if let Err(e) = self.get_remote_pdu(Box::from(pdu), server.clone()).await {
|
||||
failed_count = failed_count.saturating_add(1);
|
||||
self.services
|
||||
.admin
|
||||
.send_message(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to get remote PDU, ignoring error: {e}"
|
||||
)))
|
||||
.await;
|
||||
warn!(%e, "Failed to get remote PDU, ignoring error");
|
||||
warn!("Failed to get remote PDU, ignoring error: {e}");
|
||||
} else {
|
||||
success_count = success_count.saturating_add(1);
|
||||
}
|
||||
} else {
|
||||
self.get_remote_pdu(Box::from(pdu), server.clone()).await?;
|
||||
success_count = success_count.saturating_add(1);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain("Fetched list of remote PDUs."))
|
||||
Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Fetched {success_count} remote PDUs successfully with {failed_count} failures"
|
||||
)))
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
|
||||
+34
-5
@@ -1,7 +1,7 @@
|
||||
use std::{panic::AssertUnwindSafe, sync::Arc, time::Instant};
|
||||
|
||||
use clap::{CommandFactory, Parser};
|
||||
use conduit::{error, trace, utils::string::common_prefix, Error, Result};
|
||||
use conduit::{checked, error, trace, utils::string::common_prefix, Error, Result};
|
||||
use futures_util::future::FutureExt;
|
||||
use ruma::{
|
||||
events::{
|
||||
@@ -60,8 +60,11 @@ fn reply(mut content: RoomMessageEventContent, reply_id: Option<OwnedEventId>) -
|
||||
|
||||
// Parse and process a message from the admin room
|
||||
async fn process(services: Arc<Services>, msg: &str) -> CommandOutput {
|
||||
let mut lines = msg.lines().filter(|l| !l.trim().is_empty());
|
||||
let command = lines.next().expect("each string has at least one line");
|
||||
let lines = msg.lines().filter(|l| !l.trim().is_empty());
|
||||
let command = lines
|
||||
.clone()
|
||||
.next()
|
||||
.expect("each string has at least one line");
|
||||
let (parsed, body) = match parse_command(command) {
|
||||
Ok(parsed) => parsed,
|
||||
Err(error) => {
|
||||
@@ -71,12 +74,12 @@ async fn process(services: Arc<Services>, msg: &str) -> CommandOutput {
|
||||
},
|
||||
};
|
||||
|
||||
let timer = Instant::now();
|
||||
let body: Vec<&str> = body.iter().map(String::as_str).collect();
|
||||
let body = parse_body(AdminCommand::command(), &body, lines.skip(1).collect()).expect("trailing body parsed");
|
||||
let context = Command {
|
||||
services: &services,
|
||||
body: &body,
|
||||
};
|
||||
let timer = Instant::now();
|
||||
let result = Box::pin(admin::process(parsed, &context)).await;
|
||||
let elapsed = timer.elapsed();
|
||||
conduit::debug!(?command, ok = result.is_ok(), "command processed in {elapsed:?}");
|
||||
@@ -95,6 +98,32 @@ fn parse_command(command_line: &str) -> Result<(AdminCommand, Vec<String>), Stri
|
||||
Ok((com, argv))
|
||||
}
|
||||
|
||||
fn parse_body<'a>(mut cmd: clap::Command, body: &'a [String], lines: Vec<&'a str>) -> Result<Vec<&'a str>> {
|
||||
let mut start = 1;
|
||||
'token: for token in body.iter().skip(1) {
|
||||
let cmd_ = cmd.clone();
|
||||
for sub in cmd_.get_subcommands() {
|
||||
if sub.get_name() == *token {
|
||||
start = checked!(start + 1)?;
|
||||
cmd = sub.clone();
|
||||
continue 'token;
|
||||
}
|
||||
}
|
||||
|
||||
// positional arguments have to be skipped too
|
||||
let num_posargs = cmd_.get_positionals().count();
|
||||
start = checked!(start + num_posargs)?;
|
||||
break;
|
||||
}
|
||||
|
||||
Ok(body
|
||||
.iter()
|
||||
.skip(start)
|
||||
.map(String::as_str)
|
||||
.chain(lines)
|
||||
.collect::<Vec<&'a str>>())
|
||||
}
|
||||
|
||||
fn complete_command(mut cmd: clap::Command, line: &str) -> String {
|
||||
let argv = parse_line(line);
|
||||
let mut ret = Vec::<String>::with_capacity(argv.len().saturating_add(1));
|
||||
|
||||
@@ -35,13 +35,13 @@ pub(super) async fn list_features(
|
||||
};
|
||||
if enabled && !available {
|
||||
let features = info::rustc::features().join(delim);
|
||||
let out = format!("```\n{features}\n```");
|
||||
let out = format!("`\n{features}\n`");
|
||||
return Ok(RoomMessageEventContent::text_markdown(out));
|
||||
}
|
||||
|
||||
if available && !enabled {
|
||||
let features = info::cargo::features().join(delim);
|
||||
let out = format!("```\n{features}\n```");
|
||||
let out = format!("`\n{features}\n`");
|
||||
return Ok(RoomMessageEventContent::text_markdown(out));
|
||||
}
|
||||
|
||||
|
||||
@@ -286,9 +286,13 @@ pub(crate) async fn register_route(
|
||||
let token = utils::random_string(TOKEN_LENGTH);
|
||||
|
||||
// Create device for this account
|
||||
services
|
||||
.users
|
||||
.create_device(&user_id, &device_id, &token, body.initial_device_display_name.clone())?;
|
||||
services.users.create_device(
|
||||
&user_id,
|
||||
&device_id,
|
||||
&token,
|
||||
body.initial_device_display_name.clone(),
|
||||
Some(client.to_string()),
|
||||
)?;
|
||||
|
||||
debug_info!(%user_id, %device_id, "User account was created");
|
||||
|
||||
|
||||
@@ -21,11 +21,13 @@ pub(crate) async fn get_context_route(
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
|
||||
|
||||
// some clients, at least element, seem to require knowledge of redundant
|
||||
// members for "inline" profiles on the timeline to work properly
|
||||
let (lazy_load_enabled, lazy_load_send_redundant) = match &body.filter.lazy_load_options {
|
||||
LazyLoadOptions::Enabled {
|
||||
include_redundant_members,
|
||||
} => (true, *include_redundant_members),
|
||||
LazyLoadOptions::Disabled => (false, false),
|
||||
LazyLoadOptions::Disabled => (false, cfg!(feature = "element_hacks")),
|
||||
};
|
||||
|
||||
let mut lazy_loaded = HashSet::new();
|
||||
|
||||
+8
-21
@@ -5,19 +5,19 @@ use std::{io::Cursor, time::Duration};
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use conduit::{
|
||||
debug, debug_warn, error,
|
||||
debug, debug_info, debug_warn, err, info,
|
||||
utils::{
|
||||
self,
|
||||
content_disposition::{content_disposition_type, make_content_disposition, sanitise_filename},
|
||||
math::ruma_from_usize,
|
||||
},
|
||||
warn, Error, Result,
|
||||
warn, Err, Error, Result,
|
||||
};
|
||||
use image::io::Reader as ImgReader;
|
||||
use ipaddress::IPAddress;
|
||||
use reqwest::Url;
|
||||
use ruma::api::client::{
|
||||
error::{ErrorKind, RetryAfter},
|
||||
error::ErrorKind,
|
||||
media::{
|
||||
create_content, get_content, get_content_as_filename, get_content_thumbnail, get_media_config,
|
||||
get_media_preview,
|
||||
@@ -77,35 +77,22 @@ pub(crate) async fn get_media_preview_route(
|
||||
|
||||
let url = &body.url;
|
||||
if !url_preview_allowed(&services, url) {
|
||||
warn!(%sender_user, "URL is not allowed to be previewed: {url}");
|
||||
debug_info!(%sender_user, "URL is not allowed to be previewed: {url}");
|
||||
return Err(Error::BadRequest(ErrorKind::forbidden(), "URL is not allowed to be previewed"));
|
||||
}
|
||||
|
||||
match get_url_preview(&services, url).await {
|
||||
Ok(preview) => {
|
||||
let res = serde_json::value::to_raw_value(&preview).map_err(|e| {
|
||||
error!(%sender_user, "Failed to convert UrlPreviewData into a serde json value: {e}");
|
||||
Error::BadRequest(
|
||||
ErrorKind::LimitExceeded {
|
||||
retry_after: Some(RetryAfter::Delay(Duration::from_secs(5))),
|
||||
},
|
||||
"Failed to generate a URL preview, try again later.",
|
||||
)
|
||||
warn!(%sender_user, "Failed to convert UrlPreviewData into a serde json value: {e}");
|
||||
err!(Request(Unknown("Failed to generate a URL preview")))
|
||||
})?;
|
||||
|
||||
Ok(get_media_preview::v3::Response::from_raw_value(res))
|
||||
},
|
||||
Err(e) => {
|
||||
warn!(%sender_user, "Failed to generate a URL preview: {e}");
|
||||
|
||||
// there doesn't seem to be an agreed-upon error code in the spec.
|
||||
// the only response codes in the preview_url spec page are 200 and 429.
|
||||
Err(Error::BadRequest(
|
||||
ErrorKind::LimitExceeded {
|
||||
retry_after: Some(RetryAfter::Delay(Duration::from_secs(5))),
|
||||
},
|
||||
"Failed to generate a URL preview, try again later.",
|
||||
))
|
||||
info!(%sender_user, "Failed to generate a URL preview: {e}");
|
||||
Err!(Request(Unknown("Failed to generate a URL preview")))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
+96
-34
@@ -1,7 +1,7 @@
|
||||
use std::{cmp::max, collections::BTreeMap};
|
||||
|
||||
use axum::extract::State;
|
||||
use conduit::{debug_info, debug_warn};
|
||||
use conduit::{debug_info, debug_warn, err};
|
||||
use ruma::{
|
||||
api::client::{
|
||||
error::ErrorKind,
|
||||
@@ -20,6 +20,7 @@ use ruma::{
|
||||
tombstone::RoomTombstoneEventContent,
|
||||
topic::RoomTopicEventContent,
|
||||
},
|
||||
space::child::SpaceChildEventContent,
|
||||
StateEventType, TimelineEventType,
|
||||
},
|
||||
int,
|
||||
@@ -475,10 +476,7 @@ pub(crate) async fn get_room_event_route(
|
||||
.rooms
|
||||
.timeline
|
||||
.get_pdu(&body.event_id)?
|
||||
.ok_or_else(|| {
|
||||
warn!("Event not found, event ID: {:?}", &body.event_id);
|
||||
Error::BadRequest(ErrorKind::NotFound, "Event not found.")
|
||||
})?;
|
||||
.ok_or_else(|| err!(Request(NotFound("Event {} not found.", &body.event_id))))?;
|
||||
|
||||
if !services
|
||||
.rooms
|
||||
@@ -621,22 +619,14 @@ pub(crate) async fn upgrade_room_route(
|
||||
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
|
||||
create_event_content.insert(
|
||||
"creator".into(),
|
||||
json!(&sender_user).try_into().map_err(|e| {
|
||||
info!("Error forming creation event: {e}");
|
||||
Error::BadRequest(ErrorKind::BadJson, "Error forming creation event")
|
||||
})?,
|
||||
json!(&sender_user)
|
||||
.try_into()
|
||||
.map_err(|_| err!(Request(BadJson("Error forming creation event"))))?,
|
||||
);
|
||||
},
|
||||
V11 => {
|
||||
// "creator" key no longer exists in V11 rooms
|
||||
create_event_content.remove("creator");
|
||||
},
|
||||
_ => {
|
||||
warn!("Unexpected or unsupported room version {}", body.new_version);
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::BadJson,
|
||||
"Unexpected or unsupported room version found",
|
||||
));
|
||||
// "creator" key no longer exists in V11+ rooms
|
||||
create_event_content.remove("creator");
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -645,26 +635,100 @@ pub(crate) async fn upgrade_room_route(
|
||||
"room_version".into(),
|
||||
json!(&body.new_version)
|
||||
.try_into()
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"))?,
|
||||
.map_err(|_| err!(Request(BadJson("Error forming creation event"))))?,
|
||||
);
|
||||
create_event_content.insert(
|
||||
"predecessor".into(),
|
||||
json!(predecessor)
|
||||
.try_into()
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"))?,
|
||||
.map_err(|_| err!(Request(BadJson("Error forming creation event"))))?,
|
||||
);
|
||||
|
||||
// Validate creation event content
|
||||
if serde_json::from_str::<CanonicalJsonObject>(
|
||||
to_raw_value(&create_event_content)
|
||||
.expect("Error forming creation event")
|
||||
.get(),
|
||||
)
|
||||
.is_err()
|
||||
// if the room was a space:
|
||||
// - migrate m.space.child and/or m.space.parent
|
||||
// - add space type to replacement room m.room.create
|
||||
//
|
||||
// as apart of MSC4168
|
||||
if services
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_room_type(&body.room_id)
|
||||
.unwrap_or(None)
|
||||
.is_some_and(|room_type| room_type == ruma::room::RoomType::Space)
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"));
|
||||
create_event_content.insert(
|
||||
"type".into(),
|
||||
json!(ruma::room::RoomType::Space)
|
||||
.try_into()
|
||||
.map_err(|_| err!(Request(BadJson("Error forming creation event"))))?,
|
||||
);
|
||||
|
||||
if let Some(event_content) = services
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&body.room_id, &StateEventType::SpaceChild, body.room_id.as_str())
|
||||
.unwrap_or(None)
|
||||
{
|
||||
// space contents that are empty are not apart of the space
|
||||
if !event_content.content.get().is_empty() {
|
||||
// remove all but us from via
|
||||
let mut new_content: SpaceChildEventContent = serde_json::from_str(event_content.content.get())
|
||||
.map_err(|_| err!(Database(error!("Invalid m.space.child content in database"))))?;
|
||||
new_content.via = vec![services.globals.config.server_name.clone()];
|
||||
|
||||
services
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: StateEventType::SpaceChild.to_string().into(),
|
||||
content: to_raw_value(&new_content).expect("we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(replacement_room.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&replacement_room,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(event_content) = services
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&body.room_id, &StateEventType::SpaceParent, body.room_id.as_str())
|
||||
.unwrap_or(None)
|
||||
{
|
||||
// space contents that are empty are not apart of the space
|
||||
if !event_content.content.get().is_empty() {
|
||||
// remove all but us from via
|
||||
let mut new_content: SpaceChildEventContent = serde_json::from_str(event_content.content.get())
|
||||
.map_err(|_| err!(Database(error!("Invalid m.space.child content in database"))))?;
|
||||
new_content.via = vec![services.globals.config.server_name.clone()];
|
||||
|
||||
services
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: StateEventType::SpaceParent.to_string().into(),
|
||||
content: to_raw_value(&new_content).expect("we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(replacement_room.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&replacement_room,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// m.room.create
|
||||
services
|
||||
.rooms
|
||||
.timeline
|
||||
@@ -758,11 +822,11 @@ pub(crate) async fn upgrade_room_route(
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&body.room_id, &StateEventType::RoomPowerLevels, "")?
|
||||
.ok_or_else(|| Error::bad_database("Found room without m.room.create event."))?
|
||||
.ok_or_else(|| err!(Database(error!("Found room without m.room.create event."))))?
|
||||
.content
|
||||
.get(),
|
||||
)
|
||||
.map_err(|_| Error::bad_database("Invalid room event in database."))?;
|
||||
.map_err(|_| err!(Database(error!("Invalid room event in database."))))?;
|
||||
|
||||
// Setting events_default and invite to the greater of 50 and users_default + 1
|
||||
let new_level = max(
|
||||
@@ -770,9 +834,7 @@ pub(crate) async fn upgrade_room_route(
|
||||
power_levels_event_content
|
||||
.users_default
|
||||
.checked_add(int!(1))
|
||||
.ok_or_else(|| {
|
||||
Error::BadRequest(ErrorKind::BadJson, "users_default power levels event content is not valid")
|
||||
})?,
|
||||
.ok_or_else(|| err!(Request(BadJson("users_default power levels event content is not valid"))))?,
|
||||
);
|
||||
power_levels_event_content.events_default = new_level;
|
||||
power_levels_event_content.invite = new_level;
|
||||
@@ -836,7 +898,7 @@ fn default_power_levels_content(
|
||||
|
||||
if let Some(power_level_content_override) = power_level_content_override {
|
||||
let json: JsonObject = serde_json::from_str(power_level_content_override.json().get())
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid power_level_content_override."))?;
|
||||
.map_err(|_| err!(Request(BadJson("Invalid power_level_content_override"))))?;
|
||||
|
||||
for (key, value) in json {
|
||||
power_levels_content[key] = value;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use ruma::{
|
||||
api::client::{
|
||||
error::ErrorKind,
|
||||
@@ -56,8 +57,9 @@ pub(crate) async fn get_login_types_route(
|
||||
/// Note: You can use [`GET
|
||||
/// /_matrix/client/r0/login`](fn.get_supported_versions_route.html) to see
|
||||
/// supported login types.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login")]
|
||||
pub(crate) async fn login_route(
|
||||
State(services): State<crate::State>, body: Ruma<login::v3::Request>,
|
||||
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp, body: Ruma<login::v3::Request>,
|
||||
) -> Result<login::v3::Response> {
|
||||
// Validate login method
|
||||
// TODO: Other login methods
|
||||
@@ -176,9 +178,13 @@ pub(crate) async fn login_route(
|
||||
if device_exists {
|
||||
services.users.set_token(&user_id, &device_id, &token)?;
|
||||
} else {
|
||||
services
|
||||
.users
|
||||
.create_device(&user_id, &device_id, &token, body.initial_device_display_name.clone())?;
|
||||
services.users.create_device(
|
||||
&user_id,
|
||||
&device_id,
|
||||
&token,
|
||||
body.initial_device_display_name.clone(),
|
||||
Some(client.to_string()),
|
||||
)?;
|
||||
}
|
||||
|
||||
// send client well-known if specified so the client knows to reconfigure itself
|
||||
@@ -214,8 +220,9 @@ pub(crate) async fn login_route(
|
||||
/// last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout")]
|
||||
pub(crate) async fn logout_route(
|
||||
State(services): State<crate::State>, body: Ruma<logout::v3::Request>,
|
||||
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp, body: Ruma<logout::v3::Request>,
|
||||
) -> Result<logout::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
|
||||
@@ -241,8 +248,10 @@ pub(crate) async fn logout_route(
|
||||
/// Note: This is equivalent to calling [`GET
|
||||
/// /_matrix/client/r0/logout`](fn.logout_route.html) from each device of this
|
||||
/// user.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout")]
|
||||
pub(crate) async fn logout_all_route(
|
||||
State(services): State<crate::State>, body: Ruma<logout_all::v3::Request>,
|
||||
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
|
||||
body: Ruma<logout_all::v3::Request>,
|
||||
) -> Result<logout_all::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
|
||||
@@ -106,11 +106,13 @@ pub(crate) async fn sync_events_route(
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
|
||||
// some clients, at least element, seem to require knowledge of redundant
|
||||
// members for "inline" profiles on the timeline to work properly
|
||||
let (lazy_load_enabled, lazy_load_send_redundant) = match filter.room.state.lazy_load_options {
|
||||
LazyLoadOptions::Enabled {
|
||||
include_redundant_members: redundant,
|
||||
} => (true, redundant),
|
||||
LazyLoadOptions::Disabled => (false, false),
|
||||
include_redundant_members,
|
||||
} => (true, include_redundant_members),
|
||||
LazyLoadOptions::Disabled => (false, cfg!(feature = "element_hacks")),
|
||||
};
|
||||
|
||||
let full_state = body.full_state;
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::time::{Duration, SystemTime};
|
||||
|
||||
use axum::extract::State;
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use conduit::utils;
|
||||
use conduit::{utils, Err};
|
||||
use hmac::{Hmac, Mac};
|
||||
use ruma::{api::client::voip::get_turn_server_info, SecondsSinceUnixEpoch, UserId};
|
||||
use sha1::Sha1;
|
||||
@@ -19,6 +19,11 @@ type HmacSha1 = Hmac<Sha1>;
|
||||
pub(crate) async fn turn_server_route(
|
||||
State(services): State<crate::State>, body: Ruma<get_turn_server_info::v3::Request>,
|
||||
) -> Result<get_turn_server_info::v3::Response> {
|
||||
// MSC4166: return M_NOT_FOUND 404 if no TURN URIs are specified in any way
|
||||
if services.server.config.turn_uris.is_empty() {
|
||||
return Err!(Request(NotFound("Not Found")));
|
||||
}
|
||||
|
||||
let turn_secret = services.globals.turn_secret().clone();
|
||||
|
||||
let (username, password) = if !turn_secret.is_empty() {
|
||||
|
||||
+13
-2
@@ -6,7 +6,7 @@ use axum_extra::{
|
||||
typed_header::TypedHeaderRejectionReason,
|
||||
TypedHeader,
|
||||
};
|
||||
use conduit::{warn, Err, Error, Result};
|
||||
use conduit::{debug_info, warn, Err, Error, Result};
|
||||
use http::uri::PathAndQuery;
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, AuthScheme, Metadata},
|
||||
@@ -185,7 +185,7 @@ fn auth_appservice(services: &Services, request: &Request, info: Box<Registratio
|
||||
async fn auth_server(
|
||||
services: &Services, request: &mut Request, json_body: &Option<CanonicalJsonValue>,
|
||||
) -> Result<Auth> {
|
||||
if !services.globals.allow_federation() {
|
||||
if !services.server.config.allow_federation {
|
||||
return Err!(Config("allow_federation", "Federation is disabled."));
|
||||
}
|
||||
|
||||
@@ -206,6 +206,17 @@ async fn auth_server(
|
||||
})?;
|
||||
|
||||
let origin = &x_matrix.origin;
|
||||
|
||||
if services
|
||||
.server
|
||||
.config
|
||||
.forbidden_remote_server_names
|
||||
.contains(origin)
|
||||
{
|
||||
debug_info!("Refusing to accept inbound federation request to {origin}");
|
||||
return Err!(Request(Forbidden("Federation with this homeserver is not allowed.")));
|
||||
}
|
||||
|
||||
let signatures =
|
||||
BTreeMap::from_iter([(x_matrix.key.clone(), CanonicalJsonValue::String(x_matrix.sig.to_string()))]);
|
||||
let signatures = BTreeMap::from_iter([(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::ffi::OsStr;
|
||||
|
||||
use super::{path, Library};
|
||||
use crate::{Error, Result};
|
||||
use crate::{Err, Result};
|
||||
|
||||
const OPEN_FLAGS: i32 = libloading::os::unix::RTLD_LAZY | libloading::os::unix::RTLD_GLOBAL;
|
||||
|
||||
@@ -16,7 +16,7 @@ pub fn from_path(path: &OsStr) -> Result<Library> {
|
||||
let lib = unsafe { Library::open(Some(path), OPEN_FLAGS) };
|
||||
if let Err(e) = lib {
|
||||
let name = path::to_name(path)?;
|
||||
return Err(Error::Err(format!("Loading module {name:?} failed: {e}")));
|
||||
return Err!("Loading module {name:?} failed: {e}");
|
||||
}
|
||||
|
||||
Ok(lib.expect("module loaded"))
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ impl PduEvent {
|
||||
// deliberately allowing for the possibility of negative age
|
||||
let now: i128 = MilliSecondsSinceUnixEpoch::now().get().into();
|
||||
let then: i128 = self.origin_server_ts.into();
|
||||
let this_age: i128 = now.saturating_sub(then);
|
||||
let this_age = now.saturating_sub(then);
|
||||
|
||||
unsigned.insert("age".to_owned(), to_raw_value(&this_age).unwrap());
|
||||
self.unsigned = Some(to_raw_value(&unsigned).expect("unsigned is valid"));
|
||||
|
||||
+19
-5
@@ -1,10 +1,11 @@
|
||||
use std::{
|
||||
collections::{BTreeSet, HashMap},
|
||||
fmt::Write,
|
||||
path::PathBuf,
|
||||
sync::{atomic::AtomicU32, Arc, Mutex, RwLock},
|
||||
};
|
||||
|
||||
use conduit::{debug, error, info, utils::time::rfc2822_from_seconds, warn, Result, Server};
|
||||
use conduit::{debug, error, info, utils::time::rfc2822_from_seconds, warn, Err, Result, Server};
|
||||
use rocksdb::{
|
||||
backup::{BackupEngine, BackupEngineOptions},
|
||||
perf::get_memory_usage_stats,
|
||||
@@ -50,10 +51,7 @@ impl Engine {
|
||||
|
||||
let load_time = std::time::Instant::now();
|
||||
if config.rocksdb_repair {
|
||||
warn!("Starting database repair. This may take a long time...");
|
||||
if let Err(e) = Db::repair(&db_opts, &config.database_path) {
|
||||
error!("Repair failed: {e:?}");
|
||||
}
|
||||
repair(&db_opts, &config.database_path)?;
|
||||
}
|
||||
|
||||
debug!("Listing column families in database");
|
||||
@@ -77,6 +75,7 @@ impl Engine {
|
||||
|
||||
let db = res.or_else(or_else)?;
|
||||
info!(
|
||||
columns = cfs.len(),
|
||||
sequence = %db.latest_sequence_number(),
|
||||
time = ?load_time.elapsed(),
|
||||
"Opened database."
|
||||
@@ -243,6 +242,16 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn repair(db_opts: &Options, path: &PathBuf) -> Result<()> {
|
||||
warn!("Starting database repair. This may take a long time...");
|
||||
match Db::repair(db_opts, path) {
|
||||
Ok(()) => info!("Database repair successful."),
|
||||
Err(e) => return Err!("Repair failed: {e:?}"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Drop for Engine {
|
||||
#[cold]
|
||||
fn drop(&mut self) {
|
||||
@@ -259,5 +268,10 @@ impl Drop for Engine {
|
||||
|
||||
debug!("Joining background threads...");
|
||||
self.env.join_all_threads();
|
||||
|
||||
info!(
|
||||
sequence = %self.db.latest_sequence_number(),
|
||||
"Closing database..."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -9,11 +9,13 @@ pub(super) fn flags_capture(args: TokenStream) -> TokenStream {
|
||||
};
|
||||
|
||||
let flag = std::env::args().collect::<Vec<_>>();
|
||||
let flag_len = flag.len();
|
||||
let ret = quote! {
|
||||
pub static RUSTC_FLAGS: [&str; #flag_len] = [#( #flag ),*];
|
||||
|
||||
#[conduit_core::ctor]
|
||||
fn _set_rustc_flags() {
|
||||
let flags = &[#( #flag ),*];
|
||||
conduit_core::info::rustc::FLAGS.lock().expect("locked").insert(#crate_name, flags);
|
||||
conduit_core::info::rustc::FLAGS.lock().expect("locked").insert(#crate_name, &RUSTC_FLAGS);
|
||||
}
|
||||
|
||||
// static strings have to be yanked on module unload
|
||||
|
||||
+41
-13
@@ -1,18 +1,27 @@
|
||||
#![cfg(conduit_mods)]
|
||||
|
||||
#[no_link]
|
||||
extern crate conduit_service;
|
||||
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
sync::{atomic::Ordering, Arc},
|
||||
};
|
||||
|
||||
use conduit::{mods, Error, Result};
|
||||
use tracing::{debug, error};
|
||||
use conduit::{debug, error, mods, Error, Result};
|
||||
use conduit_service::Services;
|
||||
|
||||
use crate::Server;
|
||||
|
||||
type RunFuncResult = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
|
||||
type RunFuncProto = fn(&Arc<conduit::Server>) -> RunFuncResult;
|
||||
type StartFuncResult = Pin<Box<dyn Future<Output = Result<Arc<Services>>> + Send>>;
|
||||
type StartFuncProto = fn(&Arc<conduit::Server>) -> StartFuncResult;
|
||||
|
||||
type RunFuncResult = Pin<Box<dyn Future<Output = Result<()>> + Send>>;
|
||||
type RunFuncProto = fn(&Arc<Services>) -> RunFuncResult;
|
||||
|
||||
type StopFuncResult = Pin<Box<dyn Future<Output = Result<()>> + Send>>;
|
||||
type StopFuncProto = fn(Arc<Services>) -> StopFuncResult;
|
||||
|
||||
const RESTART_THRESH: &str = "conduit_service";
|
||||
const MODULE_NAMES: &[&str] = &[
|
||||
@@ -33,15 +42,25 @@ pub(crate) async fn run(server: &Arc<Server>, starts: bool) -> Result<(bool, boo
|
||||
let main_lock = server.mods.read().await;
|
||||
let main_mod = (*main_lock).last().expect("main module loaded");
|
||||
if starts {
|
||||
let start = main_mod.get::<RunFuncProto>("start")?;
|
||||
if let Err(error) = start(&server.server).await {
|
||||
error!("Starting server: {error}");
|
||||
return Err(error);
|
||||
}
|
||||
let start = main_mod.get::<StartFuncProto>("start")?;
|
||||
match start(&server.server).await {
|
||||
Ok(services) => server.services.lock().await.insert(services),
|
||||
Err(error) => {
|
||||
error!("Starting server: {error}");
|
||||
return Err(error);
|
||||
},
|
||||
};
|
||||
}
|
||||
server.server.stopping.store(false, Ordering::Release);
|
||||
let run = main_mod.get::<RunFuncProto>("run")?;
|
||||
if let Err(error) = run(&server.server).await {
|
||||
if let Err(error) = run(server
|
||||
.services
|
||||
.lock()
|
||||
.await
|
||||
.as_ref()
|
||||
.expect("services initialized"))
|
||||
.await
|
||||
{
|
||||
error!("Running server: {error}");
|
||||
return Err(error);
|
||||
}
|
||||
@@ -49,8 +68,17 @@ pub(crate) async fn run(server: &Arc<Server>, starts: bool) -> Result<(bool, boo
|
||||
let stops = !reloads || stale(server).await? <= restart_thresh();
|
||||
let starts = reloads && stops;
|
||||
if stops {
|
||||
let stop = main_mod.get::<RunFuncProto>("stop")?;
|
||||
if let Err(error) = stop(&server.server).await {
|
||||
let stop = main_mod.get::<StopFuncProto>("stop")?;
|
||||
if let Err(error) = stop(
|
||||
server
|
||||
.services
|
||||
.lock()
|
||||
.await
|
||||
.take()
|
||||
.expect("services initialized"),
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Stopping server: {error}");
|
||||
return Err(error);
|
||||
}
|
||||
@@ -103,7 +131,7 @@ pub(crate) async fn close(server: &Arc<Server>, force: bool) -> Result<usize, Er
|
||||
|
||||
async fn stale_count(server: &Arc<Server>) -> usize {
|
||||
let watermark = stale(server).await.unwrap_or(available());
|
||||
available() - watermark
|
||||
available().saturating_sub(watermark)
|
||||
}
|
||||
|
||||
async fn stale(server: &Arc<Server>) -> Result<usize, Error> {
|
||||
|
||||
@@ -5,7 +5,7 @@ mod grant;
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
sync::{Arc, RwLock as StdRwLock},
|
||||
sync::{Arc, RwLock as StdRwLock, Weak},
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
@@ -41,7 +41,7 @@ struct Services {
|
||||
timeline: Dep<rooms::timeline::Service>,
|
||||
state: Dep<rooms::state::Service>,
|
||||
state_cache: Dep<rooms::state_cache::Service>,
|
||||
services: StdRwLock<Option<Arc<crate::Services>>>,
|
||||
services: StdRwLock<Option<Weak<crate::Services>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -174,7 +174,14 @@ impl Service {
|
||||
}
|
||||
|
||||
async fn process_command(&self, command: CommandInput) -> CommandResult {
|
||||
let Some(services) = self.services.services.read().expect("locked").clone() else {
|
||||
let Some(services) = self
|
||||
.services
|
||||
.services
|
||||
.read()
|
||||
.expect("locked")
|
||||
.as_ref()
|
||||
.and_then(Weak::upgrade)
|
||||
else {
|
||||
return Err!("Services self-reference not initialized.");
|
||||
};
|
||||
|
||||
@@ -365,7 +372,9 @@ impl Service {
|
||||
|
||||
/// Sets the self-reference to crate::Services which will provide context to
|
||||
/// the admin commands.
|
||||
pub(super) fn set_services(&self, services: Option<Arc<crate::Services>>) {
|
||||
*self.services.services.write().expect("locked for writing") = services;
|
||||
pub(super) fn set_services(&self, services: &Option<Arc<crate::Services>>) {
|
||||
let receiver = &mut *self.services.services.write().expect("locked for writing");
|
||||
let weak = services.as_ref().map(Arc::downgrade);
|
||||
*receiver = weak;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,8 @@ impl Manager {
|
||||
.read()
|
||||
.expect("locked for reading")
|
||||
.values()
|
||||
.map(|v| v.0.clone())
|
||||
.map(|val| val.0.upgrade())
|
||||
.map(|arc| arc.expect("services available for manager startup"))
|
||||
.collect();
|
||||
|
||||
debug!("Starting service workers...");
|
||||
|
||||
@@ -4,7 +4,8 @@ use conduit::{debug_warn, utils, Error, Result};
|
||||
use database::Map;
|
||||
use ruma::{events::presence::PresenceEvent, presence::PresenceState, OwnedUserId, UInt, UserId};
|
||||
|
||||
use crate::{globals, presence::Presence, users, Dep};
|
||||
use super::Presence;
|
||||
use crate::{globals, users, Dep};
|
||||
|
||||
pub struct Data {
|
||||
presenceid_presence: Arc<Map>,
|
||||
@@ -60,6 +61,22 @@ impl Data {
|
||||
Some(ref presence) => presence.1.content.presence != *presence_state,
|
||||
};
|
||||
|
||||
let status_msg_changed = match last_presence {
|
||||
None => true,
|
||||
Some(ref last_presence) => {
|
||||
let old_msg = last_presence
|
||||
.1
|
||||
.content
|
||||
.status_msg
|
||||
.clone()
|
||||
.unwrap_or_default();
|
||||
|
||||
let new_msg = status_msg.clone().unwrap_or_default();
|
||||
|
||||
new_msg != old_msg
|
||||
},
|
||||
};
|
||||
|
||||
let now = utils::millis_since_unix_epoch();
|
||||
let last_last_active_ts = match last_presence {
|
||||
None => 0,
|
||||
@@ -71,10 +88,10 @@ impl Data {
|
||||
Some(last_active_ago) => now.saturating_sub(last_active_ago.into()),
|
||||
};
|
||||
|
||||
// tighten for state flicker?
|
||||
if !state_changed && last_active_ts <= last_last_active_ts {
|
||||
// TODO: tighten for state flicker?
|
||||
if !status_msg_changed && !state_changed && last_active_ts < last_last_active_ts {
|
||||
debug_warn!(
|
||||
"presence spam {:?} last_active_ts:{:?} <= {:?}",
|
||||
"presence spam {:?} last_active_ts:{:?} < {:?}",
|
||||
user_id,
|
||||
last_active_ts,
|
||||
last_last_active_ts
|
||||
|
||||
+16
-70
@@ -1,81 +1,25 @@
|
||||
mod data;
|
||||
mod presence;
|
||||
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use conduit::{checked, debug, error, utils, Error, Result, Server};
|
||||
use conduit::{checked, debug, error, Error, Result, Server};
|
||||
use futures_util::{stream::FuturesUnordered, StreamExt};
|
||||
use ruma::{
|
||||
events::presence::{PresenceEvent, PresenceEventContent},
|
||||
presence::PresenceState,
|
||||
OwnedUserId, UInt, UserId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ruma::{events::presence::PresenceEvent, presence::PresenceState, OwnedUserId, UInt, UserId};
|
||||
use tokio::{sync::Mutex, time::sleep};
|
||||
|
||||
use self::data::Data;
|
||||
use self::{data::Data, presence::Presence};
|
||||
use crate::{globals, users, Dep};
|
||||
|
||||
/// Represents data required to be kept in order to implement the presence
|
||||
/// specification.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Presence {
|
||||
state: PresenceState,
|
||||
currently_active: bool,
|
||||
last_active_ts: u64,
|
||||
status_msg: Option<String>,
|
||||
}
|
||||
|
||||
impl Presence {
|
||||
#[must_use]
|
||||
pub fn new(state: PresenceState, currently_active: bool, last_active_ts: u64, status_msg: Option<String>) -> Self {
|
||||
Self {
|
||||
state,
|
||||
currently_active,
|
||||
last_active_ts,
|
||||
status_msg,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_json_bytes(bytes: &[u8]) -> Result<Self> {
|
||||
serde_json::from_slice(bytes).map_err(|_| Error::bad_database("Invalid presence data in database"))
|
||||
}
|
||||
|
||||
pub fn to_json_bytes(&self) -> Result<Vec<u8>> {
|
||||
serde_json::to_vec(self).map_err(|_| Error::bad_database("Could not serialize Presence to JSON"))
|
||||
}
|
||||
|
||||
/// Creates a PresenceEvent from available data.
|
||||
pub fn to_presence_event(&self, user_id: &UserId, users: &users::Service) -> Result<PresenceEvent> {
|
||||
let now = utils::millis_since_unix_epoch();
|
||||
let last_active_ago = if self.currently_active {
|
||||
None
|
||||
} else {
|
||||
Some(UInt::new_saturating(now.saturating_sub(self.last_active_ts)))
|
||||
};
|
||||
|
||||
Ok(PresenceEvent {
|
||||
sender: user_id.to_owned(),
|
||||
content: PresenceEventContent {
|
||||
presence: self.state.clone(),
|
||||
status_msg: self.status_msg.clone(),
|
||||
currently_active: Some(self.currently_active),
|
||||
last_active_ago,
|
||||
displayname: users.displayname(user_id)?,
|
||||
avatar_url: users.avatar_url(user_id)?,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Service {
|
||||
services: Services,
|
||||
pub db: Data,
|
||||
pub timer_sender: loole::Sender<(OwnedUserId, Duration)>,
|
||||
timer_receiver: Mutex<loole::Receiver<(OwnedUserId, Duration)>>,
|
||||
timer_sender: loole::Sender<TimerType>,
|
||||
timer_receiver: Mutex<loole::Receiver<TimerType>>,
|
||||
timeout_remote_users: bool,
|
||||
idle_timeout: u64,
|
||||
offline_timeout: u64,
|
||||
pub db: Data,
|
||||
services: Services,
|
||||
}
|
||||
|
||||
struct Services {
|
||||
@@ -84,6 +28,8 @@ struct Services {
|
||||
users: Dep<users::Service>,
|
||||
}
|
||||
|
||||
type TimerType = (OwnedUserId, Duration);
|
||||
|
||||
#[async_trait]
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
@@ -92,17 +38,17 @@ impl crate::Service for Service {
|
||||
let offline_timeout_s = config.presence_offline_timeout_s;
|
||||
let (timer_sender, timer_receiver) = loole::unbounded();
|
||||
Ok(Arc::new(Self {
|
||||
services: Services {
|
||||
server: args.server.clone(),
|
||||
globals: args.depend::<globals::Service>("globals"),
|
||||
users: args.depend::<users::Service>("users"),
|
||||
},
|
||||
db: Data::new(&args),
|
||||
timer_sender,
|
||||
timer_receiver: Mutex::new(timer_receiver),
|
||||
timeout_remote_users: config.presence_timeout_remote_users,
|
||||
idle_timeout: checked!(idle_timeout_s * 1_000)?,
|
||||
offline_timeout: checked!(offline_timeout_s * 1_000)?,
|
||||
db: Data::new(&args),
|
||||
services: Services {
|
||||
server: args.server.clone(),
|
||||
globals: args.depend::<globals::Service>("globals"),
|
||||
users: args.depend::<users::Service>("users"),
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{utils, Error, Result};
|
||||
use ruma::{
|
||||
events::presence::{PresenceEvent, PresenceEventContent},
|
||||
presence::PresenceState,
|
||||
UInt, UserId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::users;
|
||||
|
||||
/// Represents data required to be kept in order to implement the presence
|
||||
/// specification.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub(super) struct Presence {
|
||||
state: PresenceState,
|
||||
currently_active: bool,
|
||||
last_active_ts: u64,
|
||||
status_msg: Option<String>,
|
||||
}
|
||||
|
||||
impl Presence {
|
||||
#[must_use]
|
||||
pub(super) fn new(
|
||||
state: PresenceState, currently_active: bool, last_active_ts: u64, status_msg: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
state,
|
||||
currently_active,
|
||||
last_active_ts,
|
||||
status_msg,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn from_json_bytes(bytes: &[u8]) -> Result<Self> {
|
||||
serde_json::from_slice(bytes).map_err(|_| Error::bad_database("Invalid presence data in database"))
|
||||
}
|
||||
|
||||
pub(super) fn to_json_bytes(&self) -> Result<Vec<u8>> {
|
||||
serde_json::to_vec(self).map_err(|_| Error::bad_database("Could not serialize Presence to JSON"))
|
||||
}
|
||||
|
||||
/// Creates a PresenceEvent from available data.
|
||||
pub(super) fn to_presence_event(&self, user_id: &UserId, users: &Arc<users::Service>) -> Result<PresenceEvent> {
|
||||
let now = utils::millis_since_unix_epoch();
|
||||
let last_active_ago = if self.currently_active {
|
||||
None
|
||||
} else {
|
||||
Some(UInt::new_saturating(now.saturating_sub(self.last_active_ts)))
|
||||
};
|
||||
|
||||
Ok(PresenceEvent {
|
||||
sender: user_id.to_owned(),
|
||||
content: PresenceEventContent {
|
||||
presence: self.state.clone(),
|
||||
status_msg: self.status_msg.clone(),
|
||||
currently_active: Some(self.currently_active),
|
||||
last_active_ago,
|
||||
displayname: users.displayname(user_id)?,
|
||||
avatar_url: users.avatar_url(user_id)?,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -189,7 +189,7 @@ impl super::Service {
|
||||
.services
|
||||
.client
|
||||
.well_known
|
||||
.get(&format!("https://{dest}/.well-known/matrix/server"))
|
||||
.get(format!("https://{dest}/.well-known/matrix/server"))
|
||||
.send()
|
||||
.await;
|
||||
|
||||
|
||||
@@ -12,17 +12,19 @@ use ruma::{DeviceId, OwnedDeviceId, OwnedRoomId, OwnedUserId, RoomId, UserId};
|
||||
use self::data::Data;
|
||||
|
||||
pub struct Service {
|
||||
pub lazy_load_waiting: Mutex<LazyLoadWaiting>,
|
||||
db: Data,
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub lazy_load_waiting: Mutex<HashMap<(OwnedUserId, OwnedDeviceId, OwnedRoomId, PduCount), HashSet<OwnedUserId>>>,
|
||||
}
|
||||
|
||||
type LazyLoadWaiting = HashMap<LazyLoadWaitingKey, LazyLoadWaitingVal>;
|
||||
type LazyLoadWaitingKey = (OwnedUserId, OwnedDeviceId, OwnedRoomId, PduCount);
|
||||
type LazyLoadWaitingVal = HashSet<OwnedUserId>;
|
||||
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
lazy_load_waiting: Mutex::new(HashMap::new()),
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::{fmt::Debug, mem};
|
||||
|
||||
use conduit::{
|
||||
debug, debug_error, debug_warn, error::inspect_debug_log, trace, utils::string::EMPTY, Err, Error, Result,
|
||||
debug, debug_error, debug_info, debug_warn, error::inspect_debug_log, trace, utils::string::EMPTY, Err, Error,
|
||||
Result,
|
||||
};
|
||||
use http::{header::AUTHORIZATION, HeaderValue};
|
||||
use ipaddress::IPAddress;
|
||||
@@ -31,6 +32,16 @@ impl super::Service {
|
||||
return Err!(Config("allow_federation", "Federation is disabled."));
|
||||
}
|
||||
|
||||
if self
|
||||
.server
|
||||
.config
|
||||
.forbidden_remote_server_names
|
||||
.contains(&dest.to_owned())
|
||||
{
|
||||
debug_info!("Refusing to send outbound federation request to {dest}");
|
||||
return Err!(Request(Forbidden("Federation with this homeserver is not allowed.")));
|
||||
}
|
||||
|
||||
let actual = self.services.resolver.get_actual_dest(dest).await?;
|
||||
let request = self.prepare::<T>(dest, &actual, req).await?;
|
||||
self.execute::<T>(dest, &actual, request, client).await
|
||||
|
||||
+47
-32
@@ -3,7 +3,7 @@ use std::{
|
||||
collections::BTreeMap,
|
||||
fmt::Write,
|
||||
ops::Deref,
|
||||
sync::{Arc, OnceLock, RwLock},
|
||||
sync::{Arc, OnceLock, RwLock, Weak},
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
@@ -53,77 +53,92 @@ pub(crate) struct Args<'a> {
|
||||
/// Circular-dependencies between services require this indirection.
|
||||
pub(crate) struct Dep<T> {
|
||||
dep: OnceLock<Arc<T>>,
|
||||
service: Arc<Map>,
|
||||
service: Weak<Map>,
|
||||
name: &'static str,
|
||||
}
|
||||
|
||||
pub(crate) type Map = RwLock<BTreeMap<String, MapVal>>;
|
||||
pub(crate) type MapVal = (Arc<dyn Service>, Arc<dyn Any + Send + Sync>);
|
||||
pub(crate) type Map = RwLock<MapType>;
|
||||
pub(crate) type MapType = BTreeMap<MapKey, MapVal>;
|
||||
pub(crate) type MapVal = (Weak<dyn Service>, Weak<dyn Any + Send + Sync>);
|
||||
pub(crate) type MapKey = String;
|
||||
|
||||
impl<T: Send + Sync + 'static> Deref for Dep<T> {
|
||||
type Target = Arc<T>;
|
||||
|
||||
/// Dereference a dependency. The dependency must be ready or panics.
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.dep
|
||||
.get_or_init(|| require::<T>(&self.service, self.name))
|
||||
self.dep.get_or_init(|| {
|
||||
let service = self
|
||||
.service
|
||||
.upgrade()
|
||||
.expect("services map exists for dependency initialization.");
|
||||
|
||||
require::<T>(&service, self.name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Args<'_> {
|
||||
impl<'a> Args<'a> {
|
||||
/// Create a lazy-reference to a service when constructing another Service.
|
||||
pub(crate) fn depend<T: Send + Sync + 'static>(&self, name: &'static str) -> Dep<T> {
|
||||
pub(crate) fn depend<T: Send + Sync + 'a + 'static>(&'a self, name: &'static str) -> Dep<T> {
|
||||
Dep::<T> {
|
||||
dep: OnceLock::new(),
|
||||
service: self.service.clone(),
|
||||
service: Arc::downgrade(self.service),
|
||||
name,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a reference immediately to a service when constructing another
|
||||
/// Service. The other service must be constructed.
|
||||
pub(crate) fn require<T: Send + Sync + 'static>(&self, name: &str) -> Arc<T> { require::<T>(self.service, name) }
|
||||
pub(crate) fn require<T: Send + Sync + 'a + 'static>(&'a self, name: &'static str) -> Arc<T> {
|
||||
require::<T>(self.service, name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reference a Service by name. Panics if the Service does not exist or was
|
||||
/// incorrectly cast.
|
||||
pub(crate) fn require<T: Send + Sync + 'static>(map: &Map, name: &str) -> Arc<T> {
|
||||
pub(crate) fn require<'a, 'b, T: Send + Sync + 'a + 'b + 'static>(map: &'b Map, name: &'a str) -> Arc<T> {
|
||||
try_get::<T>(map, name)
|
||||
.inspect_err(inspect_log)
|
||||
.expect("Failure to reference service required by another service.")
|
||||
}
|
||||
|
||||
/// Reference a Service by name. Returns Err if the Service does not exist or
|
||||
/// was incorrectly cast.
|
||||
pub(crate) fn try_get<T: Send + Sync + 'static>(map: &Map, name: &str) -> Result<Arc<T>> {
|
||||
map.read()
|
||||
.expect("locked for reading")
|
||||
.get(name)
|
||||
.map_or_else(
|
||||
|| Err!("Service {name:?} does not exist or has not been built yet."),
|
||||
|(_, s)| {
|
||||
s.clone()
|
||||
.downcast::<T>()
|
||||
.map_err(|_| err!("Service {name:?} must be correctly downcast."))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Reference a Service by name. Returns None if the Service does not exist, but
|
||||
/// panics if incorrectly cast.
|
||||
///
|
||||
/// # Panics
|
||||
/// Incorrect type is not a silent failure (None) as the type never has a reason
|
||||
/// to be incorrect.
|
||||
pub(crate) fn get<T: Send + Sync + 'static>(map: &Map, name: &str) -> Option<Arc<T>> {
|
||||
pub(crate) fn get<'a, 'b, T: Send + Sync + 'a + 'b + 'static>(map: &'b Map, name: &'a str) -> Option<Arc<T>> {
|
||||
map.read()
|
||||
.expect("locked for reading")
|
||||
.get(name)
|
||||
.map(|(_, s)| {
|
||||
s.clone()
|
||||
.downcast::<T>()
|
||||
.expect("Service must be correctly downcast.")
|
||||
})
|
||||
s.upgrade().map(|s| {
|
||||
s.downcast::<T>()
|
||||
.expect("Service must be correctly downcast.")
|
||||
})
|
||||
})?
|
||||
}
|
||||
|
||||
/// Reference a Service by name. Returns Err if the Service does not exist or
|
||||
/// was incorrectly cast.
|
||||
pub(crate) fn try_get<'a, 'b, T: Send + Sync + 'a + 'b + 'static>(map: &'b Map, name: &'a str) -> Result<Arc<T>> {
|
||||
map.read()
|
||||
.expect("locked for reading")
|
||||
.get(name)
|
||||
.map_or_else(
|
||||
|| Err!("Service {name:?} does not exist or has not been built yet."),
|
||||
|(_, s)| {
|
||||
s.upgrade().map_or_else(
|
||||
|| Err!("Service {name:?} no longer exists."),
|
||||
|s| {
|
||||
s.downcast::<T>()
|
||||
.map_err(|_| err!("Service {name:?} must be correctly downcast."))
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Utility for service implementations; see Service::name() in the trait.
|
||||
|
||||
+18
-11
@@ -109,7 +109,7 @@ impl Services {
|
||||
pub async fn start(self: &Arc<Self>) -> Result<Arc<Self>> {
|
||||
debug_info!("Starting services...");
|
||||
|
||||
self.admin.set_services(Some(Arc::clone(self)));
|
||||
self.admin.set_services(&Some(Arc::clone(self)));
|
||||
globals::migrations::migrations(self).await?;
|
||||
self.manager
|
||||
.lock()
|
||||
@@ -131,7 +131,7 @@ impl Services {
|
||||
manager.stop().await;
|
||||
}
|
||||
|
||||
self.admin.set_services(None);
|
||||
self.admin.set_services(&None);
|
||||
|
||||
debug_info!("Services shutdown complete.");
|
||||
}
|
||||
@@ -146,7 +146,9 @@ impl Services {
|
||||
|
||||
pub async fn clear_cache(&self) {
|
||||
for (service, ..) in self.service.read().expect("locked for reading").values() {
|
||||
service.clear_cache();
|
||||
if let Some(service) = service.upgrade() {
|
||||
service.clear_cache();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
@@ -161,7 +163,9 @@ impl Services {
|
||||
pub async fn memory_usage(&self) -> Result<String> {
|
||||
let mut out = String::new();
|
||||
for (service, ..) in self.service.read().expect("locked for reading").values() {
|
||||
service.memory_usage(&mut out)?;
|
||||
if let Some(service) = service.upgrade() {
|
||||
service.memory_usage(&mut out)?;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
@@ -179,27 +183,30 @@ impl Services {
|
||||
|
||||
fn interrupt(&self) {
|
||||
debug!("Interrupting services...");
|
||||
|
||||
for (name, (service, ..)) in self.service.read().expect("locked for reading").iter() {
|
||||
trace!("Interrupting {name}");
|
||||
service.interrupt();
|
||||
if let Some(service) = service.upgrade() {
|
||||
trace!("Interrupting {name}");
|
||||
service.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_get<T: Send + Sync + 'static>(&self, name: &str) -> Result<Arc<T>> {
|
||||
pub fn try_get<'a, 'b, T: Send + Sync + 'a + 'b + 'static>(&'b self, name: &'a str) -> Result<Arc<T>> {
|
||||
service::try_get::<T>(&self.service, name)
|
||||
}
|
||||
|
||||
pub fn get<T: Send + Sync + 'static>(&self, name: &str) -> Option<Arc<T>> { service::get::<T>(&self.service, name) }
|
||||
pub fn get<'a, 'b, T: Send + Sync + 'a + 'b + 'static>(&'b self, name: &'a str) -> Option<Arc<T>> {
|
||||
service::get::<T>(&self.service, name)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
fn add_service(map: &Arc<Map>, s: Arc<dyn Service>, a: Arc<dyn Any + Send + Sync>) {
|
||||
let name = s.name();
|
||||
let len = map.read().expect("locked for reading").len();
|
||||
|
||||
trace!("built service #{len}: {name:?}");
|
||||
|
||||
map.write()
|
||||
.expect("locked for writing")
|
||||
.insert(name.to_owned(), (s, a));
|
||||
.insert(name.to_owned(), (Arc::downgrade(&s), Arc::downgrade(&a)));
|
||||
}
|
||||
|
||||
@@ -246,6 +246,7 @@ impl Data {
|
||||
/// Adds a new device to a user.
|
||||
pub(super) fn create_device(
|
||||
&self, user_id: &UserId, device_id: &DeviceId, token: &str, initial_device_display_name: Option<String>,
|
||||
client_ip: Option<String>,
|
||||
) -> Result<()> {
|
||||
// This method should never be called for nonexistent users. We shouldn't assert
|
||||
// though...
|
||||
@@ -266,7 +267,7 @@ impl Data {
|
||||
&serde_json::to_vec(&Device {
|
||||
device_id: device_id.into(),
|
||||
display_name: initial_device_display_name,
|
||||
last_seen_ip: None, // TODO
|
||||
last_seen_ip: client_ip,
|
||||
last_seen_ts: Some(MilliSecondsSinceUnixEpoch::now()),
|
||||
})
|
||||
.expect("Device::to_string never fails."),
|
||||
|
||||
+17
-14
@@ -26,19 +26,10 @@ use ruma::{
|
||||
use self::data::Data;
|
||||
use crate::{admin, rooms, Dep};
|
||||
|
||||
pub struct SlidingSyncCache {
|
||||
lists: BTreeMap<String, SyncRequestList>,
|
||||
subscriptions: BTreeMap<OwnedRoomId, sync_events::v4::RoomSubscription>,
|
||||
known_rooms: BTreeMap<String, BTreeMap<OwnedRoomId, u64>>, // For every room, the roomsince number
|
||||
extensions: ExtensionsConfig,
|
||||
}
|
||||
|
||||
type DbConnections = Mutex<BTreeMap<(OwnedUserId, OwnedDeviceId, String), Arc<Mutex<SlidingSyncCache>>>>;
|
||||
|
||||
pub struct Service {
|
||||
services: Services,
|
||||
connections: DbConnections,
|
||||
pub db: Data,
|
||||
pub connections: DbConnections,
|
||||
services: Services,
|
||||
}
|
||||
|
||||
struct Services {
|
||||
@@ -49,18 +40,29 @@ struct Services {
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
connections: StdMutex::new(BTreeMap::new()),
|
||||
db: Data::new(&args),
|
||||
services: Services {
|
||||
admin: args.depend::<admin::Service>("admin"),
|
||||
state_cache: args.depend::<rooms::state_cache::Service>("rooms::state_cache"),
|
||||
},
|
||||
db: Data::new(&args),
|
||||
connections: StdMutex::new(BTreeMap::new()),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
type DbConnections = Mutex<BTreeMap<DbConnectionsKey, DbConnectionsVal>>;
|
||||
type DbConnectionsKey = (OwnedUserId, OwnedDeviceId, String);
|
||||
type DbConnectionsVal = Arc<Mutex<SlidingSyncCache>>;
|
||||
|
||||
struct SlidingSyncCache {
|
||||
lists: BTreeMap<String, SyncRequestList>,
|
||||
subscriptions: BTreeMap<OwnedRoomId, sync_events::v4::RoomSubscription>,
|
||||
known_rooms: BTreeMap<String, BTreeMap<OwnedRoomId, u64>>, // For every room, the roomsince number
|
||||
extensions: ExtensionsConfig,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Check if a user has an account on this homeserver.
|
||||
#[inline]
|
||||
@@ -326,9 +328,10 @@ impl Service {
|
||||
/// Adds a new device to a user.
|
||||
pub fn create_device(
|
||||
&self, user_id: &UserId, device_id: &DeviceId, token: &str, initial_device_display_name: Option<String>,
|
||||
client_ip: Option<String>,
|
||||
) -> Result<()> {
|
||||
self.db
|
||||
.create_device(user_id, device_id, token, initial_device_display_name)
|
||||
.create_device(user_id, device_id, token, initial_device_display_name, client_ip)
|
||||
}
|
||||
|
||||
/// Removes a device from a user.
|
||||
|
||||
Reference in New Issue
Block a user