2020-04-04 09:53:37 +00:00
|
|
|
use crate::{utils, Database, PduEvent};
|
2020-04-23 12:27:50 +00:00
|
|
|
use ruma_events::{collections::only::Event as EduEvent, EventJson, EventType};
|
2020-04-03 15:27:08 +00:00
|
|
|
use ruma_federation_api::RoomV3Pdu;
|
2020-03-29 22:10:15 +00:00
|
|
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
2020-04-11 18:03:22 +00:00
|
|
|
use serde_json::json;
|
2020-04-04 09:53:37 +00:00
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
convert::{TryFrom, TryInto},
|
|
|
|
};
|
2020-03-29 19:05:20 +00:00
|
|
|
|
2020-03-30 11:46:18 +00:00
|
|
|
pub struct Data {
|
|
|
|
hostname: String,
|
2020-04-19 12:14:47 +00:00
|
|
|
reqwest_client: reqwest::Client,
|
2020-03-30 11:46:18 +00:00
|
|
|
db: Database,
|
|
|
|
}
|
2020-03-28 17:50:02 +00:00
|
|
|
|
|
|
|
impl Data {
|
2020-03-29 19:05:20 +00:00
|
|
|
/// Load an existing database or create a new one.
|
2020-03-30 11:46:18 +00:00
|
|
|
pub fn load_or_create(hostname: &str) -> Self {
|
2020-04-19 12:14:47 +00:00
|
|
|
let db = Database::load_or_create(hostname);
|
2020-03-30 11:46:18 +00:00
|
|
|
Self {
|
|
|
|
hostname: hostname.to_owned(),
|
2020-04-19 12:14:47 +00:00
|
|
|
reqwest_client: reqwest::Client::new(),
|
|
|
|
db,
|
2020-03-30 11:46:18 +00:00
|
|
|
}
|
2020-03-29 19:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the hostname of the server.
|
2020-03-30 11:46:18 +00:00
|
|
|
pub fn hostname(&self) -> &str {
|
|
|
|
&self.hostname
|
2020-03-29 19:05:20 +00:00
|
|
|
}
|
|
|
|
|
2020-04-19 12:14:47 +00:00
|
|
|
/// Get the hostname of the server.
|
|
|
|
pub fn reqwest_client(&self) -> &reqwest::Client {
|
|
|
|
&self.reqwest_client
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn keypair(&self) -> &ruma_signatures::Ed25519KeyPair {
|
|
|
|
&self.db.keypair
|
|
|
|
}
|
|
|
|
|
2020-03-29 19:05:20 +00:00
|
|
|
/// Check if a user has an account by looking for an assigned password.
|
2020-03-28 17:50:02 +00:00
|
|
|
pub fn user_exists(&self, user_id: &UserId) -> bool {
|
2020-03-30 11:46:18 +00:00
|
|
|
self.db
|
|
|
|
.userid_password
|
2020-03-28 17:50:02 +00:00
|
|
|
.contains_key(user_id.to_string())
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
2020-03-29 19:05:20 +00:00
|
|
|
/// Create a new user account by assigning them a password.
|
2020-04-14 20:25:44 +00:00
|
|
|
pub fn user_add(&self, user_id: &UserId, hash: &str) {
|
2020-03-30 11:46:18 +00:00
|
|
|
self.db
|
|
|
|
.userid_password
|
2020-04-14 20:25:44 +00:00
|
|
|
.insert(user_id.to_string(), hash)
|
2020-03-28 17:50:02 +00:00
|
|
|
.unwrap();
|
|
|
|
}
|
2020-03-29 11:48:44 +00:00
|
|
|
|
2020-03-29 19:05:20 +00:00
|
|
|
/// Find out which user an access token belongs to.
|
|
|
|
pub fn user_from_token(&self, token: &str) -> Option<UserId> {
|
2020-03-30 11:46:18 +00:00
|
|
|
self.db
|
|
|
|
.token_userid
|
2020-03-29 19:05:20 +00:00
|
|
|
.get(token)
|
|
|
|
.unwrap()
|
2020-03-30 11:46:18 +00:00
|
|
|
.and_then(|bytes| (*utils::string_from_bytes(&bytes)).try_into().ok())
|
2020-03-29 19:05:20 +00:00
|
|
|
}
|
|
|
|
|
2020-04-14 11:54:32 +00:00
|
|
|
pub fn users_all(&self) -> Vec<UserId> {
|
|
|
|
self.db
|
|
|
|
.userid_password
|
|
|
|
.iter()
|
|
|
|
.keys()
|
|
|
|
.map(|k| UserId::try_from(&*utils::string_from_bytes(&k.unwrap())).unwrap())
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2020-04-14 20:25:44 +00:00
|
|
|
/// Gets password hash for given user id.
|
|
|
|
pub fn password_hash_get(&self, user_id: &UserId) -> Option<String> {
|
2020-03-30 11:46:18 +00:00
|
|
|
self.db
|
|
|
|
.userid_password
|
2020-03-29 19:05:20 +00:00
|
|
|
.get(user_id.to_string())
|
|
|
|
.unwrap()
|
2020-03-30 11:46:18 +00:00
|
|
|
.map(|bytes| utils::string_from_bytes(&bytes))
|
2020-03-29 19:05:20 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:47:03 +00:00
|
|
|
/// Removes a displayname.
|
|
|
|
pub fn displayname_remove(&self, user_id: &UserId) {
|
2020-04-09 19:21:28 +00:00
|
|
|
self.db
|
|
|
|
.userid_displayname
|
|
|
|
.remove(user_id.to_string())
|
|
|
|
.unwrap();
|
2020-04-09 18:47:03 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 16:49:27 +00:00
|
|
|
/// Set a new displayname.
|
2020-04-26 20:39:15 +00:00
|
|
|
pub fn displayname_set(&self, user_id: &UserId, displayname: String) {
|
2020-04-09 16:49:27 +00:00
|
|
|
self.db
|
2020-04-09 18:47:03 +00:00
|
|
|
.userid_displayname
|
2020-04-26 20:39:15 +00:00
|
|
|
.insert(user_id.to_string(), &*displayname)
|
2020-04-09 16:49:27 +00:00
|
|
|
.unwrap();
|
2020-04-26 20:39:15 +00:00
|
|
|
for room_id in self.rooms_joined(user_id) {
|
|
|
|
self.pdu_append(
|
|
|
|
room_id.clone(),
|
|
|
|
user_id.clone(),
|
|
|
|
EventType::RoomMember,
|
|
|
|
json!({"membership": "join", "displayname": displayname}),
|
|
|
|
None,
|
|
|
|
Some(user_id.to_string()),
|
|
|
|
);
|
|
|
|
}
|
2020-04-09 16:49:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a the displayname of a user.
|
|
|
|
pub fn displayname_get(&self, user_id: &UserId) -> Option<String> {
|
|
|
|
self.db
|
2020-04-09 18:47:03 +00:00
|
|
|
.userid_displayname
|
2020-04-09 16:49:27 +00:00
|
|
|
.get(user_id.to_string())
|
|
|
|
.unwrap()
|
|
|
|
.map(|bytes| utils::string_from_bytes(&bytes))
|
|
|
|
}
|
|
|
|
|
2020-04-09 18:47:03 +00:00
|
|
|
/// Removes a avatar_url.
|
|
|
|
pub fn avatar_url_remove(&self, user_id: &UserId) {
|
2020-04-09 19:21:28 +00:00
|
|
|
self.db
|
|
|
|
.userid_avatarurl
|
|
|
|
.remove(user_id.to_string())
|
|
|
|
.unwrap();
|
2020-04-09 18:47:03 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 16:49:27 +00:00
|
|
|
/// Set a new avatar_url.
|
|
|
|
pub fn avatar_url_set(&self, user_id: &UserId, avatar_url: String) {
|
|
|
|
self.db
|
2020-04-09 19:01:39 +00:00
|
|
|
.userid_avatarurl
|
2020-04-09 16:49:27 +00:00
|
|
|
.insert(user_id.to_string(), &*avatar_url)
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a the avatar_url of a user.
|
|
|
|
pub fn avatar_url_get(&self, user_id: &UserId) -> Option<String> {
|
|
|
|
self.db
|
2020-04-09 19:01:39 +00:00
|
|
|
.userid_avatarurl
|
2020-04-09 16:49:27 +00:00
|
|
|
.get(user_id.to_string())
|
|
|
|
.unwrap()
|
|
|
|
.map(|bytes| utils::string_from_bytes(&bytes))
|
|
|
|
}
|
|
|
|
|
2020-03-29 19:05:20 +00:00
|
|
|
/// Add a new device to a user.
|
|
|
|
pub fn device_add(&self, user_id: &UserId, device_id: &str) {
|
2020-03-30 11:46:18 +00:00
|
|
|
if self
|
|
|
|
.db
|
|
|
|
.userid_deviceids
|
|
|
|
.get_iter(&user_id.to_string().as_bytes())
|
|
|
|
.filter_map(|item| item.ok())
|
|
|
|
.map(|(_key, value)| value)
|
|
|
|
.all(|device| device != device_id)
|
|
|
|
{
|
|
|
|
self.db
|
|
|
|
.userid_deviceids
|
|
|
|
.add(user_id.to_string().as_bytes(), device_id.into());
|
|
|
|
}
|
2020-03-29 19:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Replace the access token of one device.
|
|
|
|
pub fn token_replace(&self, user_id: &UserId, device_id: &String, token: String) {
|
|
|
|
// Make sure the device id belongs to the user
|
|
|
|
debug_assert!(self
|
2020-03-30 11:46:18 +00:00
|
|
|
.db
|
|
|
|
.userid_deviceids
|
|
|
|
.get_iter(&user_id.to_string().as_bytes())
|
|
|
|
.filter_map(|item| item.ok())
|
|
|
|
.map(|(_key, value)| value)
|
|
|
|
.any(|device| device == device_id.as_bytes())); // Does the user have that device?
|
2020-03-29 19:05:20 +00:00
|
|
|
|
|
|
|
// Remove old token
|
2020-04-14 11:54:32 +00:00
|
|
|
let mut key = user_id.to_string().as_bytes().to_vec();
|
|
|
|
key.push(0xff);
|
|
|
|
key.extend_from_slice(device_id.as_bytes());
|
|
|
|
if let Some(old_token) = self.db.userdeviceid_token.get(&key).unwrap() {
|
2020-03-30 11:46:18 +00:00
|
|
|
self.db.token_userid.remove(old_token).unwrap();
|
|
|
|
// It will be removed from deviceid_token by the insert later
|
2020-03-29 19:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Assign token to device_id
|
2020-04-14 11:54:32 +00:00
|
|
|
self.db.userdeviceid_token.insert(key, &*token).unwrap();
|
2020-03-29 19:05:20 +00:00
|
|
|
|
|
|
|
// Assign token to user
|
2020-03-30 11:46:18 +00:00
|
|
|
self.db
|
|
|
|
.token_userid
|
2020-03-29 19:05:20 +00:00
|
|
|
.insert(token, &*user_id.to_string())
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
2020-04-08 13:05:00 +00:00
|
|
|
pub fn room_join(&self, room_id: &RoomId, user_id: &UserId) -> bool {
|
|
|
|
if !self.room_exists(room_id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-04-06 11:46:46 +00:00
|
|
|
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(),
|
|
|
|
);
|
2020-04-14 11:54:32 +00:00
|
|
|
self.db.userid_inviteroomids.remove_value(
|
|
|
|
user_id.to_string().as_bytes(),
|
|
|
|
room_id.to_string().as_bytes(),
|
|
|
|
);
|
2020-04-19 12:14:47 +00:00
|
|
|
self.db.userid_leftroomids.remove_value(
|
|
|
|
user_id.to_string().as_bytes(),
|
|
|
|
room_id.to_string().as_bytes().into(),
|
|
|
|
);
|
2020-04-08 13:05:00 +00:00
|
|
|
|
2020-04-26 20:39:15 +00:00
|
|
|
let mut content = json!({"membership": "join"});
|
|
|
|
if let Some(displayname) = self.displayname_get(user_id) {
|
|
|
|
content
|
|
|
|
.as_object_mut()
|
|
|
|
.unwrap()
|
|
|
|
.insert("displayname".to_owned(), displayname.into());
|
|
|
|
}
|
|
|
|
|
2020-04-11 18:03:22 +00:00
|
|
|
self.pdu_append(
|
|
|
|
room_id.clone(),
|
|
|
|
user_id.clone(),
|
|
|
|
EventType::RoomMember,
|
2020-04-26 20:39:15 +00:00
|
|
|
content,
|
2020-04-11 18:03:22 +00:00
|
|
|
None,
|
|
|
|
Some(user_id.to_string()),
|
|
|
|
);
|
|
|
|
|
2020-04-08 13:05:00 +00:00
|
|
|
true
|
2020-04-06 11:46:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn rooms_joined(&self, user_id: &UserId) -> Vec<RoomId> {
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2020-04-08 13:05:00 +00:00
|
|
|
/// Check if a room exists by looking for PDUs in that room.
|
|
|
|
pub fn room_exists(&self, room_id: &RoomId) -> bool {
|
|
|
|
// Create the first part of the full pdu id
|
|
|
|
let mut prefix = vec![b'd'];
|
|
|
|
prefix.extend_from_slice(room_id.to_string().as_bytes());
|
2020-04-11 18:03:22 +00:00
|
|
|
prefix.push(0xff); // Add delimiter so we don't find rooms starting with the same id
|
2020-04-08 13:05:00 +00:00
|
|
|
|
2020-04-11 07:35:06 +00:00
|
|
|
if let Some((key, _)) = self.db.pduid_pdu.get_gt(&prefix).unwrap() {
|
2020-04-08 13:05:00 +00:00
|
|
|
if key.starts_with(&prefix) {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-09 10:22:39 +00:00
|
|
|
pub fn rooms_all(&self) -> Vec<RoomId> {
|
|
|
|
let mut room_ids = self
|
|
|
|
.db
|
|
|
|
.roomid_pduleaves
|
|
|
|
.iter_all()
|
|
|
|
.keys()
|
|
|
|
.map(|key| {
|
2020-04-09 12:39:50 +00:00
|
|
|
RoomId::try_from(&*utils::string_from_bytes(
|
2020-04-09 10:22:39 +00:00
|
|
|
&key.unwrap()
|
|
|
|
.iter()
|
2020-04-09 12:39:50 +00:00
|
|
|
.skip(1) // skip "d"
|
2020-04-09 10:22:39 +00:00
|
|
|
.copied()
|
2020-04-09 12:39:50 +00:00
|
|
|
.take_while(|&x| x != 0xff) // until delimiter
|
2020-04-09 10:22:39 +00:00
|
|
|
.collect::<Vec<_>>(),
|
2020-04-09 12:39:50 +00:00
|
|
|
))
|
2020-04-09 10:22:39 +00:00
|
|
|
.unwrap()
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
room_ids.dedup();
|
|
|
|
room_ids
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn room_users(&self, room_id: &RoomId) -> u32 {
|
|
|
|
self.db
|
|
|
|
.roomid_userids
|
|
|
|
.get_iter(room_id.to_string().as_bytes())
|
|
|
|
.count() as u32
|
|
|
|
}
|
|
|
|
|
2020-04-14 11:54:32 +00:00
|
|
|
pub fn room_state(&self, room_id: &RoomId) -> HashMap<(EventType, String), PduEvent> {
|
|
|
|
let mut hashmap = HashMap::new();
|
|
|
|
for pdu in self
|
|
|
|
.db
|
|
|
|
.roomstateid_pdu
|
|
|
|
.scan_prefix(&room_id.to_string().as_bytes())
|
|
|
|
.values()
|
|
|
|
.map(|value| serde_json::from_slice::<PduEvent>(&value.unwrap()).unwrap())
|
|
|
|
{
|
|
|
|
hashmap.insert(
|
|
|
|
(
|
|
|
|
pdu.kind.clone(),
|
|
|
|
pdu.state_key
|
|
|
|
.clone()
|
|
|
|
.expect("state events have a state key"),
|
|
|
|
),
|
|
|
|
pdu,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
hashmap
|
|
|
|
}
|
|
|
|
|
2020-04-19 12:14:47 +00:00
|
|
|
pub fn room_leave(&self, sender: &UserId, room_id: &RoomId, user_id: &UserId) {
|
|
|
|
self.pdu_append(
|
|
|
|
room_id.clone(),
|
|
|
|
sender.clone(),
|
|
|
|
EventType::RoomMember,
|
|
|
|
json!({"membership": "leave"}),
|
|
|
|
None,
|
|
|
|
Some(user_id.to_string()),
|
|
|
|
);
|
|
|
|
self.db.userid_inviteroomids.remove_value(
|
|
|
|
user_id.to_string().as_bytes(),
|
|
|
|
room_id.to_string().as_bytes().into(),
|
|
|
|
);
|
|
|
|
self.db.userid_roomids.remove_value(
|
|
|
|
user_id.to_string().as_bytes(),
|
|
|
|
room_id.to_string().as_bytes().into(),
|
|
|
|
);
|
|
|
|
self.db.roomid_userids.remove_value(
|
|
|
|
room_id.to_string().as_bytes(),
|
|
|
|
user_id.to_string().as_bytes().into(),
|
|
|
|
);
|
|
|
|
self.db.userid_leftroomids.add(
|
|
|
|
user_id.to_string().as_bytes(),
|
|
|
|
room_id.to_string().as_bytes().into(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-04-14 11:54:32 +00:00
|
|
|
pub fn room_invite(&self, sender: &UserId, room_id: &RoomId, user_id: &UserId) {
|
|
|
|
self.pdu_append(
|
|
|
|
room_id.clone(),
|
|
|
|
sender.clone(),
|
|
|
|
EventType::RoomMember,
|
|
|
|
json!({"membership": "invite"}),
|
|
|
|
None,
|
|
|
|
Some(user_id.to_string()),
|
|
|
|
);
|
|
|
|
self.db.userid_inviteroomids.add(
|
2020-04-19 12:14:47 +00:00
|
|
|
user_id.to_string().as_bytes(),
|
2020-04-14 11:54:32 +00:00
|
|
|
room_id.to_string().as_bytes().into(),
|
|
|
|
);
|
2020-04-19 12:14:47 +00:00
|
|
|
self.db.roomid_userids.add(
|
|
|
|
room_id.to_string().as_bytes(),
|
|
|
|
user_id.to_string().as_bytes().into(),
|
|
|
|
);
|
2020-04-14 11:54:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn rooms_invited(&self, user_id: &UserId) -> Vec<RoomId> {
|
|
|
|
self.db
|
|
|
|
.userid_inviteroomids
|
|
|
|
.get_iter(&user_id.to_string().as_bytes())
|
|
|
|
.values()
|
|
|
|
.map(|key| RoomId::try_from(&*utils::string_from_bytes(&key.unwrap())).unwrap())
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2020-04-19 12:14:47 +00:00
|
|
|
pub fn rooms_left(&self, user_id: &UserId) -> Vec<RoomId> {
|
|
|
|
self.db
|
|
|
|
.userid_leftroomids
|
|
|
|
.get_iter(&user_id.to_string().as_bytes())
|
|
|
|
.values()
|
|
|
|
.map(|key| RoomId::try_from(&*utils::string_from_bytes(&key.unwrap())).unwrap())
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2020-04-03 15:27:08 +00:00
|
|
|
pub fn pdu_get(&self, event_id: &EventId) -> Option<RoomV3Pdu> {
|
2020-03-30 11:46:18 +00:00
|
|
|
self.db
|
2020-04-03 15:27:08 +00:00
|
|
|
.eventid_pduid
|
|
|
|
.get(event_id.to_string().as_bytes())
|
|
|
|
.unwrap()
|
|
|
|
.map(|pdu_id| {
|
|
|
|
serde_json::from_slice(
|
|
|
|
&self
|
|
|
|
.db
|
2020-04-11 07:35:06 +00:00
|
|
|
.pduid_pdu
|
2020-04-03 15:27:08 +00:00
|
|
|
.get(pdu_id)
|
|
|
|
.unwrap()
|
|
|
|
.expect("eventid_pduid in db is valid"),
|
|
|
|
)
|
|
|
|
.expect("pdu is valid")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-04-05 21:06:43 +00:00
|
|
|
pub fn pdu_leaves_get(&self, room_id: &RoomId) -> Vec<EventId> {
|
2020-04-03 15:27:08 +00:00
|
|
|
let event_ids = self
|
|
|
|
.db
|
|
|
|
.roomid_pduleaves
|
|
|
|
.get_iter(room_id.to_string().as_bytes())
|
|
|
|
.values()
|
|
|
|
.map(|pdu_id| {
|
|
|
|
EventId::try_from(&*utils::string_from_bytes(&pdu_id.unwrap()))
|
|
|
|
.expect("pdu leaves are valid event ids")
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2020-04-05 21:06:43 +00:00
|
|
|
event_ids
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn pdu_leaves_replace(&self, room_id: &RoomId, event_id: &EventId) {
|
2020-04-03 15:27:08 +00:00
|
|
|
self.db
|
|
|
|
.roomid_pduleaves
|
|
|
|
.clear(room_id.to_string().as_bytes());
|
|
|
|
|
|
|
|
self.db.roomid_pduleaves.add(
|
|
|
|
&room_id.to_string().as_bytes(),
|
|
|
|
(*event_id.to_string()).into(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add a persisted data unit from this homeserver
|
2020-04-05 21:06:43 +00:00
|
|
|
pub fn pdu_append(
|
|
|
|
&self,
|
|
|
|
room_id: RoomId,
|
|
|
|
sender: UserId,
|
|
|
|
event_type: EventType,
|
2020-04-06 11:46:46 +00:00
|
|
|
content: serde_json::Value,
|
2020-04-08 13:05:00 +00:00
|
|
|
unsigned: Option<serde_json::Map<String, serde_json::Value>>,
|
2020-04-06 12:33:02 +00:00
|
|
|
state_key: Option<String>,
|
2020-04-05 21:06:43 +00:00
|
|
|
) -> EventId {
|
2020-04-03 15:27:08 +00:00
|
|
|
// prev_events are the leaves of the current graph. This method removes all leaves from the
|
|
|
|
// room and replaces them with our event
|
2020-04-05 21:06:43 +00:00
|
|
|
// TODO: Make sure this isn't called twice in parallel
|
|
|
|
let prev_events = self.pdu_leaves_get(&room_id);
|
2020-04-03 15:27:08 +00:00
|
|
|
|
|
|
|
// Our depth is the maximum depth of prev_events + 1
|
|
|
|
let depth = prev_events
|
|
|
|
.iter()
|
|
|
|
.map(|event_id| {
|
|
|
|
self.pdu_get(event_id)
|
|
|
|
.expect("pdu in prev_events is valid")
|
|
|
|
.depth
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
.max()
|
|
|
|
.unwrap_or(0_u64)
|
|
|
|
+ 1;
|
|
|
|
|
2020-04-26 20:39:15 +00:00
|
|
|
let mut unsigned = unsigned.unwrap_or_default();
|
|
|
|
// TODO: Optimize this to not load the whole room state?
|
|
|
|
if let Some(state_key) = &state_key {
|
|
|
|
if let Some(prev_pdu) = self
|
|
|
|
.room_state(&room_id)
|
|
|
|
.get(&(event_type.clone(), state_key.clone()))
|
|
|
|
{
|
|
|
|
unsigned.insert("prev_content".to_owned(), prev_pdu.content.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-05 21:06:43 +00:00
|
|
|
let mut pdu = PduEvent {
|
|
|
|
event_id: EventId::try_from("$thiswillbefilledinlater").unwrap(),
|
2020-04-04 09:53:37 +00:00
|
|
|
room_id: room_id.clone(),
|
2020-04-05 21:06:43 +00:00
|
|
|
sender: sender.clone(),
|
2020-04-04 09:53:37 +00:00
|
|
|
origin: self.hostname.clone(),
|
2020-04-12 19:12:50 +00:00
|
|
|
origin_server_ts: utils::millis_since_unix_epoch().try_into().unwrap(),
|
2020-04-05 21:06:43 +00:00
|
|
|
kind: event_type,
|
2020-04-06 11:46:46 +00:00
|
|
|
content,
|
2020-04-06 12:33:02 +00:00
|
|
|
state_key,
|
2020-04-04 09:53:37 +00:00
|
|
|
prev_events,
|
|
|
|
depth: depth.try_into().unwrap(),
|
|
|
|
auth_events: Vec::new(),
|
|
|
|
redacts: None,
|
2020-04-26 20:39:15 +00:00
|
|
|
unsigned,
|
2020-04-04 09:53:37 +00:00
|
|
|
hashes: ruma_federation_api::EventHash {
|
|
|
|
sha256: "aaa".to_owned(),
|
|
|
|
},
|
|
|
|
signatures: HashMap::new(),
|
|
|
|
};
|
2020-04-03 15:27:08 +00:00
|
|
|
|
2020-04-05 21:06:43 +00:00
|
|
|
// Generate event id
|
|
|
|
pdu.event_id = EventId::try_from(&*format!(
|
|
|
|
"${}",
|
|
|
|
ruma_signatures::reference_hash(&serde_json::to_value(&pdu).unwrap())
|
|
|
|
.expect("ruma can calculate reference hashes")
|
|
|
|
))
|
|
|
|
.expect("ruma's reference hashes are correct");
|
|
|
|
|
2020-04-22 09:53:06 +00:00
|
|
|
let mut pdu_json = serde_json::to_value(&pdu).unwrap();
|
2020-04-25 09:47:32 +00:00
|
|
|
ruma_signatures::hash_and_sign_event(self.hostname(), self.keypair(), &mut pdu_json)
|
|
|
|
.unwrap();
|
2020-04-06 12:53:34 +00:00
|
|
|
|
2020-04-05 21:06:43 +00:00
|
|
|
self.pdu_leaves_replace(&room_id, &pdu.event_id);
|
|
|
|
|
2020-04-06 11:46:46 +00:00
|
|
|
// 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
|
2020-04-03 15:27:08 +00:00
|
|
|
// Increment the last index and use that
|
|
|
|
let index = utils::u64_from_bytes(
|
|
|
|
&self
|
|
|
|
.db
|
2020-04-11 07:35:06 +00:00
|
|
|
.pduid_pdu
|
2020-04-11 18:03:22 +00:00
|
|
|
.update_and_fetch(b"n", utils::increment)
|
2020-04-03 15:27:08 +00:00
|
|
|
.unwrap()
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut pdu_id = vec![b'd'];
|
|
|
|
pdu_id.extend_from_slice(room_id.to_string().as_bytes());
|
|
|
|
|
2020-04-11 18:03:22 +00:00
|
|
|
pdu_id.push(0xff); // Add delimiter so we don't find rooms starting with the same id
|
2020-04-06 11:46:46 +00:00
|
|
|
pdu_id.extend_from_slice(&index.to_be_bytes());
|
2020-04-03 15:27:08 +00:00
|
|
|
|
2020-04-06 12:53:34 +00:00
|
|
|
self.db
|
|
|
|
.pduid_pdu
|
2020-04-22 09:53:06 +00:00
|
|
|
.insert(&pdu_id, &*pdu_json.to_string())
|
2020-04-06 12:53:34 +00:00
|
|
|
.unwrap();
|
2020-04-03 15:27:08 +00:00
|
|
|
|
|
|
|
self.db
|
|
|
|
.eventid_pduid
|
2020-04-05 21:06:43 +00:00
|
|
|
.insert(pdu.event_id.to_string(), pdu_id.clone())
|
2020-04-03 15:27:08 +00:00
|
|
|
.unwrap();
|
2020-04-05 21:06:43 +00:00
|
|
|
|
2020-04-14 11:54:32 +00:00
|
|
|
if let Some(state_key) = pdu.state_key {
|
|
|
|
let mut key = room_id.to_string().as_bytes().to_vec();
|
|
|
|
key.push(0xff);
|
2020-04-19 12:14:47 +00:00
|
|
|
key.extend_from_slice(pdu.kind.to_string().as_bytes());
|
2020-04-14 11:54:32 +00:00
|
|
|
key.push(0xff);
|
|
|
|
key.extend_from_slice(state_key.to_string().as_bytes());
|
2020-04-22 09:53:06 +00:00
|
|
|
self.db
|
|
|
|
.roomstateid_pdu
|
|
|
|
.insert(key, &*pdu_json.to_string())
|
|
|
|
.unwrap();
|
2020-04-14 11:54:32 +00:00
|
|
|
}
|
|
|
|
|
2020-04-05 21:06:43 +00:00
|
|
|
pdu.event_id
|
2020-04-03 15:27:08 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 11:46:46 +00:00
|
|
|
/// Returns a vector of all PDUs in a room.
|
|
|
|
pub fn pdus_all(&self, room_id: &RoomId) -> Vec<PduEvent> {
|
2020-04-08 13:05:00 +00:00
|
|
|
self.pdus_since(room_id, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn last_pdu_index(&self) -> u64 {
|
|
|
|
let count_key: Vec<u8> = vec![b'n'];
|
|
|
|
utils::u64_from_bytes(
|
|
|
|
&self
|
|
|
|
.db
|
2020-04-11 07:35:06 +00:00
|
|
|
.pduid_pdu
|
2020-04-08 13:05:00 +00:00
|
|
|
.get(&count_key)
|
|
|
|
.unwrap()
|
|
|
|
.unwrap_or_else(|| (&0_u64.to_be_bytes()).into()),
|
|
|
|
)
|
2020-04-03 15:27:08 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 11:46:46 +00:00
|
|
|
/// Returns a vector of all events in a room that happened after the event with id `since`.
|
2020-04-08 13:05:00 +00:00
|
|
|
pub fn pdus_since(&self, room_id: &RoomId, since: u64) -> Vec<PduEvent> {
|
2020-04-03 15:27:08 +00:00
|
|
|
let mut pdus = Vec::new();
|
|
|
|
|
2020-04-06 11:46:46 +00:00
|
|
|
// Create the first part of the full pdu id
|
2020-04-08 13:05:00 +00:00
|
|
|
let mut prefix = vec![b'd'];
|
|
|
|
prefix.extend_from_slice(room_id.to_string().as_bytes());
|
2020-04-11 18:03:22 +00:00
|
|
|
prefix.push(0xff); // Add delimiter so we don't find rooms starting with the same id
|
2020-04-06 11:46:46 +00:00
|
|
|
|
2020-04-08 13:05:00 +00:00
|
|
|
let mut current = prefix.clone();
|
|
|
|
current.extend_from_slice(&since.to_be_bytes());
|
2020-04-03 15:27:08 +00:00
|
|
|
|
2020-04-11 07:35:06 +00:00
|
|
|
while let Some((key, value)) = self.db.pduid_pdu.get_gt(¤t).unwrap() {
|
2020-04-08 13:05:00 +00:00
|
|
|
if key.starts_with(&prefix) {
|
2020-04-06 11:46:46 +00:00
|
|
|
current = key.to_vec();
|
|
|
|
pdus.push(serde_json::from_slice(&value).expect("pdu in db is valid"));
|
|
|
|
} else {
|
|
|
|
break;
|
2020-04-03 15:27:08 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-08 13:05:00 +00:00
|
|
|
|
2020-04-03 15:27:08 +00:00
|
|
|
pdus
|
2020-03-30 11:46:18 +00:00
|
|
|
}
|
|
|
|
|
2020-04-11 18:03:22 +00:00
|
|
|
pub fn roomlatest_update(&self, user_id: &UserId, room_id: &RoomId, event: EduEvent) {
|
2020-04-12 19:12:50 +00:00
|
|
|
let mut prefix = room_id.to_string().as_bytes().to_vec();
|
2020-04-11 18:03:22 +00:00
|
|
|
prefix.push(0xff);
|
|
|
|
|
|
|
|
// Start with last
|
|
|
|
if let Some(mut current) = self
|
|
|
|
.db
|
|
|
|
.roomlatestid_roomlatest
|
|
|
|
.scan_prefix(&prefix)
|
|
|
|
.keys()
|
|
|
|
.next_back()
|
|
|
|
.map(|c| c.unwrap())
|
|
|
|
{
|
|
|
|
// Remove old marker (There should at most one)
|
|
|
|
loop {
|
|
|
|
if !current.starts_with(&prefix) {
|
|
|
|
// We're in another room
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if current.rsplitn(2, |&b| b == 0xff).next().unwrap()
|
|
|
|
== user_id.to_string().as_bytes()
|
|
|
|
{
|
|
|
|
// This is the old room_latest
|
|
|
|
self.db.roomlatestid_roomlatest.remove(current).unwrap();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Else, try the event before that
|
|
|
|
if let Some((k, _)) = self.db.roomlatestid_roomlatest.get_lt(current).unwrap() {
|
|
|
|
current = k;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increment the last index and use that
|
|
|
|
let index = utils::u64_from_bytes(
|
|
|
|
&self
|
|
|
|
.db
|
|
|
|
.pduid_pdu
|
|
|
|
.update_and_fetch(b"n", utils::increment)
|
|
|
|
.unwrap()
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut room_latest_id = prefix;
|
|
|
|
room_latest_id.extend_from_slice(&index.to_be_bytes());
|
|
|
|
room_latest_id.push(0xff);
|
|
|
|
room_latest_id.extend_from_slice(&user_id.to_string().as_bytes());
|
|
|
|
|
|
|
|
self.db
|
|
|
|
.roomlatestid_roomlatest
|
|
|
|
.insert(room_latest_id, &*serde_json::to_string(&event).unwrap())
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a vector of the most recent read_receipts in a room that happened after the event with id `since`.
|
2020-04-23 12:27:50 +00:00
|
|
|
pub fn roomlatests_since(&self, room_id: &RoomId, since: u64) -> Vec<EventJson<EduEvent>> {
|
2020-04-11 18:03:22 +00:00
|
|
|
let mut room_latests = Vec::new();
|
|
|
|
|
2020-04-12 19:12:50 +00:00
|
|
|
let mut prefix = room_id.to_string().as_bytes().to_vec();
|
2020-04-11 18:03:22 +00:00
|
|
|
prefix.push(0xff);
|
|
|
|
|
|
|
|
let mut current = prefix.clone();
|
|
|
|
current.extend_from_slice(&since.to_be_bytes());
|
|
|
|
|
|
|
|
while let Some((key, value)) = self.db.roomlatestid_roomlatest.get_gt(¤t).unwrap() {
|
|
|
|
if key.starts_with(&prefix) {
|
|
|
|
current = key.to_vec();
|
|
|
|
room_latests.push(
|
2020-04-23 12:27:50 +00:00
|
|
|
serde_json::from_slice::<EventJson<EduEvent>>(&value)
|
2020-04-11 18:03:22 +00:00
|
|
|
.expect("room_latest in db is valid")
|
2020-04-23 12:27:50 +00:00
|
|
|
.deserialize()
|
|
|
|
.expect("room_latest in db is valid")
|
|
|
|
.into(),
|
2020-04-11 18:03:22 +00:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
room_latests
|
|
|
|
}
|
|
|
|
|
2020-04-12 19:12:50 +00:00
|
|
|
pub fn roomactive_add(&self, event: EduEvent, room_id: &RoomId, timeout: u64) {
|
|
|
|
let mut prefix = room_id.to_string().as_bytes().to_vec();
|
|
|
|
prefix.push(0xff);
|
|
|
|
|
|
|
|
let mut current = prefix.clone();
|
|
|
|
|
|
|
|
while let Some((key, _)) = self.db.roomactiveid_roomactive.get_gt(¤t).unwrap() {
|
|
|
|
if key.starts_with(&prefix)
|
|
|
|
&& utils::u64_from_bytes(key.split(|&c| c == 0xff).nth(1).unwrap())
|
|
|
|
> utils::millis_since_unix_epoch().try_into().unwrap()
|
|
|
|
{
|
|
|
|
current = key.to_vec();
|
|
|
|
self.db.roomactiveid_roomactive.remove(¤t).unwrap();
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increment the last index and use that
|
|
|
|
let index = utils::u64_from_bytes(
|
|
|
|
&self
|
|
|
|
.db
|
|
|
|
.pduid_pdu
|
|
|
|
.update_and_fetch(b"n", utils::increment)
|
|
|
|
.unwrap()
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut room_active_id = prefix;
|
|
|
|
room_active_id.extend_from_slice(&timeout.to_be_bytes());
|
|
|
|
room_active_id.push(0xff);
|
|
|
|
room_active_id.extend_from_slice(&index.to_be_bytes());
|
|
|
|
|
|
|
|
self.db
|
|
|
|
.roomactiveid_roomactive
|
|
|
|
.insert(room_active_id, &*serde_json::to_string(&event).unwrap())
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn roomactive_remove(&self, event: EduEvent, room_id: &RoomId) {
|
|
|
|
let mut prefix = room_id.to_string().as_bytes().to_vec();
|
|
|
|
prefix.push(0xff);
|
|
|
|
|
|
|
|
let mut current = prefix.clone();
|
|
|
|
|
|
|
|
let json = serde_json::to_string(&event).unwrap();
|
|
|
|
|
|
|
|
while let Some((key, value)) = self.db.roomactiveid_roomactive.get_gt(¤t).unwrap() {
|
|
|
|
if key.starts_with(&prefix) {
|
|
|
|
current = key.to_vec();
|
|
|
|
if value == json.as_bytes() {
|
|
|
|
self.db.roomactiveid_roomactive.remove(¤t).unwrap();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a vector of the most recent read_receipts in a room that happened after the event with id `since`.
|
2020-04-23 12:27:50 +00:00
|
|
|
pub fn roomactives_in(&self, room_id: &RoomId) -> Vec<EventJson<EduEvent>> {
|
2020-04-12 19:12:50 +00:00
|
|
|
let mut room_actives = Vec::new();
|
|
|
|
|
|
|
|
let mut prefix = room_id.to_string().as_bytes().to_vec();
|
|
|
|
prefix.push(0xff);
|
|
|
|
|
|
|
|
let mut current = prefix.clone();
|
|
|
|
current.extend_from_slice(&utils::millis_since_unix_epoch().to_be_bytes());
|
|
|
|
|
|
|
|
while let Some((key, value)) = self.db.roomactiveid_roomactive.get_gt(¤t).unwrap() {
|
|
|
|
if key.starts_with(&prefix) {
|
|
|
|
current = key.to_vec();
|
|
|
|
room_actives.push(
|
2020-04-23 12:27:50 +00:00
|
|
|
serde_json::from_slice::<EventJson<EduEvent>>(&value)
|
|
|
|
.expect("room_active in db is valid")
|
|
|
|
.deserialize()
|
2020-04-12 19:12:50 +00:00
|
|
|
.expect("room_active in db is valid")
|
2020-04-23 12:27:50 +00:00
|
|
|
.into(),
|
2020-04-12 19:12:50 +00:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if room_actives.is_empty() {
|
|
|
|
return vec![EduEvent::Typing(ruma_events::typing::TypingEvent {
|
|
|
|
content: ruma_events::typing::TypingEventContent {
|
|
|
|
user_ids: Vec::new(),
|
|
|
|
},
|
|
|
|
room_id: None, // None because it can be inferred
|
2020-04-23 12:27:50 +00:00
|
|
|
})
|
|
|
|
.into()];
|
2020-04-12 19:12:50 +00:00
|
|
|
} else {
|
|
|
|
room_actives
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-30 11:46:18 +00:00
|
|
|
pub fn debug(&self) {
|
|
|
|
self.db.debug();
|
2020-03-29 19:05:20 +00:00
|
|
|
}
|
2020-03-28 17:50:02 +00:00
|
|
|
}
|