From 10bb96fcf7fe9da7f4e5001082348caf620cf3c0 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Mon, 6 Apr 2020 13:46:46 +0200 Subject: [PATCH] feat: room joining, room based /sync responses --- Cargo.lock | 9 +++--- Cargo.toml | 2 +- src/data.rs | 79 ++++++++++++++++++++++++++++------------------ src/database.rs | 38 ++++++++++++++++------ src/main.rs | 83 +++++++++++++++++++++++++++++++------------------ 5 files changed, 134 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d224117..2978456a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1050,9 +1050,8 @@ dependencies = [ [[package]] name = "ruma-client-api" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b390a86d36e87cc56111802bfd281eed1095f5097a89677101d0271d8e6b1306" +version = "0.7.2" +source = "git+https://github.com/ruma/ruma-client-api.git#fe92c2940a2db80509e9a9f162c0f68f3ec3d0a4" dependencies = [ "http", "js_int", @@ -1193,9 +1192,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" +checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index f61995be..631e6eea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] rocket = { git = "https://github.com/SergioBenitez/Rocket.git", branch = "async", features = ["tls"] } http = "0.2.1" -ruma-client-api = "0.7.1" +ruma-client-api = { git = "https://github.com/ruma/ruma-client-api.git" } pretty_env_logger = "0.4.0" log = "0.4.8" sled = "0.31.0" diff --git a/src/data.rs b/src/data.rs index 86a7aa91..0467d22d 100644 --- a/src/data.rs +++ b/src/data.rs @@ -107,6 +107,29 @@ impl Data { .unwrap(); } + pub fn room_join(&self, room_id: &RoomId, user_id: &UserId) { + self.db.userid_roomids.add( + user_id.to_string().as_bytes(), + room_id.to_string().as_bytes().into(), + ); + self.db.roomid_userids.add( + room_id.to_string().as_bytes(), + user_id.to_string().as_bytes().into(), + ); + } + + pub fn rooms_joined(&self, user_id: &UserId) -> Vec { + self.db + .userid_roomids + .get_iter(user_id.to_string().as_bytes()) + .values() + .map(|room_id| { + RoomId::try_from(&*utils::string_from_bytes(&room_id.unwrap())) + .expect("user joined valid room ids") + }) + .collect() + } + pub fn pdu_get(&self, event_id: &EventId) -> Option { self.db .eventid_pduid @@ -157,7 +180,7 @@ impl Data { room_id: RoomId, sender: UserId, event_type: EventType, - content: MessageEventContent, + content: serde_json::Value, ) -> EventId { // prev_events are the leaves of the current graph. This method removes all leaves from the // room and replaces them with our event @@ -184,7 +207,7 @@ impl Data { origin: self.hostname.clone(), origin_server_ts: utils::millis_since_unix_epoch(), kind: event_type, - content: serde_json::to_value(content).expect("message content is valid json"), + content, state_key: None, prev_events, depth: depth.try_into().unwrap(), @@ -207,9 +230,10 @@ impl Data { self.pdu_leaves_replace(&room_id, &pdu.event_id); - // The new value will need a new index. We store the last used index in 'n' + id - let mut count_key: Vec = vec![b'n']; - count_key.extend_from_slice(&room_id.to_string().as_bytes()); + // The new value will need a new index. We store the last used index in 'n' + // The count will go up regardless of the room_id + // This is also the next_batch/since value + let count_key: Vec = vec![b'n']; // Increment the last index and use that let index = utils::u64_from_bytes( @@ -225,7 +249,7 @@ impl Data { pdu_id.extend_from_slice(room_id.to_string().as_bytes()); pdu_id.push(b'#'); // Add delimiter so we don't find rooms starting with the same id - pdu_id.extend_from_slice(index.to_string().as_bytes()); + pdu_id.extend_from_slice(&index.to_be_bytes()); self.db .pduid_pdus @@ -240,37 +264,30 @@ impl Data { pdu.event_id } - /// Returns a vector of all PDUs. - pub fn pdus_all(&self) -> Vec { - self.pdus_since( - self.db - .eventid_pduid - .iter() - .values() - .next() - .unwrap() - .map(|key| utils::string_from_bytes(&key)) - .expect("there should be at least one pdu"), - ) + /// Returns a vector of all PDUs in a room. + pub fn pdus_all(&self, room_id: &RoomId) -> Vec { + self.pdus_since(room_id, "".to_owned()) } - /// Returns a vector of all events that happened after the event with id `since`. - pub fn pdus_since(&self, since: String) -> Vec { + /// Returns a vector of all events in a room that happened after the event with id `since`. + pub fn pdus_since(&self, room_id: &RoomId, since: String) -> Vec { let mut pdus = Vec::new(); - if let Some(room_id) = since.rsplitn(2, '#').nth(1) { - let mut current = since.clone(); + // Create the first part of the full pdu id + let mut pdu_id = vec![b'd']; + pdu_id.extend_from_slice(room_id.to_string().as_bytes()); + pdu_id.push(b'#'); // Add delimiter so we don't find rooms starting with the same id - while let Some((key, value)) = self.db.pduid_pdus.get_gt(current).unwrap() { - if key.starts_with(&room_id.to_string().as_bytes()) { - current = utils::string_from_bytes(&key); - } else { - break; - } - pdus.push(serde_json::from_slice(&value).expect("pdu is valid")); + let mut current = pdu_id.clone(); + current.extend_from_slice(since.as_bytes()); + + while let Some((key, value)) = self.db.pduid_pdus.get_gt(¤t).unwrap() { + if key.starts_with(&pdu_id) { + current = key.to_vec(); + pdus.push(serde_json::from_slice(&value).expect("pdu in db is valid")); + } else { + break; } - } else { - debug!("event at `since` not found"); } pdus } diff --git a/src/database.rs b/src/database.rs index b08dd3ce..dee2e944 100644 --- a/src/database.rs +++ b/src/database.rs @@ -55,8 +55,10 @@ pub struct Database { pub deviceid_token: sled::Tree, pub token_userid: sled::Tree, pub pduid_pdus: sled::Tree, - pub roomid_pduleaves: MultiValue, pub eventid_pduid: sled::Tree, + pub roomid_pduleaves: MultiValue, + pub roomid_userids: MultiValue, + pub userid_roomids: MultiValue, _db: sled::Db, } @@ -76,8 +78,10 @@ impl Database { deviceid_token: db.open_tree("deviceid_token").unwrap(), token_userid: db.open_tree("token_userid").unwrap(), pduid_pdus: db.open_tree("pduid_pdus").unwrap(), - roomid_pduleaves: MultiValue(db.open_tree("roomid_pduleaves").unwrap()), eventid_pduid: db.open_tree("eventid_pduid").unwrap(), + roomid_pduleaves: MultiValue(db.open_tree("roomid_pduleaves").unwrap()), + roomid_userids: MultiValue(db.open_tree("roomid_userids").unwrap()), + userid_roomids: MultiValue(db.open_tree("userid_roomids").unwrap()), _db: db, } } @@ -86,7 +90,7 @@ impl Database { println!("# UserId -> Password:"); for (k, v) in self.userid_password.iter().map(|r| r.unwrap()) { println!( - "{} -> {}", + "{:?} -> {:?}", String::from_utf8_lossy(&k), String::from_utf8_lossy(&v), ); @@ -94,7 +98,7 @@ impl Database { println!("\n# UserId -> DeviceIds:"); for (k, v) in self.userid_deviceids.iter_all().map(|r| r.unwrap()) { println!( - "{} -> {}", + "{:?} -> {:?}", String::from_utf8_lossy(&k), String::from_utf8_lossy(&v), ); @@ -102,7 +106,7 @@ impl Database { println!("\n# DeviceId -> Token:"); for (k, v) in self.deviceid_token.iter().map(|r| r.unwrap()) { println!( - "{} -> {}", + "{:?} -> {:?}", String::from_utf8_lossy(&k), String::from_utf8_lossy(&v), ); @@ -110,7 +114,7 @@ impl Database { println!("\n# Token -> UserId:"); for (k, v) in self.token_userid.iter().map(|r| r.unwrap()) { println!( - "{} -> {}", + "{:?} -> {:?}", String::from_utf8_lossy(&k), String::from_utf8_lossy(&v), ); @@ -118,7 +122,23 @@ impl Database { println!("\n# RoomId -> PDU leaves:"); for (k, v) in self.roomid_pduleaves.iter_all().map(|r| r.unwrap()) { println!( - "{} -> {}", + "{:?} -> {:?}", + String::from_utf8_lossy(&k), + String::from_utf8_lossy(&v), + ); + } + println!("\n# RoomId -> UserIds:"); + for (k, v) in self.roomid_userids.iter_all().map(|r| r.unwrap()) { + println!( + "{:?} -> {:?}", + String::from_utf8_lossy(&k), + String::from_utf8_lossy(&v), + ); + } + println!("\n# UserId -> RoomIds:"); + for (k, v) in self.userid_roomids.iter_all().map(|r| r.unwrap()) { + println!( + "{:?} -> {:?}", String::from_utf8_lossy(&k), String::from_utf8_lossy(&v), ); @@ -126,7 +146,7 @@ impl Database { println!("\n# PDU Id -> PDUs:"); for (k, v) in self.pduid_pdus.iter().map(|r| r.unwrap()) { println!( - "{} -> {}", + "{:?} -> {:?}", String::from_utf8_lossy(&k), String::from_utf8_lossy(&v), ); @@ -134,7 +154,7 @@ impl Database { println!("\n# EventId -> PDU Id:"); for (k, v) in self.eventid_pduid.iter().map(|r| r.unwrap()) { println!( - "{} -> {}", + "{:?} -> {:?}", String::from_utf8_lossy(&k), String::from_utf8_lossy(&v), ); diff --git a/src/main.rs b/src/main.rs index 5a8c066b..a5049306 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,14 +15,16 @@ use ruma_client_api::{ error::{Error, ErrorKind}, r0::{ account::register, alias::get_alias, membership::join_room_by_id, - message::create_message_event, session::login, sync::sync_events, + message::create_message_event, room::create_room, session::login, sync::sync_events, }, unversioned::get_supported_versions, }; -use ruma_events::{collections::all::RoomEvent, room::message::MessageEvent, EventResult}; -use ruma_identifiers::{EventId, UserId}; +use ruma_events::{ + collections::all::RoomEvent, room::message::MessageEvent, EventResult, EventType, +}; +use ruma_identifiers::{EventId, RoomId, UserId}; use ruma_wrapper::{MatrixResult, Ruma}; -use serde_json::map::Map; +use serde_json::{json, map::Map}; use std::{ collections::HashMap, convert::{TryFrom, TryInto}, @@ -168,6 +170,29 @@ fn login_route(data: State, body: Ruma) -> MatrixResult, + body: Ruma, +) -> MatrixResult { + // TODO: check if room is unique + let room_id = RoomId::new(data.hostname()).expect("host is valid"); + + data.room_join( + &room_id, + body.user_id.as_ref().expect("user is authenticated"), + ); + + data.pdu_append( + room_id.clone(), + body.user_id.clone().expect("user is authenticated"), + EventType::RoomMessage, + json!({"msgtype": "m.text", "body": "Hello"}), + ); + + MatrixResult(Ok(create_room::Response { room_id })) +} + #[get("/_matrix/client/r0/directory/room/")] fn get_alias_route(room_alias: String) -> MatrixResult { // TODO @@ -193,10 +218,14 @@ fn get_alias_route(room_alias: String) -> MatrixResult { #[post("/_matrix/client/r0/rooms/<_room_id>/join", data = "")] fn join_room_by_id_route( - _room_id: String, + data: State, body: Ruma, + _room_id: String, ) -> MatrixResult { - // TODO + data.room_join( + &body.room_id, + body.user_id.as_ref().expect("user is authenticated"), + ); MatrixResult(Ok(join_room_by_id::Response { room_id: body.room_id.clone(), })) @@ -213,37 +242,28 @@ fn create_message_event_route( _txn_id: String, body: Ruma, ) -> MatrixResult { - if let Ok(content) = body.data.clone().into_result() { - let event_id = data.pdu_append( - body.room_id.clone(), - body.user_id.clone().expect("user is authenticated"), - body.event_type.clone(), - content, - ); - MatrixResult(Ok(create_message_event::Response { event_id })) - } else { - error!("No data found"); - MatrixResult(Err(Error { - kind: ErrorKind::NotFound, - message: "Room not found.".to_owned(), - status_code: http::StatusCode::NOT_FOUND, - })) - } + let event_id = data.pdu_append( + body.room_id.clone(), + body.user_id.clone().expect("user is authenticated"), + body.event_type.clone(), + body.json_body, + ); + MatrixResult(Ok(create_message_event::Response { event_id })) } -#[get("/_matrix/client/r0/sync", data = "<_body>")] +#[get("/_matrix/client/r0/sync", data = "")] fn sync_route( data: State, - _body: Ruma, + body: Ruma, ) -> MatrixResult { let mut joined_rooms = HashMap::new(); - { - let pdus = data.pdus_all(); - let mut room_events = Vec::new(); - - for pdu in pdus { - room_events.push(pdu.to_room_event()); - } + let joined_roomids = data.rooms_joined(body.user_id.as_ref().expect("user is authenticated")); + for room_id in joined_roomids { + let room_events = data + .pdus_all(&room_id) + .into_iter() + .map(|pdu| pdu.to_room_event()) + .collect(); joined_rooms.insert( "!roomid:localhost".try_into().unwrap(), @@ -309,6 +329,7 @@ fn main() { get_supported_versions_route, register_route, login_route, + create_room_route, get_alias_route, join_room_by_id_route, create_message_event_route,