diff --git a/src/bot.rs b/src/bot.rs index a687551..0aaf6f4 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -11,9 +11,9 @@ use matrix_sdk::Error as MatrixError; use matrix_sdk::{ self, events::{ - room::member::MemberEventContent, + room::member::{MemberEventContent, MembershipState}, room::message::{MessageEventContent, NoticeMessageEventContent, TextMessageEventContent}, - AnyMessageEventContent, StrippedStateEvent, SyncMessageEvent, + AnyMessageEventContent, StrippedStateEvent, SyncMessageEvent, SyncStateEvent, }, Client, ClientConfig, EventEmitter, JsonStore, Room, SyncRoom, SyncSettings, }; @@ -229,6 +229,37 @@ async fn should_process<'a>( /// Originally adapted from the matrix-rust-sdk examples. #[async_trait] impl EventEmitter for DiceBot { + async fn on_room_member( + &self, + room: SyncRoom, + room_member: &SyncStateEvent, + ) { + //When joining a channel, we get join events from other users. + //content is MemberContent, and it has a membership type. + + //Ignore if state_key is our username, because we only care about other users. + let event_affects_us = if let Some(our_user_id) = self.client.user_id().await { + room_member.state_key == our_user_id + } else { + false + }; + + let should_add = match room_member.content.membership { + MembershipState::Join => true, + MembershipState::Leave | MembershipState::Ban => false, + _ => return, + }; + + //if event affects us and is leave/ban, delete all our info. + //if event does not affect us, delete info only for that user. + + //TODO replace with call to new db.rooms thing. + println!( + "member {} recorded with action {:?} to/from db.", + room_member.state_key, should_add + ); + } + async fn on_stripped_state_member( &self, room: SyncRoom, diff --git a/src/db.rs b/src/db.rs index 62a94e6..b667bd8 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,5 +1,6 @@ use crate::db::errors::{DataError, MigrationError}; use crate::db::migrations::{get_migration_version, Migrations}; +use crate::db::rooms::Rooms; use crate::db::variables::Variables; use log::info; use sled::{Config, Db}; @@ -8,6 +9,7 @@ use std::path::Path; pub mod data_migrations; pub mod errors; pub mod migrations; +pub mod rooms; pub mod schema; pub mod variables; @@ -16,6 +18,7 @@ pub struct Database { db: Db, pub(crate) variables: Variables, pub(crate) migrations: Migrations, + pub(crate) rooms: Rooms, } impl Database { @@ -26,6 +29,7 @@ impl Database { db: db.clone(), variables: Variables::new(&db)?, migrations: Migrations(migrations), + rooms: Rooms::new(&db)?, }) } diff --git a/src/db/rooms.rs b/src/db/rooms.rs new file mode 100644 index 0000000..3d507fb --- /dev/null +++ b/src/db/rooms.rs @@ -0,0 +1,82 @@ +use crate::db::errors::DataError; +use crate::db::schema::convert_i32; +use byteorder::LittleEndian; +use sled::transaction::{abort, TransactionalTree}; +use sled::Transactional; +use sled::Tree; +use std::collections::HashMap; +use std::collections::HashSet; +use std::convert::From; +use std::str; +use zerocopy::byteorder::I32; +use zerocopy::AsBytes; + +#[derive(Clone)] +pub struct Rooms { + /// Room ID -> RoomInfo struct (single entries) + pub(in crate::db) roomid_roominfo: Tree, + + /// Room ID -> list of usernames in room. + pub(in crate::db) roomid_usernames: Tree, + + /// Username -> list of room IDs user is in. + pub(in crate::db) username_roomids: Tree, +} + +// /// Request soemthing by a username and room ID. +// pub struct UserAndRoom<'a>(pub &'a str, pub &'a str); + +// fn to_vec(value: &UserAndRoom<'_>) -> Vec { +// let mut bytes = vec![]; +// bytes.extend_from_slice(value.0.as_bytes()); +// bytes.push(0xfe); +// bytes.extend_from_slice(value.1.as_bytes()); +// bytes +// } + +// impl From> for Vec { +// fn from(value: UserAndRoom) -> Vec { +// to_vec(&value) +// } +// } + +// impl From<&UserAndRoom<'_>> for Vec { +// fn from(value: &UserAndRoom) -> Vec { +// to_vec(value) +// } +// } + +impl Rooms { + pub(in crate::db) fn new(db: &sled::Db) -> Result { + Ok(Rooms { + roomid_roominfo: db.open_tree("roomid_roominfo")?, + roomid_usernames: db.open_tree("roomid_usernames")?, + username_roomids: db.open_tree("username_roomids")?, + }) + } + + pub fn add_user_to_room(&self, username: &str, room_id: &str) -> Result<(), DataError> { + //in txn: + //get or create list of users in room + //get or create list of rooms user is in + //deserialize/create set and add username to set for roomid + //deserialize/create set and add roomid to set for username + //store both again + let user_to_rooms: HashSet = self + .username_roomids + .get(username.as_bytes())? + .map(|bytes| bincode::deserialize::>(&bytes)) + .unwrap_or(Ok(HashSet::new()))?; + + let room_to_users: HashSet = self + .roomid_usernames + .get(room_id.as_bytes())? + .map(|bytes| bincode::deserialize::>(&bytes)) + .unwrap_or(Ok(HashSet::new()))?; + Ok(()) + } + + pub fn remove_user_from_room(&self, username: &str, room_id: &str) -> Result<(), DataError> { + Ok(()) + } +}