Upgrade to Matrix SDK latest (Store Rewrite) and Tokio 1.0
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This upgrade introduces a handful of breaking changes in the Rust Matrix SDK. - Some types have disappeared and changed name. - Some functions are no longer async. - Room display name now has a Result type instead of just returning the value. - Client state store has breaking changes (not really a big deal). This required introduction of a new type to store room information that we are interested in on the context struct. This new RoomContext is required mostly due to unit tests, because it is no longer possible to instantiate the Room type in the Matrix SDK.
This commit is contained in:
parent
a4cdad4936
commit
1b0003ff1b
File diff suppressed because it is too large
Load Diff
|
@ -37,5 +37,5 @@ version = "1"
|
||||||
features = ['derive']
|
features = ['derive']
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
version = "0.2"
|
version = "1.0"
|
||||||
features = [ "full" ]
|
features = [ "full" ]
|
|
@ -1,18 +1,8 @@
|
||||||
use chronicle_dicebot::commands;
|
use chronicle_dicebot::commands;
|
||||||
use chronicle_dicebot::context::Context;
|
use chronicle_dicebot::context::{Context, RoomContext};
|
||||||
use chronicle_dicebot::db::Database;
|
use chronicle_dicebot::db::Database;
|
||||||
use chronicle_dicebot::error::BotError;
|
use chronicle_dicebot::error::BotError;
|
||||||
use matrix_sdk::{
|
use matrix_sdk::identifiers::room_id;
|
||||||
identifiers::{room_id, user_id},
|
|
||||||
Room,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn dummy_room() -> Room {
|
|
||||||
Room::new(
|
|
||||||
&room_id!("!fakeroomid:example.com"),
|
|
||||||
&user_id!("@fakeuserid:example.com"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), BotError> {
|
async fn main() -> Result<(), BotError> {
|
||||||
|
@ -26,7 +16,10 @@ async fn main() -> Result<(), BotError> {
|
||||||
db: Database::new_temp()?,
|
db: Database::new_temp()?,
|
||||||
matrix_client: &matrix_sdk::Client::new("http://example.com")
|
matrix_client: &matrix_sdk::Client::new("http://example.com")
|
||||||
.expect("Could not create matrix client"),
|
.expect("Could not create matrix client"),
|
||||||
room: &dummy_room(),
|
room: RoomContext {
|
||||||
|
id: &room_id!("!fakeroomid:example.com"),
|
||||||
|
display_name: "fake room",
|
||||||
|
},
|
||||||
username: "@localuser:example.com",
|
username: "@localuser:example.com",
|
||||||
message_body: &input,
|
message_body: &input,
|
||||||
};
|
};
|
||||||
|
|
18
src/bot.rs
18
src/bot.rs
|
@ -1,6 +1,6 @@
|
||||||
use crate::commands::execute_command;
|
use crate::commands::execute_command;
|
||||||
use crate::config::*;
|
use crate::config::*;
|
||||||
use crate::context::Context;
|
use crate::context::{Context, RoomContext};
|
||||||
use crate::db::Database;
|
use crate::db::Database;
|
||||||
use crate::error::BotError;
|
use crate::error::BotError;
|
||||||
use crate::state::DiceBotState;
|
use crate::state::DiceBotState;
|
||||||
|
@ -13,7 +13,7 @@ use matrix_sdk::{
|
||||||
room::message::{MessageEventContent, NoticeMessageEventContent},
|
room::message::{MessageEventContent, NoticeMessageEventContent},
|
||||||
AnyMessageEventContent,
|
AnyMessageEventContent,
|
||||||
},
|
},
|
||||||
Client, ClientConfig, JsonStore, Room, SyncSettings,
|
Client, ClientConfig, JoinedRoom, SyncSettings,
|
||||||
};
|
};
|
||||||
//use matrix_sdk_common_macros::async_trait;
|
//use matrix_sdk_common_macros::async_trait;
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
|
@ -48,8 +48,8 @@ fn cache_dir() -> Result<PathBuf, BotError> {
|
||||||
/// Creates the matrix client.
|
/// Creates the matrix client.
|
||||||
fn create_client(config: &Config) -> Result<Client, BotError> {
|
fn create_client(config: &Config) -> Result<Client, BotError> {
|
||||||
let cache_dir = cache_dir()?;
|
let cache_dir = cache_dir()?;
|
||||||
let store = JsonStore::open(&cache_dir)?;
|
//let store = JsonStore::open(&cache_dir)?;
|
||||||
let client_config = ClientConfig::new().state_store(Box::new(store));
|
let client_config = ClientConfig::new().store_path(cache_dir);
|
||||||
let homeserver_url = Url::parse(&config.matrix_homeserver())?;
|
let homeserver_url = Url::parse(&config.matrix_homeserver())?;
|
||||||
|
|
||||||
Ok(Client::new_with_config(homeserver_url, client_config)?)
|
Ok(Client::new_with_config(homeserver_url, client_config)?)
|
||||||
|
@ -90,7 +90,7 @@ impl DiceBot {
|
||||||
let password = &self.config.matrix_password();
|
let password = &self.config.matrix_password();
|
||||||
|
|
||||||
//TODO provide a device id from config.
|
//TODO provide a device id from config.
|
||||||
let mut client = self.client.clone();
|
let client = self.client.clone();
|
||||||
client
|
client
|
||||||
.login(username, password, None, Some("matrix dice bot"))
|
.login(username, password, None, Some("matrix dice bot"))
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -118,9 +118,9 @@ impl DiceBot {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute_commands(&self, room: &Room, sender_username: &str, msg_body: &str) {
|
async fn execute_commands(&self, room: &JoinedRoom, sender_username: &str, msg_body: &str) {
|
||||||
let room_name = room.display_name().clone();
|
let room_name = room.display_name().await.ok().unwrap_or_default();
|
||||||
let room_id = room.room_id.clone();
|
let room_id = room.room_id().clone();
|
||||||
|
|
||||||
let mut results = Vec::with_capacity(msg_body.lines().count());
|
let mut results = Vec::with_capacity(msg_body.lines().count());
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ impl DiceBot {
|
||||||
let ctx = Context {
|
let ctx = Context {
|
||||||
db: self.db.clone(),
|
db: self.db.clone(),
|
||||||
matrix_client: &self.client,
|
matrix_client: &self.client,
|
||||||
room: room,
|
room: RoomContext::new_with_name(&room, &room_name),
|
||||||
username: &sender_username,
|
username: &sender_username,
|
||||||
message_body: &command,
|
message_body: &command,
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,8 @@ use matrix_sdk::{
|
||||||
room::message::{MessageEventContent, TextMessageEventContent},
|
room::message::{MessageEventContent, TextMessageEventContent},
|
||||||
StrippedStateEvent, SyncMessageEvent, SyncStateEvent,
|
StrippedStateEvent, SyncMessageEvent, SyncStateEvent,
|
||||||
},
|
},
|
||||||
EventEmitter, SyncRoom,
|
identifiers::RoomId,
|
||||||
|
EventEmitter, RoomState,
|
||||||
};
|
};
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
|
@ -92,86 +93,112 @@ fn should_process_event(db: &Database, room_id: &str, event_id: &str) -> bool {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert room state object to the room ID and display name, if
|
||||||
|
/// possible. We only care about the room if it is a joined or left
|
||||||
|
/// room.
|
||||||
|
async fn convert_room_state(state: &RoomState) -> Option<(&RoomId, String)> {
|
||||||
|
match state {
|
||||||
|
RoomState::Joined(room) => Some((
|
||||||
|
room.room_id(),
|
||||||
|
room.display_name().await.ok().unwrap_or_default(),
|
||||||
|
)),
|
||||||
|
RoomState::Left(room) => Some((
|
||||||
|
room.room_id(),
|
||||||
|
room.display_name().await.ok().unwrap_or_default(),
|
||||||
|
)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This event emitter listens for messages with dice rolling commands.
|
/// This event emitter listens for messages with dice rolling commands.
|
||||||
/// Originally adapted from the matrix-rust-sdk examples.
|
/// Originally adapted from the matrix-rust-sdk examples.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EventEmitter for DiceBot {
|
impl EventEmitter for DiceBot {
|
||||||
async fn on_room_member(&self, room: SyncRoom, event: &SyncStateEvent<MemberEventContent>) {
|
async fn on_room_member(&self, state: RoomState, event: &SyncStateEvent<MemberEventContent>) {
|
||||||
if let SyncRoom::Joined(room) | SyncRoom::Left(room) = room {
|
let (room_id, room_display_name) = match convert_room_state(&state).await {
|
||||||
//Clone to avoid holding lock.
|
Some((room_id, room_display_name)) => (room_id, room_display_name),
|
||||||
let room = room.read().await.clone();
|
_ => return,
|
||||||
let (room_id, username) = (room.room_id.as_str(), &event.state_key);
|
};
|
||||||
|
|
||||||
if !should_process_event(&self.db, room_id, event.event_id.as_str()) {
|
let room_id_str = room_id.as_str();
|
||||||
return;
|
let username = &event.state_key;
|
||||||
}
|
|
||||||
|
|
||||||
let event_affects_us = if let Some(our_user_id) = self.client.user_id().await {
|
if !should_process_event(&self.db, room_id_str, event.event_id.as_str()) {
|
||||||
event.state_key == our_user_id
|
return;
|
||||||
} else {
|
}
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
use MembershipChange::*;
|
let event_affects_us = if let Some(our_user_id) = self.client.user_id().await {
|
||||||
let adding_user = match event.membership_change() {
|
event.state_key == our_user_id
|
||||||
Joined => true,
|
} else {
|
||||||
Banned | Left | Kicked | KickedAndBanned => false,
|
false
|
||||||
_ => return,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let result = if event_affects_us && !adding_user {
|
use MembershipChange::*;
|
||||||
info!("Clearing all information for room ID {}", room_id);
|
let adding_user = match event.membership_change() {
|
||||||
self.db.rooms.clear_info(room_id)
|
Joined => true,
|
||||||
} else if event_affects_us && adding_user {
|
Banned | Left | Kicked | KickedAndBanned => false,
|
||||||
info!("Joined room {}; recording room information", room_id);
|
_ => return,
|
||||||
record_room_information(&self.client, &self.db, &room, &event.state_key).await
|
};
|
||||||
} else if !event_affects_us && adding_user {
|
|
||||||
info!("Adding user {} to room ID {}", username, room_id);
|
|
||||||
self.db.rooms.add_user_to_room(username, room_id)
|
|
||||||
} else if !event_affects_us && !adding_user {
|
|
||||||
info!("Removing user {} from room ID {}", username, room_id);
|
|
||||||
self.db.rooms.remove_user_from_room(username, room_id)
|
|
||||||
} else {
|
|
||||||
debug!("Ignoring a room member event: {:#?}", event);
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = result {
|
let result = if event_affects_us && !adding_user {
|
||||||
error!("Could not update room information: {}", e.to_string());
|
info!("Clearing all information for room ID {}", room_id);
|
||||||
} else {
|
self.db.rooms.clear_info(room_id_str)
|
||||||
debug!("Successfully processed room member update.");
|
} else if event_affects_us && adding_user {
|
||||||
}
|
info!("Joined room {}; recording room information", room_id);
|
||||||
|
record_room_information(
|
||||||
|
&self.client,
|
||||||
|
&self.db,
|
||||||
|
&room_id,
|
||||||
|
&room_display_name,
|
||||||
|
&event.state_key,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
} else if !event_affects_us && adding_user {
|
||||||
|
info!("Adding user {} to room ID {}", username, room_id);
|
||||||
|
self.db.rooms.add_user_to_room(username, room_id_str)
|
||||||
|
} else if !event_affects_us && !adding_user {
|
||||||
|
info!("Removing user {} from room ID {}", username, room_id);
|
||||||
|
self.db.rooms.remove_user_from_room(username, room_id_str)
|
||||||
|
} else {
|
||||||
|
debug!("Ignoring a room member event: {:#?}", event);
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = result {
|
||||||
|
error!("Could not update room information: {}", e.to_string());
|
||||||
|
} else {
|
||||||
|
debug!("Successfully processed room member update.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_stripped_state_member(
|
async fn on_stripped_state_member(
|
||||||
&self,
|
&self,
|
||||||
room: SyncRoom,
|
state: RoomState,
|
||||||
event: &StrippedStateEvent<MemberEventContent>,
|
event: &StrippedStateEvent<MemberEventContent>,
|
||||||
_: Option<MemberEventContent>,
|
_: Option<MemberEventContent>,
|
||||||
) {
|
) {
|
||||||
if let SyncRoom::Invited(room) = room {
|
if let RoomState::Invited(room) = state {
|
||||||
if let Some(user_id) = self.client.user_id().await {
|
if let Some(user_id) = self.client.user_id().await {
|
||||||
if event.state_key != user_id {
|
if event.state_key != user_id {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Clone to avoid holding lock.
|
info!("Autojoining room {}", room.display_name().await);
|
||||||
let room = room.read().await.clone();
|
|
||||||
info!("Autojoining room {}", room.display_name());
|
|
||||||
|
|
||||||
if let Err(e) = self.client.join_room_by_id(&room.room_id).await {
|
if let Err(e) = self.client.join_room_by_id(&room.room_id()).await {
|
||||||
warn!("Could not join room: {}", e.to_string())
|
warn!("Could not join room: {}", e.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_room_message(&self, room: SyncRoom, event: &SyncMessageEvent<MessageEventContent>) {
|
async fn on_room_message(
|
||||||
if let SyncRoom::Joined(room) = room {
|
&self,
|
||||||
//Clone to avoid holding lock.
|
state: RoomState,
|
||||||
let room = room.read().await.clone();
|
event: &SyncMessageEvent<MessageEventContent>,
|
||||||
let room_id = room.room_id.as_str();
|
) {
|
||||||
|
if let RoomState::Joined(room) = state {
|
||||||
|
let room_id = room.room_id().as_str();
|
||||||
if !should_process_event(&self.db, room_id, event.event_id.as_str()) {
|
if !should_process_event(&self.db, room_id, event.event_id.as_str()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -326,12 +326,13 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::db::Database;
|
use crate::db::Database;
|
||||||
|
|
||||||
/// Create dummy room instance.
|
macro_rules! dummy_room {
|
||||||
fn dummy_room() -> matrix_sdk::Room {
|
() => {
|
||||||
matrix_sdk::Room::new(
|
crate::context::RoomContext {
|
||||||
&matrix_sdk::identifiers::room_id!("!fakeroomid:example.com"),
|
id: &matrix_sdk::identifiers::room_id!("!fakeroomid:example.com"),
|
||||||
&matrix_sdk::identifiers::user_id!("@fakeuserid:example.com"),
|
display_name: "displayname",
|
||||||
)
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
///Instead of being random, generate a series of numbers we have complete
|
///Instead of being random, generate a series of numbers we have complete
|
||||||
|
@ -475,7 +476,7 @@ mod tests {
|
||||||
let ctx = Context {
|
let ctx = Context {
|
||||||
db: db,
|
db: db,
|
||||||
matrix_client: &matrix_sdk::Client::new("http://example.com").unwrap(),
|
matrix_client: &matrix_sdk::Client::new("http://example.com").unwrap(),
|
||||||
room: &dummy_room(),
|
room: dummy_room!(),
|
||||||
username: "username",
|
username: "username",
|
||||||
message_body: "message",
|
message_body: "message",
|
||||||
};
|
};
|
||||||
|
@ -506,7 +507,7 @@ mod tests {
|
||||||
let ctx = Context {
|
let ctx = Context {
|
||||||
db: db,
|
db: db,
|
||||||
matrix_client: &matrix_sdk::Client::new("http://example.com").unwrap(),
|
matrix_client: &matrix_sdk::Client::new("http://example.com").unwrap(),
|
||||||
room: &dummy_room(),
|
room: dummy_room!(),
|
||||||
username: "username",
|
username: "username",
|
||||||
message_body: "message",
|
message_body: "message",
|
||||||
};
|
};
|
||||||
|
@ -536,12 +537,12 @@ mod tests {
|
||||||
let ctx = Context {
|
let ctx = Context {
|
||||||
db: db.clone(),
|
db: db.clone(),
|
||||||
matrix_client: &matrix_sdk::Client::new("http://example.com").unwrap(),
|
matrix_client: &matrix_sdk::Client::new("http://example.com").unwrap(),
|
||||||
room: &dummy_room(),
|
room: dummy_room!(),
|
||||||
username: "username",
|
username: "username",
|
||||||
message_body: "message",
|
message_body: "message",
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_and_room = UserAndRoom(&ctx.username, &ctx.room.room_id.as_str());
|
let user_and_room = UserAndRoom(&ctx.username, &ctx.room.id.as_str());
|
||||||
|
|
||||||
db.variables
|
db.variables
|
||||||
.set_user_variable(&user_and_room, "myvariable", 10)
|
.set_user_variable(&user_and_room, "myvariable", 10)
|
||||||
|
|
|
@ -78,12 +78,13 @@ pub async fn execute_command(ctx: &Context<'_>) -> CommandResult {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Create a dummy room instance.
|
macro_rules! dummy_room {
|
||||||
fn dummy_room() -> matrix_sdk::Room {
|
() => {
|
||||||
matrix_sdk::Room::new(
|
crate::context::RoomContext {
|
||||||
&matrix_sdk::identifiers::room_id!("!fakeroomid:example.com"),
|
id: &matrix_sdk::identifiers::room_id!("!fakeroomid:example.com"),
|
||||||
&matrix_sdk::identifiers::user_id!("@fakeuserid:example.com"),
|
display_name: "displayname",
|
||||||
)
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -92,7 +93,7 @@ mod tests {
|
||||||
let ctx = Context {
|
let ctx = Context {
|
||||||
db: db,
|
db: db,
|
||||||
matrix_client: &matrix_sdk::Client::new("http://example.com").unwrap(),
|
matrix_client: &matrix_sdk::Client::new("http://example.com").unwrap(),
|
||||||
room: &dummy_room(),
|
room: dummy_room!(),
|
||||||
username: "myusername",
|
username: "myusername",
|
||||||
message_body: "!notacommand",
|
message_body: "!notacommand",
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,8 +19,14 @@ impl Command for ResyncCommand {
|
||||||
let our_username: Option<UserId> = ctx.matrix_client.user_id().await;
|
let our_username: Option<UserId> = ctx.matrix_client.user_id().await;
|
||||||
let our_username: &str = our_username.as_ref().map_or("", UserId::as_str);
|
let our_username: &str = our_username.as_ref().map_or("", UserId::as_str);
|
||||||
|
|
||||||
let result: ResyncResult =
|
let result: ResyncResult = record_room_information(
|
||||||
record_room_information(ctx.matrix_client, &ctx.db, &ctx.room, our_username).await;
|
ctx.matrix_client,
|
||||||
|
&ctx.db,
|
||||||
|
ctx.room.id,
|
||||||
|
&ctx.room.display_name,
|
||||||
|
our_username,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
let (plain, html) = match result {
|
let (plain, html) = match result {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
|
|
|
@ -13,7 +13,7 @@ impl Command for GetAllVariablesCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self, ctx: &Context<'_>) -> Execution {
|
async fn execute(&self, ctx: &Context<'_>) -> Execution {
|
||||||
let key = UserAndRoom(&ctx.username, &ctx.room.room_id.as_str());
|
let key = UserAndRoom(&ctx.username, &ctx.room.id.as_str());
|
||||||
let result = ctx.db.variables.get_user_variables(&key);
|
let result = ctx.db.variables.get_user_variables(&key);
|
||||||
|
|
||||||
let value = match result {
|
let value = match result {
|
||||||
|
@ -48,7 +48,7 @@ impl Command for GetVariableCommand {
|
||||||
|
|
||||||
async fn execute(&self, ctx: &Context<'_>) -> Execution {
|
async fn execute(&self, ctx: &Context<'_>) -> Execution {
|
||||||
let name = &self.0;
|
let name = &self.0;
|
||||||
let key = UserAndRoom(&ctx.username, &ctx.room.room_id.as_str());
|
let key = UserAndRoom(&ctx.username, &ctx.room.id.as_str());
|
||||||
let result = ctx.db.variables.get_user_variable(&key, name);
|
let result = ctx.db.variables.get_user_variable(&key, name);
|
||||||
|
|
||||||
let value = match result {
|
let value = match result {
|
||||||
|
@ -74,7 +74,7 @@ impl Command for SetVariableCommand {
|
||||||
async fn execute(&self, ctx: &Context<'_>) -> Execution {
|
async fn execute(&self, ctx: &Context<'_>) -> Execution {
|
||||||
let name = &self.0;
|
let name = &self.0;
|
||||||
let value = self.1;
|
let value = self.1;
|
||||||
let key = UserAndRoom(&ctx.username, ctx.room.room_id.as_str());
|
let key = UserAndRoom(&ctx.username, ctx.room.id.as_str());
|
||||||
let result = ctx.db.variables.set_user_variable(&key, name, value);
|
let result = ctx.db.variables.set_user_variable(&key, name, value);
|
||||||
|
|
||||||
let content = match result {
|
let content = match result {
|
||||||
|
@ -98,7 +98,7 @@ impl Command for DeleteVariableCommand {
|
||||||
|
|
||||||
async fn execute(&self, ctx: &Context<'_>) -> Execution {
|
async fn execute(&self, ctx: &Context<'_>) -> Execution {
|
||||||
let name = &self.0;
|
let name = &self.0;
|
||||||
let key = UserAndRoom(&ctx.username, ctx.room.room_id.as_str());
|
let key = UserAndRoom(&ctx.username, ctx.room.id.as_str());
|
||||||
let result = ctx.db.variables.delete_user_variable(&key, name);
|
let result = ctx.db.variables.delete_user_variable(&key, name);
|
||||||
|
|
||||||
let value = match result {
|
let value = match result {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::db::Database;
|
use crate::db::Database;
|
||||||
|
use matrix_sdk::identifiers::RoomId;
|
||||||
use matrix_sdk::Client;
|
use matrix_sdk::Client;
|
||||||
use matrix_sdk::Room;
|
use matrix_sdk::JoinedRoom;
|
||||||
|
|
||||||
/// A context carried through the system providing access to things
|
/// A context carried through the system providing access to things
|
||||||
/// like the database.
|
/// like the database.
|
||||||
|
@ -8,7 +9,22 @@ use matrix_sdk::Room;
|
||||||
pub struct Context<'a> {
|
pub struct Context<'a> {
|
||||||
pub db: Database,
|
pub db: Database,
|
||||||
pub matrix_client: &'a Client,
|
pub matrix_client: &'a Client,
|
||||||
pub room: &'a Room,
|
pub room: RoomContext<'a>,
|
||||||
pub username: &'a str,
|
pub username: &'a str,
|
||||||
pub message_body: &'a str,
|
pub message_body: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RoomContext<'a> {
|
||||||
|
pub id: &'a RoomId,
|
||||||
|
pub display_name: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RoomContext<'_> {
|
||||||
|
pub fn new_with_name<'a>(room: &'a JoinedRoom, display_name: &'a str) -> RoomContext<'a> {
|
||||||
|
RoomContext {
|
||||||
|
id: room.room_id(),
|
||||||
|
display_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -343,12 +343,13 @@ mod tests {
|
||||||
use crate::db::Database;
|
use crate::db::Database;
|
||||||
use crate::parser::{Amount, Element, Operator};
|
use crate::parser::{Amount, Element, Operator};
|
||||||
|
|
||||||
/// Create a dummy room instance.
|
macro_rules! dummy_room {
|
||||||
fn dummy_room() -> matrix_sdk::Room {
|
() => {
|
||||||
matrix_sdk::Room::new(
|
crate::context::RoomContext {
|
||||||
&matrix_sdk::identifiers::room_id!("!fakeroomid:example.com"),
|
id: &matrix_sdk::identifiers::room_id!("!fakeroomid:example.com"),
|
||||||
&matrix_sdk::identifiers::user_id!("@fakeuserid:example.com"),
|
display_name: "displayname",
|
||||||
)
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a series of numbers manually for testing. For this
|
/// Generate a series of numbers manually for testing. For this
|
||||||
|
@ -391,7 +392,7 @@ mod tests {
|
||||||
let ctx = Context {
|
let ctx = Context {
|
||||||
db: db,
|
db: db,
|
||||||
matrix_client: &matrix_sdk::Client::new("https://example.com").unwrap(),
|
matrix_client: &matrix_sdk::Client::new("https://example.com").unwrap(),
|
||||||
room: &dummy_room(),
|
room: dummy_room!(),
|
||||||
username: "username",
|
username: "username",
|
||||||
message_body: "message",
|
message_body: "message",
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ use futures::stream::{self, StreamExt, TryStreamExt};
|
||||||
//New hotness
|
//New hotness
|
||||||
pub async fn calculate_dice_amount(amounts: &[Amount], ctx: &Context<'_>) -> Result<i32, BotError> {
|
pub async fn calculate_dice_amount(amounts: &[Amount], ctx: &Context<'_>) -> Result<i32, BotError> {
|
||||||
let stream = stream::iter(amounts);
|
let stream = stream::iter(amounts);
|
||||||
let key = UserAndRoom(&ctx.username, ctx.room.room_id.as_str());
|
let key = UserAndRoom(&ctx.username, ctx.room.id.as_str());
|
||||||
let variables = &ctx.db.variables.get_user_variables(&key)?;
|
let variables = &ctx.db.variables.get_user_variables(&key)?;
|
||||||
|
|
||||||
use DiceRollingError::VariableNotFound;
|
use DiceRollingError::VariableNotFound;
|
||||||
|
|
|
@ -27,6 +27,9 @@ pub enum BotError {
|
||||||
#[error("could not parse URL")]
|
#[error("could not parse URL")]
|
||||||
UrlParseError(#[from] url::ParseError),
|
UrlParseError(#[from] url::ParseError),
|
||||||
|
|
||||||
|
#[error("error in matrix state store: {0}")]
|
||||||
|
MatrixStateStoreError(#[from] matrix_sdk::StoreError),
|
||||||
|
|
||||||
#[error("uncategorized matrix SDK error")]
|
#[error("uncategorized matrix SDK error")]
|
||||||
MatrixError(#[from] matrix_sdk::Error),
|
MatrixError(#[from] matrix_sdk::Error),
|
||||||
|
|
||||||
|
|
11
src/logic.rs
11
src/logic.rs
|
@ -1,21 +1,22 @@
|
||||||
use crate::db::errors::DataError;
|
use crate::db::errors::DataError;
|
||||||
use crate::matrix;
|
use crate::matrix;
|
||||||
use crate::models::RoomInfo;
|
use crate::models::RoomInfo;
|
||||||
use matrix_sdk::{self, Client, Room};
|
use matrix_sdk::{self, identifiers::RoomId, Client};
|
||||||
|
|
||||||
/// Record the information about a room, including users in it.
|
/// Record the information about a room, including users in it.
|
||||||
pub async fn record_room_information(
|
pub async fn record_room_information(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
db: &crate::db::Database,
|
db: &crate::db::Database,
|
||||||
room: &Room,
|
room_id: &RoomId,
|
||||||
|
room_display_name: &str,
|
||||||
our_username: &str,
|
our_username: &str,
|
||||||
) -> Result<(), DataError> {
|
) -> Result<(), DataError> {
|
||||||
let room_id_str = room.room_id.as_str();
|
let room_id_str = room_id.as_str();
|
||||||
let usernames = matrix::get_users_in_room(&client, &room.room_id).await;
|
let usernames = matrix::get_users_in_room(&client, &room_id).await;
|
||||||
|
|
||||||
let info = RoomInfo {
|
let info = RoomInfo {
|
||||||
room_id: room_id_str.to_owned(),
|
room_id: room_id_str.to_owned(),
|
||||||
room_name: room.display_name(),
|
room_name: room_display_name.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO this and the username adding should be one whole
|
// TODO this and the username adding should be one whole
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
use matrix_sdk::{identifiers::RoomId, Client, Room};
|
use matrix_sdk::{identifiers::RoomId, Client};
|
||||||
|
|
||||||
/// Retrieve a list of users in a given room.
|
/// Retrieve a list of users in a given room.
|
||||||
pub async fn get_users_in_room(client: &Client, room_id: &RoomId) -> Vec<String> {
|
pub async fn get_users_in_room(client: &Client, room_id: &RoomId) -> Vec<String> {
|
||||||
if let Some(joined_room) = client.get_joined_room(room_id).await {
|
if let Some(joined_room) = client.get_joined_room(room_id) {
|
||||||
let joined_room: Room = joined_room.read().await.clone();
|
|
||||||
joined_room
|
joined_room
|
||||||
.joined_members
|
.joined_members()
|
||||||
.keys()
|
.await
|
||||||
.map(|user_id| format!("@{}:{}", user_id.localpart(), user_id.server_name()))
|
.ok()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.map(|member| {
|
||||||
|
format!(
|
||||||
|
"@{}:{}",
|
||||||
|
member.user_id().localpart(),
|
||||||
|
member.user_id().server_name()
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
|
|
Loading…
Reference in New Issue