diff --git a/Cargo.lock b/Cargo.lock
index 45a5edd9..225dc09a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -214,9 +214,9 @@ checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
[[package]]
name = "bytemuck"
-version = "1.3.0"
+version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d40636046a60a45ee5185e885a3ccb771f7a2065fb7cbcc2a7ecfd9896d1c365"
+checksum = "db7a1029718df60331e557c9e83a55523c955e5dd2a7bfeffad6bbd50b538ae9"
[[package]]
name = "byteorder"
@@ -275,6 +275,7 @@ dependencies = [
"serde_json",
"sled",
"thiserror",
+ "tokio",
]
[[package]]
@@ -813,9 +814,9 @@ dependencies = [
[[package]]
name = "image"
-version = "0.23.7"
+version = "0.23.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2397fc43bd5648b7117aabb3c5e62d0e62c194826ec77b0b4d0c41e62744635"
+checksum = "543904170510c1b5fb65140485d84de4a57fddb2ed685481e9020ce3d2c9f64c"
dependencies = [
"bytemuck",
"byteorder",
@@ -881,9 +882,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.42"
+version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52732a3d3ad72c58ad2dc70624f9c17b46ecd0943b9a4f1ee37c4c18c5d983e2"
+checksum = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73"
dependencies = [
"wasm-bindgen",
]
@@ -915,9 +916,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.73"
+version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9"
+checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
[[package]]
name = "lock_api"
@@ -1238,18 +1239,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-project"
-version = "0.4.22"
+version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17"
+checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
-version = "0.4.22"
+version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7"
+checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f"
dependencies = [
"proc-macro2",
"quote",
@@ -1304,9 +1305,9 @@ checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
[[package]]
name = "proc-macro-hack"
-version = "0.5.16"
+version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
+checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598"
[[package]]
name = "proc-macro-nested"
@@ -1484,7 +1485,7 @@ dependencies = [
[[package]]
name = "rocket"
version = "0.5.0-dev"
-source = "git+https://github.com/SergioBenitez/Rocket.git?rev=8d779caa22c63b15a6c3ceb75d8f6d4971b2eb67#8d779caa22c63b15a6c3ceb75d8f6d4971b2eb67"
+source = "git+https://github.com/timokoesters/Rocket.git?branch=empty_parameters#f6d40ecd5d871d97837b3116eb670fb3c06d95b9"
dependencies = [
"async-trait",
"atomic",
@@ -1509,7 +1510,7 @@ dependencies = [
[[package]]
name = "rocket_codegen"
version = "0.5.0-dev"
-source = "git+https://github.com/SergioBenitez/Rocket.git?rev=8d779caa22c63b15a6c3ceb75d8f6d4971b2eb67#8d779caa22c63b15a6c3ceb75d8f6d4971b2eb67"
+source = "git+https://github.com/timokoesters/Rocket.git?branch=empty_parameters#f6d40ecd5d871d97837b3116eb670fb3c06d95b9"
dependencies = [
"devise",
"glob",
@@ -1521,7 +1522,7 @@ dependencies = [
[[package]]
name = "rocket_http"
version = "0.5.0-dev"
-source = "git+https://github.com/SergioBenitez/Rocket.git?rev=8d779caa22c63b15a6c3ceb75d8f6d4971b2eb67#8d779caa22c63b15a6c3ceb75d8f6d4971b2eb67"
+source = "git+https://github.com/timokoesters/Rocket.git?branch=empty_parameters#f6d40ecd5d871d97837b3116eb670fb3c06d95b9"
dependencies = [
"cookie",
"http",
@@ -1543,7 +1544,7 @@ dependencies = [
[[package]]
name = "ruma"
version = "0.1.0"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"ruma-api",
"ruma-client-api",
@@ -1558,7 +1559,7 @@ dependencies = [
[[package]]
name = "ruma-api"
version = "0.16.1"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"http",
"percent-encoding",
@@ -1573,7 +1574,7 @@ dependencies = [
[[package]]
name = "ruma-api-macros"
version = "0.16.1"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"proc-macro2",
"quote",
@@ -1583,7 +1584,7 @@ dependencies = [
[[package]]
name = "ruma-client-api"
version = "0.9.0"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"http",
"js_int",
@@ -1600,7 +1601,7 @@ dependencies = [
[[package]]
name = "ruma-common"
version = "0.2.0"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"js_int",
"ruma-serde",
@@ -1612,7 +1613,7 @@ dependencies = [
[[package]]
name = "ruma-events"
version = "0.21.3"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"js_int",
"ruma-common",
@@ -1627,7 +1628,7 @@ dependencies = [
[[package]]
name = "ruma-events-macros"
version = "0.21.3"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"proc-macro2",
"quote",
@@ -1637,7 +1638,7 @@ dependencies = [
[[package]]
name = "ruma-federation-api"
version = "0.0.2"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"js_int",
"ruma-api",
@@ -1652,7 +1653,7 @@ dependencies = [
[[package]]
name = "ruma-identifiers"
version = "0.17.1"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"rand",
"serde",
@@ -1662,7 +1663,7 @@ dependencies = [
[[package]]
name = "ruma-identifiers-macros"
version = "0.17.1"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"proc-macro2",
"quote",
@@ -1673,7 +1674,7 @@ dependencies = [
[[package]]
name = "ruma-serde"
version = "0.2.2"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"form_urlencoded",
"itoa",
@@ -1685,7 +1686,7 @@ dependencies = [
[[package]]
name = "ruma-signatures"
version = "0.6.0-dev.1"
-source = "git+https://github.com/ruma/ruma?rev=e047c647ddcb368e7eb1e05ae8823a9494273457#e047c647ddcb368e7eb1e05ae8823a9494273457"
+source = "git+https://github.com/ruma/ruma?rev=d5d2d1d893fa12d27960e4c58d6c09b215d06e95#d5d2d1d893fa12d27960e4c58d6c09b215d06e95"
dependencies = [
"base64 0.12.3",
"ring",
@@ -1837,9 +1838,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.56"
+version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3"
+checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
dependencies = [
"itoa",
"ryu",
@@ -2028,9 +2029,9 @@ checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1"
[[package]]
name = "syn"
-version = "1.0.35"
+version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0"
+checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250"
dependencies = [
"proc-macro2",
"quote",
@@ -2338,9 +2339,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasm-bindgen"
-version = "0.2.65"
+version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3edbcc9536ab7eababcc6d2374a0b7bfe13a2b6d562c5e07f370456b1a8f33d"
+checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c"
dependencies = [
"cfg-if",
"serde",
@@ -2350,9 +2351,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.65"
+version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ed2fb8c84bfad20ea66b26a3743f3e7ba8735a69fe7d95118c33ec8fc1244d"
+checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0"
dependencies = [
"bumpalo",
"lazy_static",
@@ -2365,9 +2366,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.15"
+version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41ad6e4e8b2b7f8c90b6e09a9b590ea15cb0d1dbe28502b5a405cd95d1981671"
+checksum = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699"
dependencies = [
"cfg-if",
"js-sys",
@@ -2377,9 +2378,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.65"
+version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb071268b031a64d92fc6cf691715ca5a40950694d8f683c5bb43db7c730929e"
+checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -2387,9 +2388,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.65"
+version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf592c807080719d1ff2f245a687cbadb3ed28b2077ed7084b47aba8b691f2c6"
+checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556"
dependencies = [
"proc-macro2",
"quote",
@@ -2400,15 +2401,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.65"
+version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b6c0220ded549d63860c78c38f3bcc558d1ca3f4efa74942c536ddbbb55e87"
+checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092"
[[package]]
name = "web-sys"
-version = "0.3.42"
+version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8be2398f326b7ba09815d0b403095f34dd708579220d099caae89be0b32137b2"
+checksum = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47"
dependencies = [
"js-sys",
"wasm-bindgen",
diff --git a/Cargo.toml b/Cargo.toml
index 02a90cdd..c2607a7d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,8 +13,12 @@ edition = "2018"
[dependencies]
# TODO: This can become optional as soon as proper configs are supported
-rocket = { git = "https://github.com/SergioBenitez/Rocket.git", rev = "8d779caa22c63b15a6c3ceb75d8f6d4971b2eb67", features = ["tls"], optional = false } # Used to handle requests
-ruma = { git = "https://github.com/ruma/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"], rev = "e047c647ddcb368e7eb1e05ae8823a9494273457" } # Used for matrix spec type definitions and helpers
+#rocket = { git = "https://github.com/SergioBenitez/Rocket.git", rev = "8d779caa22c63b15a6c3ceb75d8f6d4971b2eb67", features = ["tls"] } # Used to handle requests
+rocket = { git = "https://github.com/timokoesters/Rocket.git", branch = "empty_parameters", features = ["tls"] }
+
+tokio = "0.2.22" # Used for long polling
+ruma = { git = "https://github.com/ruma/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"], rev = "d5d2d1d893fa12d27960e4c58d6c09b215d06e95" } # Used for matrix spec type definitions and helpers
+#ruma = { path = "../ruma/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"] }
sled = "0.32.0" # Used for storing data permanently
log = "0.4.8" # Used for emitting log entries
http = "0.2.1" # Used for rocket<->ruma conversions
diff --git a/src/client_server.rs b/src/client_server.rs
index c5bba03d..4a2f33b3 100644
--- a/src/client_server.rs
+++ b/src/client_server.rs
@@ -1,5 +1,5 @@
use std::{
- collections::BTreeMap,
+ collections::{hash_map, BTreeMap, HashMap, HashSet},
convert::{TryFrom, TryInto},
time::{Duration, SystemTime},
};
@@ -11,14 +11,14 @@ use log::warn;
#[cfg(not(feature = "conduit_bin"))]
use super::State;
#[cfg(feature = "conduit_bin")]
-use rocket::{delete, get, options, post, put, State};
+use rocket::{delete, get, options, post, put, tokio, State};
use ruma::{
api::client::{
error::ErrorKind,
r0::{
account::{
- change_password, deactivate, get_username_availability, register,
+ change_password, deactivate, get_username_availability, register, whoami,
ThirdPartyIdRemovalStatus,
},
alias::{create_alias, delete_alias, get_alias},
@@ -35,7 +35,7 @@ use ruma::{
set_room_visibility,
},
filter::{self, create_filter, get_filter},
- keys::{self, claim_keys, get_keys, upload_keys},
+ keys::{self, claim_keys, get_key_changes, get_keys, upload_keys},
media::{create_content, get_content, get_content_thumbnail, get_media_config},
membership::{
ban_user, forget_room, get_member_events, invite_user, join_room_by_id,
@@ -304,6 +304,18 @@ pub fn login_route(
.into())
}
+#[cfg_attr(
+ feature = "conduit_bin",
+ get("/_matrix/client/r0/account/whoami", data = "
")
+)]
+pub fn whoami_route(body: Ruma) -> ConduitResult {
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
+ Ok(whoami::Response {
+ user_id: sender_id.clone(),
+ }
+ .into())
+}
+
#[cfg_attr(
feature = "conduit_bin",
post("/_matrix/client/r0/logout", data = "")
@@ -312,10 +324,10 @@ pub fn logout_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let device_id = body.device_id.as_ref().expect("user is authenticated");
- db.users.remove_device(&user_id, device_id)?;
+ db.users.remove_device(&sender_id, device_id)?;
Ok(logout::Response.into())
}
@@ -328,11 +340,11 @@ pub fn logout_all_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- for device_id in db.users.all_device_ids(user_id) {
+ for device_id in db.users.all_device_ids(sender_id) {
if let Ok(device_id) = device_id {
- db.users.remove_device(&user_id, &device_id)?;
+ db.users.remove_device(&sender_id, &device_id)?;
}
}
@@ -347,59 +359,7 @@ pub fn change_password_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
- let device_id = body.device_id.as_ref().expect("user is authenticated");
-
- let mut uiaainfo = UiaaInfo {
- flows: vec![AuthFlow {
- stages: vec!["m.login.password".to_owned()],
- }],
- completed: Vec::new(),
- params: Default::default(),
- session: None,
- auth_error: None,
- };
-
- if let Some(auth) = &body.auth {
- let (worked, uiaainfo) =
- db.uiaa
- .try_auth(&user_id, device_id, auth, &uiaainfo, &db.users, &db.globals)?;
- if !worked {
- return Err(Error::Uiaa(uiaainfo));
- }
- // Success!
- } else {
- uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
- db.uiaa.create(&user_id, &device_id, &uiaainfo)?;
- return Err(Error::Uiaa(uiaainfo));
- }
-
- db.users.set_password(&user_id, &body.new_password)?;
-
- // TODO: Read logout_devices field when it's available and respect that, currently not supported in Ruma
- // See: https://github.com/ruma/ruma/issues/107
- // Logout all devices except the current one
- for id in db
- .users
- .all_device_ids(&user_id)
- .filter_map(|id| id.ok())
- .filter(|id| id != device_id)
- {
- db.users.remove_device(&user_id, &id)?;
- }
-
- Ok(change_password::Response.into())
-}
-
-#[cfg_attr(
- feature = "conduit_bin",
- post("/_matrix/client/r0/account/deactivate", data = "")
-)]
-pub fn deactivate_route(
- db: State<'_, Database>,
- body: Ruma,
-) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let device_id = body.device_id.as_ref().expect("user is authenticated");
let mut uiaainfo = UiaaInfo {
@@ -414,7 +374,64 @@ pub fn deactivate_route(
if let Some(auth) = &body.auth {
let (worked, uiaainfo) = db.uiaa.try_auth(
- &user_id,
+ &sender_id,
+ device_id,
+ auth,
+ &uiaainfo,
+ &db.users,
+ &db.globals,
+ )?;
+ if !worked {
+ return Err(Error::Uiaa(uiaainfo));
+ }
+ // Success!
+ } else {
+ uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
+ db.uiaa.create(&sender_id, &device_id, &uiaainfo)?;
+ return Err(Error::Uiaa(uiaainfo));
+ }
+
+ db.users.set_password(&sender_id, &body.new_password)?;
+
+ // TODO: Read logout_devices field when it's available and respect that, currently not supported in Ruma
+ // See: https://github.com/ruma/ruma/issues/107
+ // Logout all devices except the current one
+ for id in db
+ .users
+ .all_device_ids(&sender_id)
+ .filter_map(|id| id.ok())
+ .filter(|id| id != device_id)
+ {
+ db.users.remove_device(&sender_id, &id)?;
+ }
+
+ Ok(change_password::Response.into())
+}
+
+#[cfg_attr(
+ feature = "conduit_bin",
+ post("/_matrix/client/r0/account/deactivate", data = "")
+)]
+pub fn deactivate_route(
+ db: State<'_, Database>,
+ body: Ruma,
+) -> ConduitResult {
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
+ let device_id = body.device_id.as_ref().expect("user is authenticated");
+
+ let mut uiaainfo = UiaaInfo {
+ flows: vec![AuthFlow {
+ stages: vec!["m.login.password".to_owned()],
+ }],
+ completed: Vec::new(),
+ params: Default::default(),
+ session: None,
+ auth_error: None,
+ };
+
+ if let Some(auth) = &body.auth {
+ let (worked, uiaainfo) = db.uiaa.try_auth(
+ &sender_id,
&device_id,
auth,
&uiaainfo,
@@ -427,15 +444,15 @@ pub fn deactivate_route(
// Success!
} else {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
- db.uiaa.create(&user_id, &device_id, &uiaainfo)?;
+ db.uiaa.create(&sender_id, &device_id, &uiaainfo)?;
return Err(Error::Uiaa(uiaainfo));
}
// Leave all joined rooms and reject all invitations
for room_id in db
.rooms
- .rooms_joined(&user_id)
- .chain(db.rooms.rooms_invited(&user_id))
+ .rooms_joined(&sender_id)
+ .chain(db.rooms.rooms_invited(&sender_id))
{
let room_id = room_id?;
let event = member::MemberEventContent {
@@ -448,18 +465,18 @@ pub fn deactivate_route(
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(event).expect("event is valid, we just created it"),
None,
- Some(user_id.to_string()),
+ Some(sender_id.to_string()),
None,
&db.globals,
)?;
}
// Remove devices and mark account as deactivated
- db.users.deactivate_account(&user_id)?;
+ db.users.deactivate_account(&sender_id)?;
Ok(deactivate::Response {
id_server_unbind_result: ThirdPartyIdRemovalStatus::NoSupport,
@@ -500,11 +517,11 @@ pub fn get_pushrules_all_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let event = db
.account_data
- .get::(None, &user_id, EventType::PushRules)?
+ .get::(None, &sender_id, EventType::PushRules)?
.ok_or(Error::BadRequest(
ErrorKind::NotFound,
"PushRules event not found.",
@@ -517,15 +534,11 @@ pub fn get_pushrules_all_route(
}
#[cfg_attr(feature = "conduit_bin", put(
- "/_matrix/client/r0/pushrules/<_scope>/<_kind>/<_rule_id>",
+ "/_matrix/client/r0/pushrules/<_>/<_>/<_>",
//data = ""
))]
-pub fn set_pushrule_route(
- //db: State<'_, Database>,
+pub fn set_pushrule_route(//db: State<'_, Database>,
//body: Ruma,
- _scope: String,
- _kind: String,
- _rule_id: String,
) -> ConduitResult {
// TODO
warn!("TODO: set_pushrule_route");
@@ -534,26 +547,16 @@ pub fn set_pushrule_route(
#[cfg_attr(
feature = "conduit_bin",
- put("/_matrix/client/r0/pushrules/<_scope>/<_kind>/<_rule_id>/enabled")
+ put("/_matrix/client/r0/pushrules/<_>/<_>/<_>/enabled")
)]
-pub fn set_pushrule_enabled_route(
- _scope: String,
- _kind: String,
- _rule_id: String,
-) -> ConduitResult {
+pub fn set_pushrule_enabled_route() -> ConduitResult {
// TODO
warn!("TODO: set_pushrule_enabled_route");
Ok(set_pushrule_enabled::Response.into())
}
-#[cfg_attr(
- feature = "conduit_bin",
- get("/_matrix/client/r0/user/<_user_id>/filter/<_filter_id>")
-)]
-pub fn get_filter_route(
- _user_id: String,
- _filter_id: String,
-) -> ConduitResult {
+#[cfg_attr(feature = "conduit_bin", get("/_matrix/client/r0/user/<_>/filter/<_>"))]
+pub fn get_filter_route() -> ConduitResult {
// TODO
Ok(get_filter::Response {
filter: filter::FilterDefinition {
@@ -567,11 +570,8 @@ pub fn get_filter_route(
.into())
}
-#[cfg_attr(
- feature = "conduit_bin",
- post("/_matrix/client/r0/user/<_user_id>/filter")
-)]
-pub fn create_filter_route(_user_id: String) -> ConduitResult {
+#[cfg_attr(feature = "conduit_bin", post("/_matrix/client/r0/user/<_>/filter"))]
+pub fn create_filter_route() -> ConduitResult {
// TODO
Ok(create_filter::Response {
filter_id: utils::random_string(10),
@@ -581,18 +581,13 @@ pub fn create_filter_route(_user_id: String) -> ConduitResult/account_data/<_type>",
- data = ""
- )
+ put("/_matrix/client/r0/user/<_>/account_data/<_>", data = "")
)]
pub fn set_global_account_data_route(
db: State<'_, Database>,
body: Ruma,
- _user_id: String,
- _type: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let content = serde_json::from_str::(body.data.get())
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Data is invalid."))?;
@@ -601,7 +596,7 @@ pub fn set_global_account_data_route(
db.account_data.update(
None,
- user_id,
+ sender_id,
event_type.clone().into(),
&BasicEvent {
content: CustomEventContent {
@@ -617,60 +612,51 @@ pub fn set_global_account_data_route(
#[cfg_attr(
feature = "conduit_bin",
- get(
- "/_matrix/client/r0/user/<_user_id>/account_data/<_type>",
- data = ""
- )
+ get("/_matrix/client/r0/user/<_>/account_data/<_>", data = "")
)]
pub fn get_global_account_data_route(
db: State<'_, Database>,
body: Ruma,
- _user_id: String,
- _type: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let data = db
.account_data
- .get::(
+ .get::>(
None,
- user_id,
+ sender_id,
EventType::try_from(&body.event_type).expect("EventType::try_from can never fail"),
)?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?;
- Ok(get_global_account_data::Response {
- account_data: Raw::from(data),
- }
- .into())
+ Ok(get_global_account_data::Response { account_data: data }.into())
}
#[cfg_attr(
feature = "conduit_bin",
- put("/_matrix/client/r0/profile/<_user_id>/displayname", data = "")
+ put("/_matrix/client/r0/profile/<_>/displayname", data = "")
)]
pub fn set_displayname_route(
db: State<'_, Database>,
body: Ruma,
- _user_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
db.users
- .set_displayname(&user_id, body.displayname.clone())?;
+ .set_displayname(&sender_id, body.displayname.clone())?;
- // Send a new membership event into all joined rooms
- for room_id in db.rooms.rooms_joined(&user_id) {
+ // Send a new membership event and presence update into all joined rooms
+ for room_id in db.rooms.rooms_joined(&sender_id) {
let room_id = room_id?;
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(ruma::events::room::member::MemberEventContent {
displayname: body.displayname.clone(),
..serde_json::from_value::>(
db.rooms
- .room_state_get(&room_id, &EventType::RoomMember, &user_id.to_string())?
+ .room_state_get(&room_id, &EventType::RoomMember, &sender_id.to_string())?
.ok_or_else(|| {
Error::bad_database(
"Tried to send displayname update for user not in the room.",
@@ -685,61 +671,60 @@ pub fn set_displayname_route(
})
.expect("event is valid, we just created it"),
None,
- Some(user_id.to_string()),
+ Some(sender_id.to_string()),
None,
&db.globals,
)?;
- }
- // Presence update
- db.global_edus.update_presence(
- ruma::events::presence::PresenceEvent {
- content: ruma::events::presence::PresenceEventContent {
- avatar_url: db.users.avatar_url(&user_id)?,
- currently_active: None,
- displayname: db.users.displayname(&user_id)?,
- last_active_ago: Some(
- utils::millis_since_unix_epoch()
- .try_into()
- .expect("time is valid"),
- ),
- presence: ruma::presence::PresenceState::Online,
- status_msg: None,
+ // Presence update
+ db.rooms.edus.update_presence(
+ &sender_id,
+ &room_id,
+ ruma::events::presence::PresenceEvent {
+ content: ruma::events::presence::PresenceEventContent {
+ avatar_url: db.users.avatar_url(&sender_id)?,
+ currently_active: None,
+ displayname: db.users.displayname(&sender_id)?,
+ last_active_ago: Some(
+ utils::millis_since_unix_epoch()
+ .try_into()
+ .expect("time is valid"),
+ ),
+ presence: ruma::presence::PresenceState::Online,
+ status_msg: None,
+ },
+ sender: sender_id.clone(),
},
- sender: user_id.clone(),
- },
- &db.globals,
- )?;
+ &db.globals,
+ )?;
+ }
Ok(set_display_name::Response.into())
}
#[cfg_attr(
feature = "conduit_bin",
- get("/_matrix/client/r0/profile/<_user_id>/displayname", data = "")
+ get("/_matrix/client/r0/profile/<_>/displayname", data = "")
)]
pub fn get_displayname_route(
db: State<'_, Database>,
body: Ruma,
- _user_id: String,
) -> ConduitResult {
- let user_id = body.body.user_id.clone();
Ok(get_display_name::Response {
- displayname: db.users.displayname(&user_id)?,
+ displayname: db.users.displayname(&body.user_id)?,
}
.into())
}
#[cfg_attr(
feature = "conduit_bin",
- put("/_matrix/client/r0/profile/<_user_id>/avatar_url", data = "")
+ put("/_matrix/client/r0/profile/<_>/avatar_url", data = "")
)]
pub fn set_avatar_url_route(
db: State<'_, Database>,
body: Ruma,
- _user_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
if let Some(avatar_url) = &body.avatar_url {
if !avatar_url.starts_with("mxc://") {
@@ -753,20 +738,21 @@ pub fn set_avatar_url_route(
// TODO also make sure this is valid mxc:// format (not only starting with it)
}
- db.users.set_avatar_url(&user_id, body.avatar_url.clone())?;
+ db.users
+ .set_avatar_url(&sender_id, body.avatar_url.clone())?;
- // Send a new membership event into all joined rooms
- for room_id in db.rooms.rooms_joined(&user_id) {
+ // Send a new membership event and presence update into all joined rooms
+ for room_id in db.rooms.rooms_joined(&sender_id) {
let room_id = room_id?;
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(ruma::events::room::member::MemberEventContent {
avatar_url: body.avatar_url.clone(),
..serde_json::from_value::>(
db.rooms
- .room_state_get(&room_id, &EventType::RoomMember, &user_id.to_string())?
+ .room_state_get(&room_id, &EventType::RoomMember, &sender_id.to_string())?
.ok_or_else(|| {
Error::bad_database(
"Tried to send avatar url update for user not in the room.",
@@ -781,63 +767,61 @@ pub fn set_avatar_url_route(
})
.expect("event is valid, we just created it"),
None,
- Some(user_id.to_string()),
+ Some(sender_id.to_string()),
None,
&db.globals,
)?;
- }
- // Presence update
- db.global_edus.update_presence(
- ruma::events::presence::PresenceEvent {
- content: ruma::events::presence::PresenceEventContent {
- avatar_url: db.users.avatar_url(&user_id)?,
- currently_active: None,
- displayname: db.users.displayname(&user_id)?,
- last_active_ago: Some(
- utils::millis_since_unix_epoch()
- .try_into()
- .expect("time is valid"),
- ),
- presence: ruma::presence::PresenceState::Online,
- status_msg: None,
+ // Presence update
+ db.rooms.edus.update_presence(
+ &sender_id,
+ &room_id,
+ ruma::events::presence::PresenceEvent {
+ content: ruma::events::presence::PresenceEventContent {
+ avatar_url: db.users.avatar_url(&sender_id)?,
+ currently_active: None,
+ displayname: db.users.displayname(&sender_id)?,
+ last_active_ago: Some(
+ utils::millis_since_unix_epoch()
+ .try_into()
+ .expect("time is valid"),
+ ),
+ presence: ruma::presence::PresenceState::Online,
+ status_msg: None,
+ },
+ sender: sender_id.clone(),
},
- sender: user_id.clone(),
- },
- &db.globals,
- )?;
+ &db.globals,
+ )?;
+ }
Ok(set_avatar_url::Response.into())
}
#[cfg_attr(
feature = "conduit_bin",
- get("/_matrix/client/r0/profile/<_user_id>/avatar_url", data = "")
+ get("/_matrix/client/r0/profile/<_>/avatar_url", data = "")
)]
pub fn get_avatar_url_route(
db: State<'_, Database>,
body: Ruma,
- _user_id: String,
) -> ConduitResult {
- let user_id = body.body.user_id.clone();
Ok(get_avatar_url::Response {
- avatar_url: db.users.avatar_url(&user_id)?,
+ avatar_url: db.users.avatar_url(&body.user_id)?,
}
.into())
}
#[cfg_attr(
feature = "conduit_bin",
- get("/_matrix/client/r0/profile/<_user_id>", data = "")
+ get("/_matrix/client/r0/profile/<_>", data = "")
)]
pub fn get_profile_route(
db: State<'_, Database>,
body: Ruma,
- _user_id: String,
) -> ConduitResult {
- let user_id = body.body.user_id.clone();
- let avatar_url = db.users.avatar_url(&user_id)?;
- let displayname = db.users.displayname(&user_id)?;
+ let avatar_url = db.users.avatar_url(&body.user_id)?;
+ let displayname = db.users.displayname(&body.user_id)?;
if avatar_url.is_none() && displayname.is_none() {
// Return 404 if we don't have a profile for this id
@@ -856,33 +840,38 @@ pub fn get_profile_route(
#[cfg_attr(
feature = "conduit_bin",
- put("/_matrix/client/r0/presence/<_user_id>/status", data = "")
+ put("/_matrix/client/r0/presence/<_>/status", data = "")
)]
pub fn set_presence_route(
db: State<'_, Database>,
body: Ruma,
- _user_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- db.global_edus.update_presence(
- ruma::events::presence::PresenceEvent {
- content: ruma::events::presence::PresenceEventContent {
- avatar_url: db.users.avatar_url(&user_id)?,
- currently_active: None,
- displayname: db.users.displayname(&user_id)?,
- last_active_ago: Some(
- utils::millis_since_unix_epoch()
- .try_into()
- .expect("time is valid"),
- ),
- presence: body.presence,
- status_msg: body.status_msg.clone(),
+ for room_id in db.rooms.rooms_joined(&sender_id) {
+ let room_id = room_id?;
+
+ db.rooms.edus.update_presence(
+ &sender_id,
+ &room_id,
+ ruma::events::presence::PresenceEvent {
+ content: ruma::events::presence::PresenceEventContent {
+ avatar_url: db.users.avatar_url(&sender_id)?,
+ currently_active: None,
+ displayname: db.users.displayname(&sender_id)?,
+ last_active_ago: Some(
+ utils::millis_since_unix_epoch()
+ .try_into()
+ .expect("time is valid"),
+ ),
+ presence: body.presence,
+ status_msg: body.status_msg.clone(),
+ },
+ sender: sender_id.clone(),
},
- sender: user_id.clone(),
- },
- &db.globals,
- )?;
+ &db.globals,
+ )?;
+ }
Ok(set_presence::Response.into())
}
@@ -895,26 +884,26 @@ pub fn upload_keys_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let device_id = body.device_id.as_ref().expect("user is authenticated");
if let Some(one_time_keys) = &body.one_time_keys {
for (key_key, key_value) in one_time_keys {
db.users
- .add_one_time_key(user_id, device_id, key_key, key_value)?;
+ .add_one_time_key(sender_id, device_id, key_key, key_value, &db.globals)?;
}
}
if let Some(device_keys) = &body.device_keys {
// This check is needed to assure that signatures are kept
- if db.users.get_device_keys(user_id, device_id)?.is_none() {
+ if db.users.get_device_keys(sender_id, device_id)?.is_none() {
db.users
- .add_device_keys(user_id, device_id, device_keys, &db.globals)?;
+ .add_device_keys(sender_id, device_id, device_keys, &db.rooms, &db.globals)?;
}
}
Ok(upload_keys::Response {
- one_time_key_counts: db.users.count_one_time_keys(user_id, device_id)?,
+ one_time_key_counts: db.users.count_one_time_keys(sender_id, device_id)?,
}
.into())
}
@@ -927,7 +916,7 @@ pub fn get_keys_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let sender_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let mut master_keys = BTreeMap::new();
let mut self_signing_keys = BTreeMap::new();
@@ -1013,7 +1002,7 @@ pub fn claim_keys_route(
for (device_id, key_algorithm) in map {
if let Some(one_time_keys) =
db.users
- .take_one_time_key(user_id, device_id, key_algorithm)?
+ .take_one_time_key(user_id, device_id, key_algorithm, &db.globals)?
{
let mut c = BTreeMap::new();
c.insert(one_time_keys.0, one_time_keys.1);
@@ -1038,29 +1027,25 @@ pub fn create_backup_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let version = db
.key_backups
- .create_backup(&user_id, &body.algorithm, &db.globals)?;
+ .create_backup(&sender_id, &body.algorithm, &db.globals)?;
Ok(create_backup::Response { version }.into())
}
#[cfg_attr(
feature = "conduit_bin",
- put(
- "/_matrix/client/unstable/room_keys/version/<_version>",
- data = ""
- )
+ put("/_matrix/client/unstable/room_keys/version/<_>", data = "")
)]
pub fn update_backup_route(
db: State<'_, Database>,
body: Ruma,
- _version: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
db.key_backups
- .update_backup(&user_id, &body.version, &body.algorithm, &db.globals)?;
+ .update_backup(&sender_id, &body.version, &body.algorithm, &db.globals)?;
Ok(update_backup::Response.into())
}
@@ -1073,11 +1058,11 @@ pub fn get_latest_backup_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let (version, algorithm) =
db.key_backups
- .get_latest_backup(&user_id)?
+ .get_latest_backup(&sender_id)?
.ok_or(Error::BadRequest(
ErrorKind::NotFound,
"Key backup does not exist.",
@@ -1085,8 +1070,8 @@ pub fn get_latest_backup_route(
Ok(get_latest_backup::Response {
algorithm,
- count: (db.key_backups.count_keys(user_id, &version)? as u32).into(),
- etag: db.key_backups.get_etag(user_id, &version)?,
+ count: (db.key_backups.count_keys(sender_id, &version)? as u32).into(),
+ etag: db.key_backups.get_etag(sender_id, &version)?,
version,
}
.into())
@@ -1094,29 +1079,25 @@ pub fn get_latest_backup_route(
#[cfg_attr(
feature = "conduit_bin",
- get(
- "/_matrix/client/unstable/room_keys/version/<_version>",
- data = ""
- )
+ get("/_matrix/client/unstable/room_keys/version/<_>", data = "")
)]
pub fn get_backup_route(
db: State<'_, Database>,
body: Ruma,
- _version: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
- let algorithm =
- db.key_backups
- .get_backup(&user_id, &body.version)?
- .ok_or(Error::BadRequest(
- ErrorKind::NotFound,
- "Key backup does not exist.",
- ))?;
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
+ let algorithm = db
+ .key_backups
+ .get_backup(&sender_id, &body.version)?
+ .ok_or(Error::BadRequest(
+ ErrorKind::NotFound,
+ "Key backup does not exist.",
+ ))?;
Ok(get_backup::Response {
algorithm,
- count: (db.key_backups.count_keys(user_id, &body.version)? as u32).into(),
- etag: db.key_backups.get_etag(user_id, &body.version)?,
+ count: (db.key_backups.count_keys(sender_id, &body.version)? as u32).into(),
+ etag: db.key_backups.get_etag(sender_id, &body.version)?,
version: body.version.clone(),
}
.into())
@@ -1131,12 +1112,12 @@ pub fn add_backup_keys_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
for (room_id, room) in &body.rooms {
for (session_id, key_data) in &room.sessions {
db.key_backups.add_key(
- &user_id,
+ &sender_id,
&body.version,
&room_id,
&session_id,
@@ -1147,8 +1128,8 @@ pub fn add_backup_keys_route(
}
Ok(add_backup_keys::Response {
- count: (db.key_backups.count_keys(user_id, &body.version)? as u32).into(),
- etag: db.key_backups.get_etag(user_id, &body.version)?,
+ count: (db.key_backups.count_keys(sender_id, &body.version)? as u32).into(),
+ etag: db.key_backups.get_etag(sender_id, &body.version)?,
}
.into())
}
@@ -1161,23 +1142,22 @@ pub fn get_backup_keys_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- let rooms = db.key_backups.get_all(&user_id, &body.version)?;
+ let rooms = db.key_backups.get_all(&sender_id, &body.version)?;
Ok(get_backup_keys::Response { rooms }.into())
}
#[cfg_attr(
feature = "conduit_bin",
- post("/_matrix/client/r0/rooms/<_room_id>/read_markers", data = "")
+ post("/_matrix/client/r0/rooms/<_>/read_markers", data = "")
)]
pub fn set_read_marker_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let fully_read_event = ruma::events::fully_read::FullyReadEvent {
content: ruma::events::fully_read::FullyReadEventContent {
@@ -1187,7 +1167,7 @@ pub fn set_read_marker_route(
};
db.account_data.update(
Some(&body.room_id),
- &user_id,
+ &sender_id,
EventType::FullyRead,
&fully_read_event,
&db.globals,
@@ -1196,7 +1176,7 @@ pub fn set_read_marker_route(
if let Some(event) = &body.read_receipt {
db.rooms.edus.room_read_set(
&body.room_id,
- &user_id,
+ &sender_id,
db.rooms.get_pdu_count(event)?.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Event does not exist.",
@@ -1205,7 +1185,7 @@ pub fn set_read_marker_route(
let mut user_receipts = BTreeMap::new();
user_receipts.insert(
- user_id.clone(),
+ sender_id.clone(),
ruma::events::receipt::Receipt {
ts: Some(SystemTime::now()),
},
@@ -1219,7 +1199,7 @@ pub fn set_read_marker_route(
);
db.rooms.edus.roomlatest_update(
- &user_id,
+ &sender_id,
&body.room_id,
AnyEvent::Ephemeral(AnyEphemeralRoomEvent::Receipt(
ruma::events::receipt::ReceiptEvent {
@@ -1235,22 +1215,17 @@ pub fn set_read_marker_route(
#[cfg_attr(
feature = "conduit_bin",
- put(
- "/_matrix/client/r0/rooms/<_room_id>/typing/<_user_id>",
- data = ""
- )
+ put("/_matrix/client/r0/rooms/<_>/typing/<_>", data = "")
)]
pub fn create_typing_event_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
- _user_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
if body.typing {
db.rooms.edus.roomactive_add(
- &user_id,
+ &sender_id,
&body.room_id,
body.timeout.map(|d| d.as_millis() as u64).unwrap_or(30000)
+ utils::millis_since_unix_epoch(),
@@ -1259,7 +1234,7 @@ pub fn create_typing_event_route(
} else {
db.rooms
.edus
- .roomactive_remove(&user_id, &body.room_id, &db.globals)?;
+ .roomactive_remove(&sender_id, &body.room_id, &db.globals)?;
}
Ok(create_typing_event::Response.into())
@@ -1273,7 +1248,7 @@ pub fn create_room_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let room_id = RoomId::new(db.globals.server_name());
@@ -1296,7 +1271,7 @@ pub fn create_room_route(
}
})?;
- let mut content = ruma::events::room::create::CreateEventContent::new(user_id.clone());
+ let mut content = ruma::events::room::create::CreateEventContent::new(sender_id.clone());
content.federate = body.creation_content.as_ref().map_or(true, |c| c.federate);
content.predecessor = body
.creation_content
@@ -1307,7 +1282,7 @@ pub fn create_room_route(
// 1. The room create event
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomCreate,
serde_json::to_value(content).expect("event is valid, we just created it"),
None,
@@ -1319,18 +1294,18 @@ pub fn create_room_route(
// 2. Let the room creator join
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(member::MemberEventContent {
membership: member::MembershipState::Join,
- displayname: db.users.displayname(&user_id)?,
- avatar_url: db.users.avatar_url(&user_id)?,
+ displayname: db.users.displayname(&sender_id)?,
+ avatar_url: db.users.avatar_url(&sender_id)?,
is_direct: body.is_direct,
third_party_invite: None,
})
.expect("event is valid, we just created it"),
None,
- Some(user_id.to_string()),
+ Some(sender_id.to_string()),
None,
&db.globals,
)?;
@@ -1344,9 +1319,9 @@ pub fn create_room_route(
// 3. Power levels
let mut users = BTreeMap::new();
- users.insert(user_id.clone(), 100.into());
- for invite_user_id in &body.invite {
- users.insert(invite_user_id.clone(), 100.into());
+ users.insert(sender_id.clone(), 100.into());
+ for invite_ in &body.invite {
+ users.insert(invite_.clone(), 100.into());
}
let power_levels_content = if let Some(power_levels) = &body.power_level_content_override {
@@ -1372,7 +1347,7 @@ pub fn create_room_route(
};
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomPowerLevels,
power_levels_content,
None,
@@ -1385,7 +1360,7 @@ pub fn create_room_route(
// 4.1 Join Rules
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomJoinRules,
match preset {
create_room::RoomPreset::PublicChat => serde_json::to_value(
@@ -1407,7 +1382,7 @@ pub fn create_room_route(
// 4.2 History Visibility
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomHistoryVisibility,
serde_json::to_value(history_visibility::HistoryVisibilityEventContent::new(
history_visibility::HistoryVisibility::Shared,
@@ -1422,7 +1397,7 @@ pub fn create_room_route(
// 4.3 Guest Access
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomGuestAccess,
match preset {
create_room::RoomPreset::PublicChat => serde_json::to_value(
@@ -1454,7 +1429,7 @@ pub fn create_room_route(
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
event_type.clone(),
serde_json::from_str(content.get()).map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid initial_state content.")
@@ -1470,7 +1445,7 @@ pub fn create_room_route(
if let Some(name) = &body.name {
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomName,
serde_json::to_value(
name::NameEventContent::new(name.clone())
@@ -1487,7 +1462,7 @@ pub fn create_room_route(
if let Some(topic) = &body.topic {
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomTopic,
serde_json::to_value(topic::TopicEventContent {
topic: topic.clone(),
@@ -1504,7 +1479,7 @@ pub fn create_room_route(
for user in &body.invite {
db.rooms.append_pdu(
room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(member::MemberEventContent {
membership: member::MembershipState::Invite,
@@ -1541,12 +1516,12 @@ pub fn joined_rooms_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
Ok(joined_rooms::Response {
joined_rooms: db
.rooms
- .rooms_joined(&user_id)
+ .rooms_joined(&sender_id)
.filter_map(|r| r.ok())
.collect(),
}
@@ -1555,23 +1530,17 @@ pub fn joined_rooms_route(
#[cfg_attr(
feature = "conduit_bin",
- put(
- "/_matrix/client/r0/rooms/<_room_id>/redact/<_event_id>/<_txn_id>",
- data = ""
- )
+ put("/_matrix/client/r0/rooms/<_>/redact/<_>/<_>", data = "")
)]
pub fn redact_event_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
- _event_id: String,
- _txn_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let event_id = db.rooms.append_pdu(
body.room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomRedaction,
serde_json::to_value(redaction::RedactionEventContent {
reason: body.reason.clone(),
@@ -1588,12 +1557,11 @@ pub fn redact_event_route(
#[cfg_attr(
feature = "conduit_bin",
- put("/_matrix/client/r0/directory/room/<_room_alias>", data = "")
+ put("/_matrix/client/r0/directory/room/<_>", data = "")
)]
pub fn create_alias_route(
db: State<'_, Database>,
body: Ruma,
- _room_alias: String,
) -> ConduitResult {
if db.rooms.id_from_alias(&body.room_alias)?.is_some() {
return Err(Error::Conflict("Alias already exists."));
@@ -1607,12 +1575,11 @@ pub fn create_alias_route(
#[cfg_attr(
feature = "conduit_bin",
- delete("/_matrix/client/r0/directory/room/<_room_alias>", data = "")
+ delete("/_matrix/client/r0/directory/room/<_>", data = "")
)]
pub fn delete_alias_route(
db: State<'_, Database>,
body: Ruma,
- _room_alias: String,
) -> ConduitResult {
db.rooms.set_alias(&body.room_alias, None, &db.globals)?;
@@ -1621,12 +1588,11 @@ pub fn delete_alias_route(
#[cfg_attr(
feature = "conduit_bin",
- get("/_matrix/client/r0/directory/room/<_room_alias>", data = "")
+ get("/_matrix/client/r0/directory/room/<_>", data = "")
)]
pub fn get_alias_route(
db: State<'_, Database>,
body: Ruma,
- _room_alias: String,
) -> ConduitResult {
if body.room_alias.server_name() != db.globals.server_name() {
todo!("ask remote server");
@@ -1649,32 +1615,31 @@ pub fn get_alias_route(
#[cfg_attr(
feature = "conduit_bin",
- post("/_matrix/client/r0/rooms/<_room_id>/join", data = "")
+ post("/_matrix/client/r0/rooms/<_>/join", data = "")
)]
pub fn join_room_by_id_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
// TODO: Ask a remote server if we don't have this room
let event = member::MemberEventContent {
membership: member::MembershipState::Join,
- displayname: db.users.displayname(&user_id)?,
- avatar_url: db.users.avatar_url(&user_id)?,
+ displayname: db.users.displayname(&sender_id)?,
+ avatar_url: db.users.avatar_url(&sender_id)?,
is_direct: None,
third_party_invite: None,
};
db.rooms.append_pdu(
body.room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(event).expect("event is valid, we just created it"),
None,
- Some(user_id.to_string()),
+ Some(sender_id.to_string()),
None,
&db.globals,
)?;
@@ -1687,12 +1652,11 @@ pub fn join_room_by_id_route(
#[cfg_attr(
feature = "conduit_bin",
- post("/_matrix/client/r0/join/<_room_id_or_alias>", data = "")
+ post("/_matrix/client/r0/join/<_>", data = "")
)]
pub fn join_room_by_id_or_alias_route(
db: State<'_, Database>,
body: Ruma,
- _room_id_or_alias: String,
) -> ConduitResult {
let room_id = RoomId::try_from(body.room_id_or_alias.clone()).or_else(|alias| {
Ok::<_, Error>(db.rooms.id_from_alias(&alias)?.ok_or(Error::BadRequest(
@@ -1702,7 +1666,7 @@ pub fn join_room_by_id_or_alias_route(
})?;
let body = Ruma {
- user_id: body.user_id.clone(),
+ sender_id: body.sender_id.clone(),
device_id: body.device_id.clone(),
json_body: None,
body: join_room_by_id::Request {
@@ -1712,25 +1676,28 @@ pub fn join_room_by_id_or_alias_route(
};
Ok(join_room_by_id_or_alias::Response {
- room_id: join_room_by_id_route(db, body, "".to_owned())?.0.room_id,
+ room_id: join_room_by_id_route(db, body)?.0.room_id,
}
.into())
}
#[cfg_attr(
feature = "conduit_bin",
- post("/_matrix/client/r0/rooms/<_room_id>/leave", data = "")
+ post("/_matrix/client/r0/rooms/<_>/leave", data = "")
)]
pub fn leave_room_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let mut event = serde_json::from_value::>(
db.rooms
- .room_state_get(&body.room_id, &EventType::RoomMember, &user_id.to_string())?
+ .room_state_get(
+ &body.room_id,
+ &EventType::RoomMember,
+ &sender_id.to_string(),
+ )?
.ok_or(Error::BadRequest(
ErrorKind::BadState,
"Cannot leave a room you are not a member of.",
@@ -1746,11 +1713,11 @@ pub fn leave_room_route(
db.rooms.append_pdu(
body.room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(event).expect("event is valid, we just created it"),
None,
- Some(user_id.to_string()),
+ Some(sender_id.to_string()),
None,
&db.globals,
)?;
@@ -1760,18 +1727,21 @@ pub fn leave_room_route(
#[cfg_attr(
feature = "conduit_bin",
- post("/_matrix/client/r0/rooms/<_room_id>/kick", data = "")
+ post("/_matrix/client/r0/rooms/<_>/kick", data = "")
)]
pub fn kick_user_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let mut event = serde_json::from_value::>(
db.rooms
- .room_state_get(&body.room_id, &EventType::RoomMember, &user_id.to_string())?
+ .room_state_get(
+ &body.room_id,
+ &EventType::RoomMember,
+ &body.user_id.to_string(),
+ )?
.ok_or(Error::BadRequest(
ErrorKind::BadState,
"Cannot kick member that's not in the room.",
@@ -1779,7 +1749,7 @@ pub fn kick_user_route(
.content
.clone(),
)
- .map_err(|_| Error::bad_database("Invalid member event in database."))?
+ .expect("Raw::from_value always works")
.deserialize()
.map_err(|_| Error::bad_database("Invalid member event in database."))?;
@@ -1788,11 +1758,11 @@ pub fn kick_user_route(
db.rooms.append_pdu(
body.room_id.clone(),
- user_id.clone(), // Sender
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(event).expect("event is valid, we just created it"),
None,
- Some(body.body.user_id.to_string()),
+ Some(body.user_id.to_string()),
None,
&db.globals,
)?;
@@ -1802,16 +1772,19 @@ pub fn kick_user_route(
#[cfg_attr(
feature = "conduit_bin",
- get("/_matrix/client/r0/rooms/<_room_id>/joined_members", data = "")
+ get("/_matrix/client/r0/rooms/<_>/joined_members", data = "")
)]
pub fn joined_members_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- if !db.rooms.is_joined(&user_id, &body.room_id).unwrap_or(false) {
+ if !db
+ .rooms
+ .is_joined(&sender_id, &body.room_id)
+ .unwrap_or(false)
+ {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You aren't a member of the room.",
@@ -1837,25 +1810,28 @@ pub fn joined_members_route(
#[cfg_attr(
feature = "conduit_bin",
- post("/_matrix/client/r0/rooms/<_room_id>/ban", data = "")
+ post("/_matrix/client/r0/rooms/<_>/ban", data = "")
)]
pub fn ban_user_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
// TODO: reason
let event = db
.rooms
- .room_state_get(&body.room_id, &EventType::RoomMember, &user_id.to_string())?
+ .room_state_get(
+ &body.room_id,
+ &EventType::RoomMember,
+ &body.user_id.to_string(),
+ )?
.map_or(
Ok::<_, Error>(member::MemberEventContent {
membership: member::MembershipState::Ban,
- displayname: db.users.displayname(&user_id)?,
- avatar_url: db.users.avatar_url(&user_id)?,
+ displayname: db.users.displayname(&body.user_id)?,
+ avatar_url: db.users.avatar_url(&body.user_id)?,
is_direct: None,
third_party_invite: None,
}),
@@ -1863,7 +1839,7 @@ pub fn ban_user_route(
let mut event = serde_json::from_value::>(
event.content.clone(),
)
- .map_err(|_| Error::bad_database("Invalid member event in database."))?
+ .expect("Raw::from_value always works")
.deserialize()
.map_err(|_| Error::bad_database("Invalid member event in database."))?;
event.membership = ruma::events::room::member::MembershipState::Ban;
@@ -1873,11 +1849,11 @@ pub fn ban_user_route(
db.rooms.append_pdu(
body.room_id.clone(),
- user_id.clone(), // Sender
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(event).expect("event is valid, we just created it"),
None,
- Some(body.body.user_id.to_string()),
+ Some(body.user_id.to_string()),
None,
&db.globals,
)?;
@@ -1887,18 +1863,21 @@ pub fn ban_user_route(
#[cfg_attr(
feature = "conduit_bin",
- post("/_matrix/client/r0/rooms/<_room_id>/unban", data = "")
+ post("/_matrix/client/r0/rooms/<_>/unban", data = "")
)]
pub fn unban_user_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let mut event = serde_json::from_value::>(
db.rooms
- .room_state_get(&body.room_id, &EventType::RoomMember, &user_id.to_string())?
+ .room_state_get(
+ &body.room_id,
+ &EventType::RoomMember,
+ &body.user_id.to_string(),
+ )?
.ok_or(Error::BadRequest(
ErrorKind::BadState,
"Cannot unban a user who is not banned.",
@@ -1914,11 +1893,11 @@ pub fn unban_user_route(
db.rooms.append_pdu(
body.room_id.clone(),
- user_id.clone(), // Sender
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(event).expect("event is valid, we just created it"),
None,
- Some(body.body.user_id.to_string()),
+ Some(body.user_id.to_string()),
None,
&db.globals,
)?;
@@ -1928,33 +1907,33 @@ pub fn unban_user_route(
#[cfg_attr(
feature = "conduit_bin",
- post("/_matrix/client/r0/rooms/<_room_id>/forget", data = "")
+ post("/_matrix/client/r0/rooms/<_>/forget", data = "")
)]
pub fn forget_room_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- db.rooms.forget(&body.room_id, &user_id)?;
+ db.rooms.forget(&body.room_id, &sender_id)?;
Ok(forget_room::Response.into())
}
#[cfg_attr(
feature = "conduit_bin",
- post("/_matrix/client/r0/rooms/<_room_id>/invite", data = "")
+ post("/_matrix/client/r0/rooms/<_>/invite", data = "")
)]
pub fn invite_user_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
+
if let invite_user::InvitationRecipient::UserId { user_id } = &body.recipient {
db.rooms.append_pdu(
body.room_id.clone(),
- body.user_id.clone().expect("user is authenticated"),
+ sender_id.clone(),
EventType::RoomMember,
serde_json::to_value(member::MemberEventContent {
membership: member::MembershipState::Invite,
@@ -1978,12 +1957,11 @@ pub fn invite_user_route(
#[cfg_attr(
feature = "conduit_bin",
- put("/_matrix/client/r0/directory/list/room/<_room_id>", data = "")
+ put("/_matrix/client/r0/directory/list/room/<_>", data = "")
)]
pub async fn set_room_visibility_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
match body.visibility {
room::Visibility::Public => db.rooms.set_public(&body.room_id, true)?,
@@ -1995,12 +1973,11 @@ pub async fn set_room_visibility_route(
#[cfg_attr(
feature = "conduit_bin",
- get("/_matrix/client/r0/directory/list/room/<_room_id>", data = "")
+ get("/_matrix/client/r0/directory/list/room/<_>", data = "")
)]
pub async fn get_room_visibility_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
Ok(get_room_visibility::Response {
visibility: if db.rooms.is_public_room(&body.room_id)? {
@@ -2027,7 +2004,7 @@ pub async fn get_public_rooms_route(
server,
since,
},
- user_id,
+ sender_id,
device_id,
json_body,
} = body;
@@ -2047,7 +2024,7 @@ pub async fn get_public_rooms_route(
server,
since,
},
- user_id,
+ sender_id,
device_id,
json_body,
},
@@ -2224,16 +2201,15 @@ pub fn search_users_route(
#[cfg_attr(
feature = "conduit_bin",
- get("/_matrix/client/r0/rooms/<_room_id>/members", data = "")
+ get("/_matrix/client/r0/rooms/<_>/members", data = "")
)]
pub fn get_member_events_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- if !db.rooms.is_joined(user_id, &body.room_id)? {
+ if !db.rooms.is_joined(sender_id, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
@@ -2265,20 +2241,15 @@ pub fn get_protocols_route() -> ConduitResult {
#[cfg_attr(
feature = "conduit_bin",
- get(
- "/_matrix/client/r0/rooms/<_room_id>/event/<_event_id>",
- data = ""
- )
+ get("/_matrix/client/r0/rooms/<_>/event/<_>", data = "")
)]
pub fn get_room_event_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
- _event_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- if !db.rooms.is_joined(user_id, &body.room_id)? {
+ if !db.rooms.is_joined(sender_id, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
@@ -2297,26 +2268,20 @@ pub fn get_room_event_route(
#[cfg_attr(
feature = "conduit_bin",
- put(
- "/_matrix/client/r0/rooms/<_room_id>/send/<_event_type>/<_txn_id>",
- data = ""
- )
+ put("/_matrix/client/r0/rooms/<_>/send/<_>/<_>", data = "")
)]
pub fn create_message_event_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
- _event_type: String,
- _txn_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let mut unsigned = serde_json::Map::new();
unsigned.insert("transaction_id".to_owned(), body.txn_id.clone().into());
let event_id = db.rooms.append_pdu(
body.room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
body.event_type.clone(),
serde_json::from_str(
body.json_body
@@ -2335,19 +2300,13 @@ pub fn create_message_event_route(
#[cfg_attr(
feature = "conduit_bin",
- put(
- "/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>/<_state_key>",
- data = ""
- )
+ put("/_matrix/client/r0/rooms/<_>/state/<_>/<_>", data = "")
)]
pub fn create_state_event_for_key_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
- _event_type: String,
- _state_key: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let content = serde_json::from_str::(
body.json_body
@@ -2386,7 +2345,7 @@ pub fn create_state_event_for_key_route(
let event_id = db.rooms.append_pdu(
body.room_id.clone(),
- user_id.clone(),
+ sender_id.clone(),
body.event_type.clone(),
content,
None,
@@ -2400,16 +2359,11 @@ pub fn create_state_event_for_key_route(
#[cfg_attr(
feature = "conduit_bin",
- put(
- "/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>",
- data = ""
- )
+ put("/_matrix/client/r0/rooms/<_>/state/<_>", data = "")
)]
pub fn create_state_event_for_empty_key_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
- _event_type: String,
) -> ConduitResult {
// This just calls create_state_event_for_key_route
let Ruma {
@@ -2419,7 +2373,7 @@ pub fn create_state_event_for_empty_key_route(
event_type,
data,
},
- user_id,
+ sender_id,
device_id,
json_body,
} = body;
@@ -2434,13 +2388,10 @@ pub fn create_state_event_for_empty_key_route(
data,
state_key: "".to_owned(),
},
- user_id,
+ sender_id,
device_id,
json_body,
},
- _room_id,
- _event_type,
- "".to_owned(),
)?
.0
.event_id,
@@ -2450,16 +2401,15 @@ pub fn create_state_event_for_empty_key_route(
#[cfg_attr(
feature = "conduit_bin",
- get("/_matrix/client/r0/rooms/<_room_id>/state", data = "")
+ get("/_matrix/client/r0/rooms/<_>/state", data = "")
)]
pub fn get_state_events_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- if !db.rooms.is_joined(user_id, &body.room_id)? {
+ if !db.rooms.is_joined(sender_id, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view the room state.",
@@ -2479,21 +2429,15 @@ pub fn get_state_events_route(
#[cfg_attr(
feature = "conduit_bin",
- get(
- "/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>/<_state_key>",
- data = ""
- )
+ get("/_matrix/client/r0/rooms/<_>/state/<_>/<_>", data = "")
)]
pub fn get_state_events_for_key_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
- _event_type: String,
- _state_key: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- if !db.rooms.is_joined(user_id, &body.room_id)? {
+ if !db.rooms.is_joined(sender_id, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view the room state.",
@@ -2517,20 +2461,15 @@ pub fn get_state_events_for_key_route(
#[cfg_attr(
feature = "conduit_bin",
- get(
- "/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>",
- data = ""
- )
+ get("/_matrix/client/r0/rooms/<_>/state/<_>", data = "")
)]
pub fn get_state_events_for_empty_key_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
- _event_type: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- if !db.rooms.is_joined(user_id, &body.room_id)? {
+ if !db.rooms.is_joined(sender_id, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view the room state.",
@@ -2556,14 +2495,19 @@ pub fn get_state_events_for_empty_key_route(
feature = "conduit_bin",
get("/_matrix/client/r0/sync", data = "")
)]
-pub fn sync_route(
+pub async fn sync_events_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- std::thread::sleep(Duration::from_millis(1000));
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let device_id = body.device_id.as_ref().expect("user is authenticated");
+ // TODO: match body.set_presence {
+ db.rooms.edus.ping_presence(&sender_id)?;
+
+ // Setup watchers, so if there's no response, we can wait for them
+ let watcher = db.watch(sender_id, device_id);
+
let next_batch = db.globals.current_count()?.to_string();
let mut joined_rooms = BTreeMap::new();
@@ -2573,23 +2517,50 @@ pub fn sync_route(
.and_then(|string| string.parse().ok())
.unwrap_or(0);
- for room_id in db.rooms.rooms_joined(&user_id) {
+ let mut presence_updates = HashMap::new();
+ let mut device_list_updates = HashSet::new();
+
+ for room_id in db.rooms.rooms_joined(&sender_id) {
let room_id = room_id?;
- let mut pdus = db
+ let mut non_timeline_pdus = db
.rooms
- .pdus_since(&user_id, &room_id, since)?
- .filter_map(|r| r.ok()) // Filter out buggy events
+ .pdus_since(&sender_id, &room_id, since)?
+ .filter_map(|r| r.ok()); // Filter out buggy events
+
+ // Take the last 10 events for the timeline
+ let timeline_pdus = non_timeline_pdus
+ .by_ref()
+ .rev()
+ .take(10)
+ .collect::>()
+ .into_iter()
+ .rev()
.collect::>();
+ // They /sync response doesn't always return all messages, so we say the output is
+ // limited unless there are events in non_timeline_pdus
+ //let mut limited = false;
+
+ let mut state_pdus = Vec::new();
+ for pdu in non_timeline_pdus {
+ if pdu.state_key.is_some() {
+ state_pdus.push(pdu);
+ }
+ }
+
let mut send_member_count = false;
let mut joined_since_last_sync = false;
let mut send_notification_counts = false;
- for pdu in &pdus {
+ for pdu in db
+ .rooms
+ .pdus_since(&sender_id, &room_id, since)?
+ .filter_map(|r| r.ok())
+ {
send_notification_counts = true;
if pdu.kind == EventType::RoomMember {
send_member_count = true;
- if !joined_since_last_sync && pdu.state_key == Some(user_id.to_string()) {
+ if !joined_since_last_sync && pdu.state_key == Some(sender_id.to_string()) {
let content = serde_json::from_value::<
Raw,
>(pdu.content.clone())
@@ -2598,8 +2569,8 @@ pub fn sync_route(
.map_err(|_| Error::bad_database("Invalid PDU in database."))?;
if content.membership == ruma::events::room::member::MembershipState::Join {
joined_since_last_sync = true;
- // Both send_member_count and joined_since_last_sync are set. There's nothing more
- // to do
+ // Both send_member_count and joined_since_last_sync are set. There's
+ // nothing more to do
break;
}
}
@@ -2621,14 +2592,14 @@ pub fn sync_route(
for hero in db
.rooms
- .all_pdus(&user_id, &room_id)?
+ .all_pdus(&sender_id, &room_id)?
.filter_map(|pdu| pdu.ok()) // Ignore all broken pdus
.filter(|pdu| pdu.kind == EventType::RoomMember)
.map(|pdu| {
let content = serde_json::from_value::<
Raw,
>(pdu.content.clone())
- .map_err(|_| Error::bad_database("Invalid member event in database."))?
+ .expect("Raw::from_value always works")
.deserialize()
.map_err(|_| Error::bad_database("Invalid member event in database."))?;
@@ -2646,7 +2617,7 @@ pub fn sync_route(
.content
.clone(),
)
- .map_err(|_| Error::bad_database("Invalid member event in database."))?
+ .expect("Raw::from_value always works")
.deserialize()
.map_err(|_| {
Error::bad_database("Invalid member event in database.")
@@ -2674,7 +2645,7 @@ pub fn sync_route(
// Filter for possible heroes
.filter_map(|u| u)
{
- if heroes.contains(&hero) || hero == user_id.to_string() {
+ if heroes.contains(&hero) || hero == sender_id.to_string() {
continue;
}
@@ -2692,10 +2663,10 @@ pub fn sync_route(
};
let notification_count = if send_notification_counts {
- if let Some(last_read) = db.rooms.edus.room_read_get(&room_id, &user_id)? {
+ if let Some(last_read) = db.rooms.edus.room_read_get(&room_id, &sender_id)? {
Some(
(db.rooms
- .pdus_since(&user_id, &room_id, last_read)?
+ .pdus_since(&sender_id, &room_id, last_read)?
.filter_map(|pdu| pdu.ok()) // Filter out buggy events
.filter(|pdu| {
matches!(
@@ -2713,15 +2684,7 @@ pub fn sync_route(
None
};
- // They /sync response doesn't always return all messages, so we say the output is
- // limited unless there are enough events
- let mut limited = true;
- pdus = pdus.split_off(pdus.len().checked_sub(10).unwrap_or_else(|| {
- limited = false;
- 0
- }));
-
- let prev_batch = pdus.first().map_or(Ok::<_, Error>(None), |e| {
+ let prev_batch = timeline_pdus.first().map_or(Ok::<_, Error>(None), |e| {
Ok(Some(
db.rooms
.get_pdu_count(&e.event_id)?
@@ -2730,7 +2693,7 @@ pub fn sync_route(
))
})?;
- let room_events = pdus
+ let room_events = timeline_pdus
.into_iter()
.map(|pdu| pdu.to_sync_room_event())
.collect::>();
@@ -2763,7 +2726,7 @@ pub fn sync_route(
account_data: sync_events::AccountData {
events: db
.account_data
- .changes_since(Some(&room_id), &user_id, since)?
+ .changes_since(Some(&room_id), &sender_id, since)?
.into_iter()
.filter_map(|(_, v)| {
serde_json::from_str(v.json().get())
@@ -2782,7 +2745,7 @@ pub fn sync_route(
notification_count,
},
timeline: sync_events::Timeline {
- limited: limited || joined_since_last_sync,
+ limited: false || joined_since_last_sync,
prev_batch,
events: room_events,
},
@@ -2804,12 +2767,53 @@ pub fn sync_route(
if !joined_room.is_empty() {
joined_rooms.insert(room_id.clone(), joined_room);
}
+
+ // Look for device list updates in this room
+ device_list_updates.extend(
+ db.users
+ .keys_changed(&room_id, since, None)
+ .filter_map(|r| r.ok()),
+ );
+
+ // Take presence updates from this room
+ for (user_id, presence) in
+ db.rooms
+ .edus
+ .presence_since(&room_id, since, &db.rooms, &db.globals)?
+ {
+ match presence_updates.entry(user_id) {
+ hash_map::Entry::Vacant(v) => {
+ v.insert(presence);
+ }
+ hash_map::Entry::Occupied(mut o) => {
+ let p = o.get_mut();
+
+ // Update existing presence event with more info
+ p.content.presence = presence.content.presence;
+ if let Some(status_msg) = presence.content.status_msg {
+ p.content.status_msg = Some(status_msg);
+ }
+ if let Some(last_active_ago) = presence.content.last_active_ago {
+ p.content.last_active_ago = Some(last_active_ago);
+ }
+ if let Some(displayname) = presence.content.displayname {
+ p.content.displayname = Some(displayname);
+ }
+ if let Some(avatar_url) = presence.content.avatar_url {
+ p.content.avatar_url = Some(avatar_url);
+ }
+ if let Some(currently_active) = presence.content.currently_active {
+ p.content.currently_active = Some(currently_active);
+ }
+ }
+ }
+ }
}
let mut left_rooms = BTreeMap::new();
- for room_id in db.rooms.rooms_left(&user_id) {
+ for room_id in db.rooms.rooms_left(&sender_id) {
let room_id = room_id?;
- let pdus = db.rooms.pdus_since(&user_id, &room_id, since)?;
+ let pdus = db.rooms.pdus_since(&sender_id, &room_id, since)?;
let room_events = pdus
.filter_map(|pdu| pdu.ok()) // Filter out buggy events
.map(|pdu| pdu.to_sync_room_event())
@@ -2856,7 +2860,7 @@ pub fn sync_route(
}
let mut invited_rooms = BTreeMap::new();
- for room_id in db.rooms.rooms_invited(&user_id) {
+ for room_id in db.rooms.rooms_invited(&sender_id) {
let room_id = room_id?;
let invited_room = sync_events::InvitedRoom {
@@ -2877,9 +2881,9 @@ pub fn sync_route(
// Remove all to-device events the device received *last time*
db.users
- .remove_to_device_events(user_id, device_id, since)?;
+ .remove_to_device_events(sender_id, device_id, since)?;
- Ok(sync_events::Response {
+ let response = sync_events::Response {
next_batch,
rooms: sync_events::Rooms {
leave: left_rooms,
@@ -2887,29 +2891,15 @@ pub fn sync_route(
invite: invited_rooms,
},
presence: sync_events::Presence {
- events: db
- .global_edus
- .presence_since(since)?
- .map(|edu| {
- let mut edu = edu?
- .deserialize()
- .map_err(|_| Error::bad_database("EDU in database is invalid."))?;
- if let Some(timestamp) = edu.content.last_active_ago {
- let mut last_active_ago = utils::millis_since_unix_epoch()
- .try_into()
- .expect("time is valid");
- last_active_ago -= timestamp;
- edu.content.last_active_ago = Some(last_active_ago);
- }
- Ok::<_, Error>(edu.into())
- })
- .filter_map(|edu| edu.ok()) // Filter out buggy events
+ events: presence_updates
+ .into_iter()
+ .map(|(_, v)| Raw::from(v))
.collect(),
},
account_data: sync_events::AccountData {
events: db
.account_data
- .changes_since(None, &user_id, since)?
+ .changes_since(None, &sender_id, since)?
.into_iter()
.filter_map(|(_, v)| {
serde_json::from_str(v.json().get())
@@ -2919,40 +2909,55 @@ pub fn sync_route(
.collect::>(),
},
device_lists: sync_events::DeviceLists {
- changed: if since != 0 {
- db.users
- .keys_changed(since)
- .filter_map(|u| u.ok())
- .collect() // Filter out buggy events
- } else {
- Vec::new()
- },
+ changed: device_list_updates.into_iter().collect(),
left: Vec::new(), // TODO
},
- device_one_time_keys_count: Default::default(), // TODO
- to_device: sync_events::ToDevice {
- events: db.users.get_to_device_events(user_id, device_id)?,
+ device_one_time_keys_count: if db.users.last_one_time_keys_update(sender_id)? > since {
+ db.users.count_one_time_keys(sender_id, device_id)?
+ } else {
+ BTreeMap::new()
},
+ to_device: sync_events::ToDevice {
+ events: db.users.get_to_device_events(sender_id, device_id)?,
+ },
+ };
+
+ // TODO: Retry the endpoint instead of returning (waiting for #118)
+ if !body.full_state
+ && response.rooms.is_empty()
+ && response.presence.is_empty()
+ && response.account_data.is_empty()
+ && response.device_lists.is_empty()
+ && response.device_one_time_keys_count.is_empty()
+ && response.to_device.is_empty()
+ {
+ // Hang a few seconds so requests are not spammed
+ // Stop hanging if new info arrives
+ let mut duration = body.timeout.unwrap_or(Duration::default());
+ if duration.as_secs() > 30 {
+ duration = Duration::from_secs(30);
+ }
+ let mut delay = tokio::time::delay_for(duration);
+ tokio::select! {
+ _ = &mut delay => {}
+ _ = watcher => {}
+ }
}
- .into())
+
+ Ok(response.into())
}
#[cfg_attr(
feature = "conduit_bin",
- get(
- "/_matrix/client/r0/rooms/<_room_id>/context/<_event_id>",
- data = ""
- )
+ get("/_matrix/client/r0/rooms/<_>/context/<_>", data = "")
)]
pub fn get_context_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
- _event_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- if !db.rooms.is_joined(user_id, &body.room_id)? {
+ if !db.rooms.is_joined(sender_id, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
@@ -2975,7 +2980,7 @@ pub fn get_context_route(
let events_before = db
.rooms
- .pdus_until(&user_id, &body.room_id, base_token)
+ .pdus_until(&sender_id, &body.room_id, base_token)
.take(
u32::try_from(body.limit).map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid.")
@@ -2985,14 +2990,7 @@ pub fn get_context_route(
.filter_map(|r| r.ok()) // Remove buggy events
.collect::>();
- let start_token = events_before.last().map_or(Ok(None), |(_, e)| {
- Ok::<_, Error>(Some(
- db.rooms
- .get_pdu_count(&e.event_id)?
- .ok_or_else(|| Error::bad_database("Can't find count from event in db."))?
- .to_string(),
- ))
- })?;
+ let start_token = events_before.last().map(|(count, _)| count.to_string());
let events_before = events_before
.into_iter()
@@ -3001,7 +2999,7 @@ pub fn get_context_route(
let events_after = db
.rooms
- .pdus_after(&user_id, &body.room_id, base_token)
+ .pdus_after(&sender_id, &body.room_id, base_token)
.take(
u32::try_from(body.limit).map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid.")
@@ -3011,15 +3009,7 @@ pub fn get_context_route(
.filter_map(|r| r.ok()) // Remove buggy events
.collect::>();
- let end_token = if let Some(last_event) = events_after.last() {
- Some(
- utils::u64_from_bytes(&last_event.0)
- .map_err(|_| Error::bad_database("Invalid pdu id in db."))?
- .to_string(),
- )
- } else {
- None
- };
+ let end_token = events_after.last().map(|(count, _)| count.to_string());
let events_after = events_after
.into_iter()
@@ -3044,16 +3034,15 @@ pub fn get_context_route(
#[cfg_attr(
feature = "conduit_bin",
- get("/_matrix/client/r0/rooms/<_room_id>/messages", data = "")
+ get("/_matrix/client/r0/rooms/<_>/messages", data = "")
)]
pub fn get_message_events_route(
db: State<'_, Database>,
body: Ruma,
- _room_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
- if !db.rooms.is_joined(user_id, &body.room_id)? {
+ if !db.rooms.is_joined(sender_id, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
@@ -3066,7 +3055,7 @@ pub fn get_message_events_route(
.parse()
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `from` value."))?;
- let to = body.to.as_ref().map(|t| t.as_bytes());
+ let to = body.to.as_ref().map(|t| t.parse());
// Use limit or else 10
let limit = body
@@ -3078,21 +3067,13 @@ pub fn get_message_events_route(
get_message_events::Direction::Forward => {
let events_after = db
.rooms
- .pdus_after(&user_id, &body.room_id, from)
+ .pdus_after(&sender_id, &body.room_id, from)
.take(limit)
.filter_map(|r| r.ok()) // Filter out buggy events
- .take_while(|(k, _)| Some(&**k) != to) // Stop at `to`
+ .take_while(|&(k, _)| Some(Ok(k)) != to) // Stop at `to`
.collect::>();
- let end_token = if let Some(last_event) = events_after.last() {
- Some(
- utils::u64_from_bytes(&last_event.0)
- .map_err(|_| Error::bad_database("Invalid pdu id in db."))?
- .to_string(),
- )
- } else {
- None
- };
+ let end_token = events_after.last().map(|(count, _)| count.to_string());
let events_after = events_after
.into_iter()
@@ -3110,21 +3091,13 @@ pub fn get_message_events_route(
get_message_events::Direction::Backward => {
let events_before = db
.rooms
- .pdus_until(&user_id, &body.room_id, from)
+ .pdus_until(&sender_id, &body.room_id, from)
.take(limit)
.filter_map(|r| r.ok()) // Filter out buggy events
- .take_while(|(k, _)| Some(&**k) != to) // Stop at `to`
+ .take_while(|&(k, _)| Some(Ok(k)) != to) // Stop at `to`
.collect::>();
- let start_token = if let Some(last_event) = events_before.last() {
- Some(
- utils::u64_from_bytes(&last_event.0)
- .map_err(|_| Error::bad_database("Invalid pdu id in db."))?
- .to_string(),
- )
- } else {
- None
- };
+ let start_token = events_before.last().map(|(count, _)| count.to_string());
let events_before = events_before
.into_iter()
@@ -3160,25 +3133,20 @@ pub fn publicised_groups_route() -> ConduitResult/<_txn_id>",
- data = ""
- )
+ put("/_matrix/client/r0/sendToDevice/<_>/<_>", data = "")
)]
pub fn send_event_to_device_route(
db: State<'_, Database>,
body: Ruma,
- _event_type: String,
- _txn_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
for (target_user_id, map) in &body.messages {
for (target_device_id_maybe, event) in map {
match target_device_id_maybe {
to_device::DeviceIdOrAllDevices::DeviceId(target_device_id) => {
db.users.add_to_device_event(
- user_id,
+ sender_id,
&target_user_id,
&target_device_id,
&body.event_type,
@@ -3192,7 +3160,7 @@ pub fn send_event_to_device_route(
to_device::DeviceIdOrAllDevices::AllDevices => {
for target_device_id in db.users.all_device_ids(&target_user_id) {
db.users.add_to_device_event(
- user_id,
+ sender_id,
&target_user_id,
&target_device_id?,
&body.event_type,
@@ -3307,11 +3275,11 @@ pub fn get_devices_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let devices = db
.users
- .all_devices_metadata(user_id)
+ .all_devices_metadata(sender_id)
.filter_map(|r| r.ok()) // Filter out buggy devices
.collect::>();
@@ -3327,11 +3295,11 @@ pub fn get_device_route(
body: Ruma,
_device_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let device = db
.users
- .get_device_metadata(&user_id, &body.body.device_id)?
+ .get_device_metadata(&sender_id, &body.body.device_id)?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Device not found."))?;
Ok(get_device::Response { device }.into())
@@ -3346,17 +3314,17 @@ pub fn update_device_route(
body: Ruma,
_device_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let mut device = db
.users
- .get_device_metadata(&user_id, &body.body.device_id)?
+ .get_device_metadata(&sender_id, &body.body.device_id)?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Device not found."))?;
device.display_name = body.display_name.clone();
db.users
- .update_device_metadata(&user_id, &body.body.device_id, &device)?;
+ .update_device_metadata(&sender_id, &body.body.device_id, &device)?;
Ok(update_device::Response.into())
}
@@ -3370,7 +3338,7 @@ pub fn delete_device_route(
body: Ruma,
_device_id: String,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let device_id = body.device_id.as_ref().expect("user is authenticated");
// UIAA
@@ -3386,7 +3354,7 @@ pub fn delete_device_route(
if let Some(auth) = &body.auth {
let (worked, uiaainfo) = db.uiaa.try_auth(
- &user_id,
+ &sender_id,
&device_id,
auth,
&uiaainfo,
@@ -3399,11 +3367,11 @@ pub fn delete_device_route(
// Success!
} else {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
- db.uiaa.create(&user_id, &device_id, &uiaainfo)?;
+ db.uiaa.create(&sender_id, &device_id, &uiaainfo)?;
return Err(Error::Uiaa(uiaainfo));
}
- db.users.remove_device(&user_id, &body.body.device_id)?;
+ db.users.remove_device(&sender_id, &body.body.device_id)?;
Ok(delete_device::Response.into())
}
@@ -3416,7 +3384,7 @@ pub fn delete_devices_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let device_id = body.device_id.as_ref().expect("user is authenticated");
// UIAA
@@ -3432,7 +3400,7 @@ pub fn delete_devices_route(
if let Some(auth) = &body.auth {
let (worked, uiaainfo) = db.uiaa.try_auth(
- &user_id,
+ &sender_id,
&device_id,
auth,
&uiaainfo,
@@ -3445,12 +3413,12 @@ pub fn delete_devices_route(
// Success!
} else {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
- db.uiaa.create(&user_id, &device_id, &uiaainfo)?;
+ db.uiaa.create(&sender_id, &device_id, &uiaainfo)?;
return Err(Error::Uiaa(uiaainfo));
}
for device_id in &body.devices {
- db.users.remove_device(&user_id, &device_id)?
+ db.users.remove_device(&sender_id, &device_id)?
}
Ok(delete_devices::Response.into())
@@ -3464,7 +3432,7 @@ pub fn upload_signing_keys_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let device_id = body.device_id.as_ref().expect("user is authenticated");
// UIAA
@@ -3480,7 +3448,7 @@ pub fn upload_signing_keys_route(
if let Some(auth) = &body.auth {
let (worked, uiaainfo) = db.uiaa.try_auth(
- &user_id,
+ &sender_id,
&device_id,
auth,
&uiaainfo,
@@ -3493,16 +3461,17 @@ pub fn upload_signing_keys_route(
// Success!
} else {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
- db.uiaa.create(&user_id, &device_id, &uiaainfo)?;
+ db.uiaa.create(&sender_id, &device_id, &uiaainfo)?;
return Err(Error::Uiaa(uiaainfo));
}
if let Some(master_key) = &body.master_key {
db.users.add_cross_signing_keys(
- user_id,
+ sender_id,
&master_key,
&body.self_signing_key,
&body.user_signing_key,
+ &db.rooms,
&db.globals,
)?;
}
@@ -3518,7 +3487,7 @@ pub fn upload_signatures_route(
db: State<'_, Database>,
body: Ruma,
) -> ConduitResult {
- let sender_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
for (user_id, signed_keys) in &body.signed_keys {
for (key_id, signed_key) in signed_keys {
@@ -3553,8 +3522,14 @@ pub fn upload_signatures_route(
))?
.to_owned(),
);
- db.users
- .sign_key(&user_id, &key_id, signature, &sender_id, &db.globals)?;
+ db.users.sign_key(
+ &user_id,
+ &key_id,
+ signature,
+ &sender_id,
+ &db.rooms,
+ &db.globals,
+ )?;
}
}
}
@@ -3562,6 +3537,39 @@ pub fn upload_signatures_route(
Ok(upload_signatures::Response.into())
}
+#[cfg_attr(
+ feature = "conduit_bin",
+ get("/_matrix/client/r0/keys/changes", data = "")
+)]
+pub fn get_key_changes_route(
+ db: State<'_, Database>,
+ body: Ruma,
+) -> ConduitResult {
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
+
+ let mut device_list_updates = HashSet::new();
+ for room_id in db.rooms.rooms_joined(sender_id).filter_map(|r| r.ok()) {
+ device_list_updates.extend(
+ db.users
+ .keys_changed(
+ &room_id,
+ body.from.parse().map_err(|_| {
+ Error::BadRequest(ErrorKind::InvalidParam, "Invalid `from`.")
+ })?,
+ Some(body.to.parse().map_err(|_| {
+ Error::BadRequest(ErrorKind::InvalidParam, "Invalid `to`.")
+ })?),
+ )
+ .filter_map(|r| r.ok()),
+ );
+ }
+ Ok(get_key_changes::Response {
+ changed: device_list_updates.into_iter().collect(),
+ left: Vec::new(), // TODO
+ }
+ .into())
+}
+
#[cfg_attr(feature = "conduit_bin", get("/_matrix/client/r0/pushers"))]
pub fn pushers_route() -> ConduitResult {
Ok(get_pushers::Response {
@@ -3580,23 +3588,17 @@ pub fn set_pushers_route() -> ConduitResult {
#[cfg_attr(
feature = "conduit_bin",
- put(
- "/_matrix/client/r0/user/<_user_id>/rooms/<_room_id>/tags/<_tag>",
- data = ""
- )
+ put("/_matrix/client/r0/user/<_>/rooms/<_>/tags/<_>", data = "")
)]
pub fn update_tag_route(
db: State<'_, Database>,
- _user_id: String,
- _room_id: String,
- _tag: String,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let mut tags_event = db
.account_data
- .get::(Some(&body.room_id), user_id, EventType::Tag)?
+ .get::(Some(&body.room_id), sender_id, EventType::Tag)?
.unwrap_or_else(|| ruma::events::tag::TagEvent {
content: ruma::events::tag::TagEventContent {
tags: BTreeMap::new(),
@@ -3609,7 +3611,7 @@ pub fn update_tag_route(
db.account_data.update(
Some(&body.room_id),
- user_id,
+ sender_id,
EventType::Tag,
&tags_event,
&db.globals,
@@ -3620,23 +3622,17 @@ pub fn update_tag_route(
#[cfg_attr(
feature = "conduit_bin",
- delete(
- "/_matrix/client/r0/user/<_user_id>/rooms/<_room_id>/tags/<_tag>",
- data = ""
- )
+ delete("/_matrix/client/r0/user/<_>/rooms/<_>/tags/<_>", data = "")
)]
pub fn delete_tag_route(
db: State<'_, Database>,
- _user_id: String,
- _room_id: String,
- _tag: String,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let mut tags_event = db
.account_data
- .get::(Some(&body.room_id), user_id, EventType::Tag)?
+ .get::(Some(&body.room_id), sender_id, EventType::Tag)?
.unwrap_or_else(|| ruma::events::tag::TagEvent {
content: ruma::events::tag::TagEventContent {
tags: BTreeMap::new(),
@@ -3646,7 +3642,7 @@ pub fn delete_tag_route(
db.account_data.update(
Some(&body.room_id),
- user_id,
+ sender_id,
EventType::Tag,
&tags_event,
&db.globals,
@@ -3657,23 +3653,18 @@ pub fn delete_tag_route(
#[cfg_attr(
feature = "conduit_bin",
- get(
- "/_matrix/client/r0/user/<_user_id>/rooms/<_room_id>/tags",
- data = ""
- )
+ get("/_matrix/client/r0/user/<_>/rooms/<_>/tags", data = "")
)]
pub fn get_tags_route(
db: State<'_, Database>,
- _user_id: String,
- _room_id: String,
body: Ruma,
) -> ConduitResult {
- let user_id = body.user_id.as_ref().expect("user is authenticated");
+ let sender_id = body.sender_id.as_ref().expect("user is authenticated");
Ok(get_tags::Response {
tags: db
.account_data
- .get::(Some(&body.room_id), user_id, EventType::Tag)?
+ .get::(Some(&body.room_id), sender_id, EventType::Tag)?
.unwrap_or_else(|| ruma::events::tag::TagEvent {
content: ruma::events::tag::TagEventContent {
tags: BTreeMap::new(),
@@ -3686,9 +3677,7 @@ pub fn get_tags_route(
}
#[cfg(feature = "conduit_bin")]
-#[options("/<_segments..>")]
-pub fn options_route(
- _segments: rocket::http::uri::Segments<'_>,
-) -> ConduitResult {
+#[options("/<_..>")]
+pub fn options_route() -> ConduitResult {
Ok(send_event_to_device::Response.into())
}
diff --git a/src/database.rs b/src/database.rs
index 370fde75..5a1ed0f6 100644
--- a/src/database.rs
+++ b/src/database.rs
@@ -1,5 +1,4 @@
pub(self) mod account_data;
-pub(self) mod global_edus;
pub(self) mod globals;
pub(self) mod key_backups;
pub(self) mod media;
@@ -12,7 +11,9 @@ use directories::ProjectDirs;
use log::info;
use std::fs::remove_dir_all;
-use rocket::Config;
+use futures::StreamExt;
+use rocket::{futures, Config};
+use ruma::{DeviceId, UserId};
pub struct Database {
pub globals: globals::Globals,
@@ -20,7 +21,6 @@ pub struct Database {
pub uiaa: uiaa::Uiaa,
pub rooms: rooms::Rooms,
pub account_data: account_data::AccountData,
- pub global_edus: global_edus::GlobalEdus,
pub media: media::Media,
pub key_backups: key_backups::KeyBackups,
pub _db: sled::Db,
@@ -75,6 +75,7 @@ impl Database {
userdeviceid_metadata: db.open_tree("userdeviceid_metadata")?,
token_userdeviceid: db.open_tree("token_userdeviceid")?,
onetimekeyid_onetimekeys: db.open_tree("onetimekeyid_onetimekeys")?,
+ userid_lastonetimekeyupdate: db.open_tree("userid_lastonetimekeyupdate")?,
keychangeid_userid: db.open_tree("devicekeychangeid_userid")?,
keyid_key: db.open_tree("keyid_key")?,
userid_masterkeyid: db.open_tree("userid_masterkeyid")?,
@@ -91,6 +92,8 @@ impl Database {
roomlatestid_roomlatest: db.open_tree("roomlatestid_roomlatest")?, // Read receipts
roomactiveid_userid: db.open_tree("roomactiveid_userid")?, // Typing notifs
roomid_lastroomactiveupdate: db.open_tree("roomid_lastroomactiveupdate")?,
+ presenceid_presence: db.open_tree("presenceid_presence")?,
+ userid_lastpresenceupdate: db.open_tree("userid_lastpresenceupdate")?,
},
pduid_pdu: db.open_tree("pduid_pdu")?,
eventid_pduid: db.open_tree("eventid_pduid")?,
@@ -110,9 +113,6 @@ impl Database {
account_data: account_data::AccountData {
roomuserdataid_accountdata: db.open_tree("roomuserdataid_accountdata")?,
},
- global_edus: global_edus::GlobalEdus {
- presenceid_presence: db.open_tree("presenceid_presence")?, // Presence
- },
media: media::Media {
mediaid_file: db.open_tree("mediaid_file")?,
},
@@ -124,4 +124,74 @@ impl Database {
_db: db,
})
}
+
+ pub async fn watch(&self, user_id: &UserId, device_id: &DeviceId) -> () {
+ let mut userid_prefix = user_id.to_string().as_bytes().to_vec();
+ userid_prefix.push(0xff);
+ let mut userdeviceid_prefix = userid_prefix.clone();
+ userdeviceid_prefix.extend_from_slice(device_id.as_bytes());
+ userdeviceid_prefix.push(0xff);
+
+ let mut futures = futures::stream::FuturesUnordered::new();
+
+ futures.push(self.users.keychangeid_userid.watch_prefix(b""));
+
+ // Return when *any* user changed his key
+ // TODO: only send for user they share a room with
+ futures.push(
+ self.users
+ .todeviceid_events
+ .watch_prefix(&userdeviceid_prefix),
+ );
+
+ futures.push(self.rooms.userroomid_joined.watch_prefix(&userid_prefix));
+ futures.push(self.rooms.userroomid_invited.watch_prefix(&userid_prefix));
+ futures.push(self.rooms.userroomid_left.watch_prefix(&userid_prefix));
+
+ // Events for rooms we are in
+ for room_id in self.rooms.rooms_joined(user_id).filter_map(|r| r.ok()) {
+ let mut roomid_prefix = room_id.to_string().as_bytes().to_vec();
+ roomid_prefix.push(0xff);
+
+ // PDUs
+ futures.push(self.rooms.pduid_pdu.watch_prefix(&roomid_prefix));
+
+ // EDUs
+ futures.push(
+ self.rooms
+ .edus
+ .roomid_lastroomactiveupdate
+ .watch_prefix(&roomid_prefix),
+ );
+
+ futures.push(
+ self.rooms
+ .edus
+ .roomlatestid_roomlatest
+ .watch_prefix(&roomid_prefix),
+ );
+
+ // Room account data
+ let mut roomuser_prefix = roomid_prefix.clone();
+ roomuser_prefix.extend_from_slice(&userid_prefix);
+
+ futures.push(
+ self.account_data
+ .roomuserdataid_accountdata
+ .watch_prefix(&roomuser_prefix),
+ );
+ }
+
+ let mut globaluserdata_prefix = vec![0xff];
+ globaluserdata_prefix.extend_from_slice(&userid_prefix);
+
+ futures.push(
+ self.account_data
+ .roomuserdataid_accountdata
+ .watch_prefix(&globaluserdata_prefix),
+ );
+
+ // Wait until one of them finds something
+ futures.next().await;
+ }
}
diff --git a/src/database/account_data.rs b/src/database/account_data.rs
index 1afbcd61..99e0d5c7 100644
--- a/src/database/account_data.rs
+++ b/src/database/account_data.rs
@@ -1,5 +1,6 @@
use crate::{utils, Error, Result};
use ruma::{
+ api::client::error::ErrorKind,
events::{AnyEvent as EduEvent, EventType},
Raw, RoomId, UserId,
};
@@ -19,7 +20,7 @@ impl AccountData {
room_id: Option<&RoomId>,
user_id: &UserId,
event_type: EventType,
- event: &T,
+ data: &T,
globals: &super::globals::Globals,
) -> Result<()> {
let mut prefix = room_id
@@ -42,10 +43,16 @@ impl AccountData {
key.push(0xff);
key.extend_from_slice(event_type.to_string().as_bytes());
- self.roomuserdataid_accountdata.insert(
- key,
- &*serde_json::to_string(&event).expect("Map::to_string always works"),
- )?;
+ let json = serde_json::to_value(data).expect("all types here can be serialized"); // TODO: maybe add error handling
+ if json.get("type").is_none() || json.get("content").is_none() {
+ return Err(Error::BadRequest(
+ ErrorKind::InvalidParam,
+ "Account data doesn't have all required fields.",
+ ));
+ }
+
+ self.roomuserdataid_accountdata
+ .insert(key, &*json.to_string())?;
Ok(())
}
@@ -60,7 +67,7 @@ impl AccountData {
self.find_event(room_id, user_id, &kind)
.map(|r| {
let (_, v) = r?;
- serde_json::from_slice(&v).map_err(|_| Error::BadDatabase("could not deserialize"))
+ serde_json::from_slice(&v).map_err(|_| Error::bad_database("could not deserialize"))
})
.transpose()
}
diff --git a/src/database/global_edus.rs b/src/database/global_edus.rs
deleted file mode 100644
index 94f2de82..00000000
--- a/src/database/global_edus.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use crate::{Error, Result};
-use ruma::Raw;
-
-pub struct GlobalEdus {
- //pub globalallid_globalall: sled::Tree, // ToDevice, GlobalAllId = UserId + Count
- pub(super) presenceid_presence: sled::Tree, // Presence, PresenceId = Count + UserId
-}
-
-impl GlobalEdus {
- /// Adds a global event which will be saved until a new event replaces it (e.g. presence updates).
- pub fn update_presence(
- &self,
- presence: ruma::events::presence::PresenceEvent,
- globals: &super::globals::Globals,
- ) -> Result<()> {
- // Remove old entry
- if let Some(old) = self
- .presenceid_presence
- .iter()
- .keys()
- .rev()
- .filter_map(|r| r.ok())
- .find(|key| {
- key.rsplit(|&b| b == 0xff)
- .next()
- .expect("rsplit always returns an element")
- == presence.sender.to_string().as_bytes()
- })
- {
- // This is the old global_latest
- self.presenceid_presence.remove(old)?;
- }
-
- let mut presence_id = globals.next_count()?.to_be_bytes().to_vec();
- presence_id.push(0xff);
- presence_id.extend_from_slice(&presence.sender.to_string().as_bytes());
-
- self.presenceid_presence.insert(
- presence_id,
- &*serde_json::to_string(&presence).expect("PresenceEvent can be serialized"),
- )?;
-
- Ok(())
- }
-
- /// Returns an iterator over the most recent presence updates that happened after the event with id `since`.
- pub fn presence_since(
- &self,
- since: u64,
- ) -> Result>>> {
- let first_possible_edu = (since + 1).to_be_bytes().to_vec(); // +1 so we don't send the event at since
-
- Ok(self
- .presenceid_presence
- .range(&*first_possible_edu..)
- .filter_map(|r| r.ok())
- .map(|(_, v)| {
- Ok(serde_json::from_slice(&v)
- .map_err(|_| Error::bad_database("Invalid presence event in db."))?)
- }))
- }
-}
diff --git a/src/database/rooms.rs b/src/database/rooms.rs
index 0395cc20..7895f025 100644
--- a/src/database/rooms.rs
+++ b/src/database/rooms.rs
@@ -611,44 +611,29 @@ impl Rooms {
self.pdus_since(user_id, room_id, 0)
}
- /// Returns an iterator over all events in a room that happened after the event with id `since`.
+ /// Returns a double-ended iterator over all events in a room that happened after the event with id `since`
+ /// in chronological order.
pub fn pdus_since(
&self,
user_id: &UserId,
room_id: &RoomId,
since: u64,
- ) -> Result>> {
- // Create the first part of the full pdu id
- let mut pdu_id = room_id.to_string().as_bytes().to_vec();
- pdu_id.push(0xff);
- pdu_id.extend_from_slice(&(since).to_be_bytes());
-
- self.pdus_since_pduid(user_id, room_id, &pdu_id)
- }
-
- /// Returns an iterator over all events in a room that happened after the event with id `since`.
- pub fn pdus_since_pduid(
- &self,
- user_id: &UserId,
- room_id: &RoomId,
- pdu_id: &[u8],
- ) -> Result>> {
- // Create the first part of the full pdu id
+ ) -> Result>> {
let mut prefix = room_id.to_string().as_bytes().to_vec();
prefix.push(0xff);
+ // Skip the first pdu if it's exactly at since, because we sent that last time
+ let mut first_pdu_id = prefix.clone();
+ first_pdu_id.extend_from_slice(&(since + 1).to_be_bytes());
+
+ let mut last_pdu_id = prefix.clone();
+ last_pdu_id.extend_from_slice(&u64::MAX.to_be_bytes());
+
let user_id = user_id.clone();
Ok(self
.pduid_pdu
- .range(pdu_id..)
- // Skip the first pdu if it's exactly at since, because we sent that last time
- .skip(if self.pduid_pdu.get(pdu_id)?.is_some() {
- 1
- } else {
- 0
- })
+ .range(first_pdu_id..last_pdu_id)
.filter_map(|r| r.ok())
- .take_while(move |(k, _)| k.starts_with(&prefix))
.map(move |(_, v)| {
let mut pdu = serde_json::from_slice::(&v)
.map_err(|_| Error::bad_database("PDU in db is invalid."))?;
@@ -666,7 +651,7 @@ impl Rooms {
user_id: &UserId,
room_id: &RoomId,
until: u64,
- ) -> impl Iterator- > {
+ ) -> impl Iterator
- > {
// Create the first part of the full pdu id
let mut prefix = room_id.to_string().as_bytes().to_vec();
prefix.push(0xff);
@@ -677,6 +662,7 @@ impl Rooms {
let current: &[u8] = ¤t;
let user_id = user_id.clone();
+ let prefixlen = prefix.len();
self.pduid_pdu
.range(..current)
.rev()
@@ -688,7 +674,11 @@ impl Rooms {
if pdu.sender != user_id {
pdu.unsigned.remove("transaction_id");
}
- Ok((k, pdu))
+ Ok((
+ utils::u64_from_bytes(&k[prefixlen..])
+ .map_err(|_| Error::bad_database("Invalid pdu id in db."))?,
+ pdu,
+ ))
})
}
@@ -699,7 +689,7 @@ impl Rooms {
user_id: &UserId,
room_id: &RoomId,
from: u64,
- ) -> impl Iterator
- > {
+ ) -> impl Iterator
- > {
// Create the first part of the full pdu id
let mut prefix = room_id.to_string().as_bytes().to_vec();
prefix.push(0xff);
@@ -710,6 +700,7 @@ impl Rooms {
let current: &[u8] = ¤t;
let user_id = user_id.clone();
+ let prefixlen = prefix.len();
self.pduid_pdu
.range(current..)
.filter_map(|r| r.ok())
@@ -720,7 +711,11 @@ impl Rooms {
if pdu.sender != user_id {
pdu.unsigned.remove("transaction_id");
}
- Ok((k, pdu))
+ Ok((
+ utils::u64_from_bytes(&k[prefixlen..])
+ .map_err(|_| Error::bad_database("Invalid pdu id in db."))?,
+ pdu,
+ ))
})
}
@@ -919,7 +914,7 @@ impl Rooms {
})
}
- /// Returns an iterator over all left members of a room.
+ /// Returns an iterator over all rooms this user joined.
pub fn rooms_joined(&self, user_id: &UserId) -> impl Iterator
- > {
self.userroomid_joined
.scan_prefix(user_id.to_string())
diff --git a/src/database/rooms/edus.rs b/src/database/rooms/edus.rs
index 22d01666..fff30c22 100644
--- a/src/database/rooms/edus.rs
+++ b/src/database/rooms/edus.rs
@@ -1,15 +1,25 @@
use crate::{utils, Error, Result};
+use js_int::UInt;
use ruma::{
- events::{AnyEvent as EduEvent, SyncEphemeralRoomEvent},
+ events::{
+ presence::{PresenceEvent, PresenceEventContent},
+ AnyEvent as EduEvent, SyncEphemeralRoomEvent,
+ },
+ presence::PresenceState,
Raw, RoomId, UserId,
};
-use std::convert::TryFrom;
+use std::{
+ collections::HashMap,
+ convert::{TryFrom, TryInto},
+};
pub struct RoomEdus {
pub(in super::super) roomuserid_lastread: sled::Tree, // RoomUserId = Room + User
pub(in super::super) roomlatestid_roomlatest: sled::Tree, // Read Receipts, RoomLatestId = RoomId + Count + UserId
pub(in super::super) roomactiveid_userid: sled::Tree, // Typing, RoomActiveId = RoomId + TimeoutTime + Count
pub(in super::super) roomid_lastroomactiveupdate: sled::Tree, // LastRoomActiveUpdate = Count
+ pub(in super::super) presenceid_presence: sled::Tree, // PresenceId = RoomId + Count + UserId
+ pub(in super::super) userid_lastpresenceupdate: sled::Tree, // LastPresenceUpdate = Count
}
impl RoomEdus {
@@ -263,4 +273,182 @@ impl RoomEdus {
})?))
})
}
+
+ /// Adds a presence event which will be saved until a new event replaces it.
+ ///
+ /// Note: This method takes a RoomId because presence updates are always bound to rooms to
+ /// make sure users outside these rooms can't see them.
+ pub fn update_presence(
+ &self,
+ user_id: &UserId,
+ room_id: &RoomId,
+ presence: ruma::events::presence::PresenceEvent,
+ globals: &super::super::globals::Globals,
+ ) -> Result<()> {
+ // TODO: Remove old entry? Or maybe just wipe completely from time to time?
+
+ let count = globals.next_count()?.to_be_bytes();
+
+ let mut presence_id = room_id.to_string().as_bytes().to_vec();
+ presence_id.push(0xff);
+ presence_id.extend_from_slice(&count);
+ presence_id.push(0xff);
+ presence_id.extend_from_slice(&presence.sender.to_string().as_bytes());
+
+ self.presenceid_presence.insert(
+ presence_id,
+ &*serde_json::to_string(&presence).expect("PresenceEvent can be serialized"),
+ )?;
+
+ self.userid_lastpresenceupdate.insert(
+ &user_id.to_string().as_bytes(),
+ &utils::millis_since_unix_epoch().to_be_bytes(),
+ )?;
+
+ Ok(())
+ }
+
+ /// Resets the presence timeout, so the user will stay in their current presence state.
+ pub fn ping_presence(&self, user_id: &UserId) -> Result<()> {
+ self.userid_lastpresenceupdate.insert(
+ &user_id.to_string().as_bytes(),
+ &utils::millis_since_unix_epoch().to_be_bytes(),
+ )?;
+
+ Ok(())
+ }
+
+ /// Returns the timestamp of the last presence update of this user in millis since the unix epoch.
+ pub fn last_presence_update(&self, user_id: &UserId) -> Result