Compare commits
12 Commits
variables-
...
master
Author | SHA1 | Date |
---|---|---|
projectmoon | 86df3c5d1f | |
projectmoon | 38a7e50c5c | |
projectmoon | e309fd1fc6 | |
projectmoon | 9262fe2cac | |
projectmoon | 724a781e7c | |
projectmoon | ef074beb96 | |
projectmoon | 81a69f329a | |
projectmoon | c9e7efa61d | |
projectmoon | f295f2b7b6 | |
projectmoon | 090ce9be45 | |
projectmoon | 2a6dff3e07 | |
projectmoon | 952f35d53a |
|
@ -3,7 +3,7 @@ name: build-and-test
|
|||
|
||||
steps:
|
||||
- name: test
|
||||
image: rust:1.54
|
||||
image: rust:1.80
|
||||
commands:
|
||||
- apt-get update
|
||||
- apt-get install -y cmake
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,7 @@
|
|||
# Builder image with development dependencies.
|
||||
FROM ghcr.io/void-linux/void-linux:latest-mini-x86_64 as builder
|
||||
RUN xbps-install -S
|
||||
RUN xbps-install -yu xbps
|
||||
RUN xbps-install -Syu
|
||||
RUN xbps-install -Sy base-devel rustup cmake wget gnupg
|
||||
RUN xbps-install -Sy openssl-devel libstdc++-devel
|
||||
|
@ -18,6 +20,9 @@ RUN . /root/.cargo/env && cargo build --release
|
|||
|
||||
# Final image
|
||||
FROM ghcr.io/void-linux/void-linux:latest-mini-x86_64
|
||||
RUN xbps-install -S
|
||||
RUN xbps-install -yu xbps
|
||||
RUN xbps-install -Syu
|
||||
RUN xbps-install -Sy ca-certificates libstdc++
|
||||
COPY --from=builder \
|
||||
/root/src/target/release/dicebot \
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[package]
|
||||
name = "tenebrous-dicebot"
|
||||
version = "0.13.1"
|
||||
version = "0.13.2"
|
||||
rust-version = "1.68"
|
||||
authors = ["projectmoon <projectmoon@agnos.is>", "Taylor C. Richberger <taywee@gmx.com>"]
|
||||
edition = "2018"
|
||||
license = 'AGPL-3.0-or-later'
|
||||
|
@ -15,7 +16,7 @@ tonic-build = "0.4"
|
|||
|
||||
[dependencies]
|
||||
# indexmap version locked fixes a dependency cycle.
|
||||
indexmap = "=1.6.2"
|
||||
# indexmap = "=1.6.2"
|
||||
log = "0.4"
|
||||
tracing-subscriber = "0.2"
|
||||
toml = "0.5"
|
||||
|
@ -32,7 +33,7 @@ combine = "4.5"
|
|||
futures = "0.3"
|
||||
html2text = "0.2"
|
||||
phf = { version = "0.8", features = ["macros"] }
|
||||
matrix-sdk = { version = "0.4.1" }
|
||||
matrix-sdk = { version = "0.6" }
|
||||
refinery = { version = "0.8", features = ["rusqlite"]}
|
||||
barrel = { version = "0.7", features = ["sqlite3"] }
|
||||
strum = { version = "0.22", features = ["derive"] }
|
||||
|
@ -44,7 +45,7 @@ prost = "0.7"
|
|||
tenebrous-rpc = { path = "../rpc", version = "0.1.0" }
|
||||
|
||||
[dependencies.sqlx]
|
||||
version = "0.5"
|
||||
version = "0.6"
|
||||
features = [ "offline", "sqlite", "runtime-tokio-native-tls" ]
|
||||
|
||||
[dependencies.serde]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use matrix_sdk::ruma::identifiers::room_id;
|
||||
use matrix_sdk::ruma::room_id;
|
||||
use matrix_sdk::Client;
|
||||
use tenebrous_dicebot::commands;
|
||||
use tenebrous_dicebot::commands::ResponseExtractor;
|
||||
|
@ -29,7 +29,7 @@ async fn main() -> Result<(), BotError> {
|
|||
let context = Context {
|
||||
db,
|
||||
account: Account::default(),
|
||||
matrix_client: Client::new(homeserver).expect("Could not create matrix client"),
|
||||
matrix_client: Client::new(homeserver).await.expect("Could not create matrix client"),
|
||||
origin_room: RoomContext {
|
||||
id: &room_id!("!fakeroomid:example.com"),
|
||||
display_name: "fake room".to_owned(),
|
||||
|
|
|
@ -21,7 +21,7 @@ async fn init(config_path: &str) -> Result<(Arc<Config>, Database, Client), BotE
|
|||
let cfg = Arc::new(cfg);
|
||||
let sqlite_path = format!("{}/dicebot.sqlite", cfg.database_path());
|
||||
let db = Database::new(&sqlite_path).await?;
|
||||
let client = tenebrous_dicebot::matrix::create_client(&cfg)?;
|
||||
let client = tenebrous_dicebot::matrix::create_client(&cfg).await?;
|
||||
Ok((cfg, db, client))
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ async fn run() -> Result<(), BotError> {
|
|||
|
||||
match try_join!(bot, grpc) {
|
||||
Ok(_) => (),
|
||||
Err(e) => error!("Error: {}", e),
|
||||
Err(e) => error!("Error: {:?}", e),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
models::Account,
|
||||
};
|
||||
use futures::stream::{self, StreamExt};
|
||||
use matrix_sdk::ruma::{EventId, RoomId};
|
||||
use matrix_sdk::ruma::{OwnedEventId, RoomId};
|
||||
use matrix_sdk::{self, room::Joined, Client};
|
||||
use std::clone::Clone;
|
||||
use std::convert::TryFrom;
|
||||
|
@ -20,7 +20,7 @@ pub(super) async fn handle_single_result(
|
|||
cmd_result: &ExecutionResult,
|
||||
respond_to: &str,
|
||||
room: &Joined,
|
||||
event_id: EventId,
|
||||
event_id: OwnedEventId,
|
||||
) {
|
||||
let html = cmd_result.message_html(respond_to);
|
||||
let plain = cmd_result.message_plain(respond_to);
|
||||
|
@ -108,9 +108,9 @@ fn get_account_active_room(client: &Client, account: &Account) -> Result<Option<
|
|||
let active_room = account
|
||||
.registered_user()
|
||||
.and_then(|u| u.active_room.as_deref())
|
||||
.map(|room_id| RoomId::try_from(room_id))
|
||||
.map(|room_id| <&RoomId>::try_from(room_id))
|
||||
.transpose()?
|
||||
.and_then(|active_room_id| client.get_joined_room(&active_room_id));
|
||||
.and_then(|active_room_id| client.get_joined_room(active_room_id));
|
||||
|
||||
Ok(active_room)
|
||||
}
|
||||
|
|
|
@ -3,25 +3,24 @@ use crate::db::sqlite::Database;
|
|||
use crate::db::Rooms;
|
||||
use crate::error::BotError;
|
||||
use log::{debug, error, info, warn};
|
||||
use matrix_sdk::ruma::events::room::member::MemberEventContent;
|
||||
use matrix_sdk::ruma::events::room::message::{MessageType, TextMessageEventContent};
|
||||
use matrix_sdk::ruma::events::{StrippedStateEvent, SyncMessageEvent};
|
||||
use matrix_sdk::Client;
|
||||
use matrix_sdk::{self, room::Room, ruma::events::room::message::MessageEventContent};
|
||||
use matrix_sdk::ruma::events::room::member::RoomMemberEventContent;
|
||||
use matrix_sdk::ruma::events::{StrippedStateEvent, SyncMessageLikeEvent};
|
||||
use matrix_sdk::{self, room::Room, ruma::events::room::message::RoomMessageEventContent};
|
||||
use matrix_sdk::{Client, DisplayName};
|
||||
use std::ops::Sub;
|
||||
use std::time::UNIX_EPOCH;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{clone::Clone, time::UNIX_EPOCH};
|
||||
|
||||
/// Check if a message is recent enough to actually process. If the
|
||||
/// message is within "oldest_message_age" seconds, this function
|
||||
/// returns true. If it's older than that, it returns false and logs a
|
||||
/// debug message.
|
||||
fn check_message_age(
|
||||
event: &SyncMessageEvent<MessageEventContent>,
|
||||
event: &SyncMessageLikeEvent<RoomMessageEventContent>,
|
||||
oldest_message_age: u64,
|
||||
) -> bool {
|
||||
let sending_time = event
|
||||
.origin_server_ts
|
||||
.origin_server_ts()
|
||||
.to_system_time()
|
||||
.unwrap_or(UNIX_EPOCH);
|
||||
|
||||
|
@ -48,7 +47,7 @@ fn check_message_age(
|
|||
/// the bot left and rejoined quickly.
|
||||
async fn should_process_message<'a>(
|
||||
bot: &DiceBot,
|
||||
event: &SyncMessageEvent<MessageEventContent>,
|
||||
event: &SyncMessageLikeEvent<RoomMessageEventContent>,
|
||||
) -> Result<(String, String), BotError> {
|
||||
//Ignore messages that are older than configured duration.
|
||||
if !check_message_age(event, bot.config.oldest_message_age()) {
|
||||
|
@ -62,23 +61,29 @@ async fn should_process_message<'a>(
|
|||
return Err(BotError::ShouldNotProcessError);
|
||||
}
|
||||
|
||||
let (msg_body, sender_username) = if let SyncMessageEvent {
|
||||
content:
|
||||
MessageEventContent {
|
||||
msgtype: MessageType::Text(TextMessageEventContent { body, .. }),
|
||||
..
|
||||
},
|
||||
sender,
|
||||
..
|
||||
} = event
|
||||
{
|
||||
(
|
||||
body.clone(),
|
||||
format!("@{}:{}", sender.localpart(), sender.server_name()),
|
||||
)
|
||||
} else {
|
||||
(String::new(), String::new())
|
||||
};
|
||||
let msg_body: String = event
|
||||
.as_original()
|
||||
.map(|e| e.content.body())
|
||||
.map(str::to_string)
|
||||
.unwrap_or_else(|| String::new());
|
||||
|
||||
let sender_username: String = format!(
|
||||
"@{}:{}",
|
||||
event.sender().localpart(),
|
||||
event.sender().server_name()
|
||||
);
|
||||
|
||||
// Do not process messages from the bot itself. Otherwise it might
|
||||
// try to execute its own commands.
|
||||
let bot_username = bot
|
||||
.client
|
||||
.user_id()
|
||||
.map(|u| format!("@{}:{}", u.localpart(), u.server_name()))
|
||||
.unwrap_or_default();
|
||||
|
||||
if sender_username == bot_username {
|
||||
return Err(BotError::ShouldNotProcessError);
|
||||
}
|
||||
|
||||
Ok((msg_body, sender_username))
|
||||
}
|
||||
|
@ -96,7 +101,7 @@ async fn should_process_event(db: &Database, room_id: &str, event_id: &str) -> b
|
|||
}
|
||||
|
||||
pub(super) async fn on_stripped_state_member(
|
||||
event: StrippedStateEvent<MemberEventContent>,
|
||||
event: StrippedStateEvent<RoomMemberEventContent>,
|
||||
client: Client,
|
||||
room: Room,
|
||||
) {
|
||||
|
@ -111,7 +116,10 @@ pub(super) async fn on_stripped_state_member(
|
|||
|
||||
info!(
|
||||
"Autojoining room {}",
|
||||
room.display_name().await.ok().unwrap_or_default()
|
||||
room.display_name()
|
||||
.await
|
||||
.ok()
|
||||
.unwrap_or_else(|| DisplayName::Named("[error]".to_string()))
|
||||
);
|
||||
|
||||
if let Err(e) = client.join_room_by_id(&room.room_id()).await {
|
||||
|
@ -120,7 +128,7 @@ pub(super) async fn on_stripped_state_member(
|
|||
}
|
||||
|
||||
pub(super) async fn on_room_message(
|
||||
event: SyncMessageEvent<MessageEventContent>,
|
||||
event: SyncMessageLikeEvent<RoomMessageEventContent>,
|
||||
room: Room,
|
||||
bot: DiceBot,
|
||||
) {
|
||||
|
@ -130,7 +138,7 @@ pub(super) async fn on_room_message(
|
|||
};
|
||||
|
||||
let room_id = room.room_id().as_str();
|
||||
if !should_process_event(&bot.db, room_id, event.event_id.as_str()).await {
|
||||
if !should_process_event(&bot.db, room_id, event.event_id().as_str()).await {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -145,6 +153,11 @@ pub(super) async fn on_room_message(
|
|||
.execute_commands(&room, &sender_username, &msg_body)
|
||||
.await;
|
||||
|
||||
bot.handle_results(&room, &sender_username, event.event_id.clone(), results)
|
||||
bot.handle_results(
|
||||
&room,
|
||||
&sender_username,
|
||||
event.event_id().to_owned(),
|
||||
results,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
|
@ -6,10 +6,11 @@ use crate::error::BotError;
|
|||
use crate::state::DiceBotState;
|
||||
use log::info;
|
||||
use matrix_sdk::room::Room;
|
||||
use matrix_sdk::ruma::events::room::message::MessageEventContent;
|
||||
use matrix_sdk::ruma::events::SyncMessageEvent;
|
||||
use matrix_sdk::ruma::EventId;
|
||||
use matrix_sdk::{self, room::Joined, Client, SyncSettings};
|
||||
use matrix_sdk::ruma::events::room::message::RoomMessageEventContent;
|
||||
use matrix_sdk::ruma::events::SyncMessageLikeEvent;
|
||||
use matrix_sdk::ruma::OwnedEventId;
|
||||
use matrix_sdk::{self, room::Joined, Client};
|
||||
use matrix_sdk::config::SyncSettings;
|
||||
use std::clone::Clone;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
|
@ -68,12 +69,14 @@ impl DiceBot {
|
|||
let device_id: Option<String> = self.db.get_device_id().await?;
|
||||
let device_id: Option<&str> = device_id.as_deref();
|
||||
|
||||
client
|
||||
.login(username, password, device_id, Some("matrix dice bot"))
|
||||
.await?;
|
||||
let no_device_ld_login = || client.login_username(username, password);
|
||||
let device_id_login = |id| client.login_username(username, password).device_id(id);
|
||||
let login = device_id.map_or_else(no_device_ld_login, device_id_login);
|
||||
|
||||
login.send().await?;
|
||||
|
||||
if device_id.is_none() {
|
||||
let device_id = client.device_id().await.ok_or(BotError::NoDeviceIdFound)?;
|
||||
let device_id = client.device_id().ok_or(BotError::NoDeviceIdFound)?;
|
||||
self.db.set_device_id(device_id.as_str()).await?;
|
||||
info!("Recorded new device ID: {}", device_id.as_str());
|
||||
} else {
|
||||
|
@ -87,19 +90,17 @@ impl DiceBot {
|
|||
async fn bind_events(&self) {
|
||||
//on room message: need closure to pass bot ref in.
|
||||
self.client
|
||||
.register_event_handler({
|
||||
.add_event_handler({
|
||||
let bot: DiceBot = self.clone();
|
||||
move |event: SyncMessageEvent<MessageEventContent>, room: Room| {
|
||||
move |event: SyncMessageLikeEvent<RoomMessageEventContent>, room: Room| {
|
||||
let bot = bot.clone();
|
||||
async move { event_handlers::on_room_message(event, room, bot).await }
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
//auto-join handler
|
||||
self.client
|
||||
.register_event_handler(event_handlers::on_stripped_state_member)
|
||||
.await;
|
||||
.add_event_handler(event_handlers::on_stripped_state_member);
|
||||
}
|
||||
|
||||
/// Logs the bot in to Matrix and listens for events until program
|
||||
|
@ -114,7 +115,7 @@ impl DiceBot {
|
|||
|
||||
// TODO replace with sync_with_callback for cleaner shutdown
|
||||
// process.
|
||||
client.sync(SyncSettings::default()).await;
|
||||
client.sync(SyncSettings::default()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -144,7 +145,7 @@ impl DiceBot {
|
|||
&self,
|
||||
room: &Joined,
|
||||
sender_username: &str,
|
||||
event_id: EventId,
|
||||
event_id: OwnedEventId,
|
||||
results: Vec<(String, ExecutionResult)>,
|
||||
) {
|
||||
if results.len() >= 1 {
|
||||
|
|
|
@ -332,7 +332,7 @@ mod tests {
|
|||
macro_rules! dummy_room {
|
||||
() => {
|
||||
crate::context::RoomContext {
|
||||
id: &matrix_sdk::ruma::identifiers::room_id!("!fakeroomid:example.com"),
|
||||
id: &matrix_sdk::ruma::room_id!("!fakeroomid:example.com"),
|
||||
display_name: "displayname".to_owned(),
|
||||
secure: false,
|
||||
}
|
||||
|
@ -485,7 +485,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: dummy_room!(),
|
||||
active_room: dummy_room!(),
|
||||
username: "username",
|
||||
|
@ -527,7 +527,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: dummy_room!(),
|
||||
active_room: dummy_room!(),
|
||||
username: "username",
|
||||
|
@ -566,7 +566,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db.clone(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: dummy_room!(),
|
||||
active_room: dummy_room!(),
|
||||
username: "username",
|
||||
|
|
|
@ -162,11 +162,12 @@ mod tests {
|
|||
use super::*;
|
||||
use management::RegisterCommand;
|
||||
use url::Url;
|
||||
use matrix_sdk::ruma::room_id;
|
||||
|
||||
macro_rules! dummy_room {
|
||||
() => {
|
||||
crate::context::RoomContext {
|
||||
id: &matrix_sdk::ruma::identifiers::room_id!("!fakeroomid:example.com"),
|
||||
id: &room_id!("!fakeroomid:example.com"),
|
||||
display_name: "displayname".to_owned(),
|
||||
secure: false,
|
||||
}
|
||||
|
@ -176,7 +177,7 @@ mod tests {
|
|||
macro_rules! secure_room {
|
||||
() => {
|
||||
crate::context::RoomContext {
|
||||
id: &matrix_sdk::ruma::identifiers::room_id!("!fakeroomid:example.com"),
|
||||
id: &room_id!("!fakeroomid:example.com"),
|
||||
display_name: "displayname".to_owned(),
|
||||
secure: true,
|
||||
}
|
||||
|
@ -195,7 +196,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: secure_room!(),
|
||||
active_room: secure_room!(),
|
||||
username: "myusername",
|
||||
|
@ -218,7 +219,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: secure_room!(),
|
||||
active_room: secure_room!(),
|
||||
username: "myusername",
|
||||
|
@ -241,7 +242,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: dummy_room!(),
|
||||
active_room: dummy_room!(),
|
||||
username: "myusername",
|
||||
|
@ -264,7 +265,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: dummy_room!(),
|
||||
active_room: dummy_room!(),
|
||||
username: "myusername",
|
||||
|
@ -287,7 +288,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: dummy_room!(),
|
||||
active_room: dummy_room!(),
|
||||
username: "myusername",
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::matrix;
|
|||
use async_trait::async_trait;
|
||||
use fuse_rust::{Fuse, FuseProperty, Fuseable};
|
||||
use futures::stream::{self, StreamExt, TryStreamExt};
|
||||
use matrix_sdk::{ruma::UserId, Client};
|
||||
use matrix_sdk::{ruma::OwnedUserId, Client};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
/// Holds matrix room ID and display name as strings, for use with
|
||||
|
@ -62,13 +62,13 @@ async fn get_rooms_for_user(
|
|||
client: &Client,
|
||||
user_id: &str,
|
||||
) -> Result<Vec<RoomNameAndId>, BotError> {
|
||||
let user_id = UserId::try_from(user_id)?;
|
||||
let user_id = OwnedUserId::try_from(user_id)?;
|
||||
let rooms_for_user = matrix::get_rooms_for_user(client, &user_id).await?;
|
||||
let mut rooms_for_user: Vec<RoomNameAndId> = stream::iter(rooms_for_user)
|
||||
.filter_map(|room| async move {
|
||||
Some(room.display_name().await.map(|room_name| RoomNameAndId {
|
||||
id: room.room_id().to_string(),
|
||||
name: room_name,
|
||||
name: room_name.to_string(),
|
||||
}))
|
||||
})
|
||||
.try_collect()
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::db::sqlite::Database;
|
|||
use crate::error::BotError;
|
||||
use crate::models::Account;
|
||||
use matrix_sdk::room::Joined;
|
||||
use matrix_sdk::ruma::identifiers::{RoomId, UserId};
|
||||
use matrix_sdk::ruma::{RoomId, UserId};
|
||||
use matrix_sdk::Client;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
|
@ -48,15 +48,16 @@ impl RoomContext<'_> {
|
|||
// TODO is_direct is a hack; the bot should set eligible rooms
|
||||
// to Direct Message upon joining, if other contact has
|
||||
// requested it. Waiting on SDK support.
|
||||
let display_name = room
|
||||
let display_name =
|
||||
room
|
||||
.display_name()
|
||||
.await
|
||||
.ok()
|
||||
.unwrap_or_default()
|
||||
.to_string();
|
||||
.map(|d| d.to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
let sending_user = UserId::try_from(sending_user)?;
|
||||
let user_in_room = room.get_member(&sending_user).await.ok().is_some();
|
||||
let sending_user = <&UserId>::try_from(sending_user)?;
|
||||
let user_in_room = room.get_member(sending_user).await.ok().is_some();
|
||||
let is_direct = room.active_members().await?.len() == 2;
|
||||
|
||||
Ok(RoomContext {
|
||||
|
|
|
@ -270,7 +270,7 @@ macro_rules! is_variable {
|
|||
element: Element::Variable(_),
|
||||
..
|
||||
}
|
||||
);
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -427,11 +427,12 @@ mod tests {
|
|||
use crate::db::sqlite::Database;
|
||||
use crate::parser::dice::{Amount, Element, Operator};
|
||||
use url::Url;
|
||||
use matrix_sdk::ruma::room_id;
|
||||
|
||||
macro_rules! dummy_room {
|
||||
() => {
|
||||
crate::context::RoomContext {
|
||||
id: &matrix_sdk::ruma::identifiers::room_id!("!fakeroomid:example.com"),
|
||||
id: &room_id!("!fakeroomid:example.com"),
|
||||
display_name: "displayname".to_owned(),
|
||||
secure: false,
|
||||
}
|
||||
|
@ -511,7 +512,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: dummy_room!(),
|
||||
active_room: dummy_room!(),
|
||||
username: "username",
|
||||
|
@ -549,7 +550,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: dummy_room!(),
|
||||
active_room: dummy_room!(),
|
||||
username: "username",
|
||||
|
@ -587,7 +588,7 @@ mod tests {
|
|||
let ctx = Context {
|
||||
account: crate::models::Account::default(),
|
||||
db: db,
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).unwrap(),
|
||||
matrix_client: matrix_sdk::Client::new(homeserver).await.unwrap(),
|
||||
origin_room: dummy_room!(),
|
||||
active_room: dummy_room!(),
|
||||
username: "username",
|
||||
|
|
|
@ -18,6 +18,12 @@ pub enum BotError {
|
|||
#[error("could not retrieve device id")]
|
||||
NoDeviceIdFound,
|
||||
|
||||
#[error("could not build client: {0}")]
|
||||
ClientBuildError(#[from] matrix_sdk::ClientBuildError),
|
||||
|
||||
#[error("could not open matrix store: {0}")]
|
||||
OpenStoreError(#[from] matrix_sdk::store::OpenStoreError),
|
||||
|
||||
#[error("command error: {0}")]
|
||||
CommandError(#[from] CommandError),
|
||||
|
||||
|
@ -33,6 +39,9 @@ pub enum BotError {
|
|||
#[error("could not parse URL")]
|
||||
UrlParseError(#[from] url::ParseError),
|
||||
|
||||
#[error("could not parse ID")]
|
||||
IdParseError(#[from] matrix_sdk::ruma::IdParseError),
|
||||
|
||||
#[error("error in matrix state store: {0}")]
|
||||
MatrixStateStoreError(#[from] matrix_sdk::StoreError),
|
||||
|
||||
|
@ -76,8 +85,8 @@ pub enum BotError {
|
|||
#[error("could not convert to proper integer type")]
|
||||
TryFromIntError(#[from] std::num::TryFromIntError),
|
||||
|
||||
#[error("identifier error: {0}")]
|
||||
IdentifierError(#[from] matrix_sdk::ruma::identifiers::Error),
|
||||
// #[error("identifier error: {0}")]
|
||||
// IdentifierError(#[from] matrix_sdk::ruma::Error),
|
||||
|
||||
#[error("password creation error: {0}")]
|
||||
PasswordCreationError(argon2::Error),
|
||||
|
|
|
@ -6,6 +6,9 @@ pub fn parse_help_topic(input: &str) -> Option<HelpTopic> {
|
|||
"dicepool" => Some(HelpTopic::DicePool),
|
||||
"dice" => Some(HelpTopic::RollingDice),
|
||||
"cthulhu" => Some(HelpTopic::Cthulhu),
|
||||
"variables" => Some(HelpTopic::Variables),
|
||||
"var" => Some(HelpTopic::Variables),
|
||||
"variable" => Some(HelpTopic::Variables),
|
||||
"" => Some(HelpTopic::General),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -16,6 +19,7 @@ pub enum HelpTopic {
|
|||
DicePool,
|
||||
Cthulhu,
|
||||
RollingDice,
|
||||
Variables,
|
||||
General,
|
||||
}
|
||||
|
||||
|
@ -101,6 +105,34 @@ Note: If !cthadv is given a variable, and the roll is successful, it will
|
|||
update the variable with the new skill.
|
||||
"};
|
||||
|
||||
const VARIABLES_HELP: &'static str = indoc! {"
|
||||
Variables
|
||||
|
||||
Commands: !get, !set, !variables
|
||||
|
||||
Manage variables that can be substituted into roll commands.
|
||||
|
||||
Examples: !get myvar, !set myvar 10
|
||||
|
||||
!get <variable> = show variable of the given name
|
||||
!set <variable> <num> = set a variable to a number
|
||||
|
||||
The !variables command will list all variables for the room. The
|
||||
variables command cna be used in a secure room to avoid spamming the
|
||||
actual room that the variable is set in.
|
||||
|
||||
Variable names can be used in all types of dice rolls:
|
||||
|
||||
!pool myvar + 3
|
||||
!roll myvar
|
||||
|
||||
There are some limitations on variables: they cannot themselves be
|
||||
dice expressions (i.e. can only be numbers), and they must be uniquely
|
||||
parseable in an expression (i.e 'myvard6' does not work for the !roll
|
||||
command).
|
||||
|
||||
"};
|
||||
|
||||
const GENERAL_HELP: &'static str = indoc! {"
|
||||
General Help
|
||||
|
||||
|
@ -117,6 +149,7 @@ impl HelpTopic {
|
|||
HelpTopic::DicePool => DICEPOOL_HELP,
|
||||
HelpTopic::Cthulhu => CTHULHU_HELP,
|
||||
HelpTopic::RollingDice => DICE_HELP,
|
||||
HelpTopic::Variables => VARIABLES_HELP,
|
||||
HelpTopic::General => GENERAL_HELP,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@ use std::path::PathBuf;
|
|||
|
||||
use futures::stream::{self, StreamExt, TryStreamExt};
|
||||
use log::error;
|
||||
use matrix_sdk::ruma::events::room::message::{InReplyTo, MessageEventContent, Relation};
|
||||
use matrix_sdk::ruma::events::AnyMessageEventContent;
|
||||
use matrix_sdk::ruma::{EventId, RoomId, UserId};
|
||||
use matrix_sdk::ruma::events::room::message::{InReplyTo, RoomMessageEventContent, Relation};
|
||||
use matrix_sdk::ruma::events::AnyMessageLikeEventContent;
|
||||
use matrix_sdk::ruma::{RoomId, OwnedEventId, OwnedUserId};
|
||||
use matrix_sdk::Client;
|
||||
use matrix_sdk::Error as MatrixError;
|
||||
use matrix_sdk::{room::Joined, ClientConfig};
|
||||
use matrix_sdk::room::Joined;
|
||||
use url::Url;
|
||||
|
||||
use crate::{config::Config, error::BotError};
|
||||
|
@ -29,12 +29,16 @@ fn extract_error_message(error: MatrixError) -> String {
|
|||
}
|
||||
|
||||
/// Creates the matrix client.
|
||||
pub fn create_client(config: &Config) -> Result<Client, BotError> {
|
||||
pub async fn create_client(config: &Config) -> Result<Client, BotError> {
|
||||
let cache_dir = cache_dir()?;
|
||||
let client_config = ClientConfig::new().store_path(cache_dir);
|
||||
let homeserver_url = Url::parse(&config.matrix_homeserver())?;
|
||||
|
||||
Ok(Client::new_with_config(homeserver_url, client_config)?)
|
||||
let client = Client::builder()
|
||||
.sled_store(cache_dir, None)?
|
||||
.homeserver_url(homeserver_url).build()
|
||||
.await?;
|
||||
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
/// Retrieve a list of users in a given room.
|
||||
|
@ -56,7 +60,7 @@ pub async fn get_users_in_room(
|
|||
|
||||
pub async fn get_rooms_for_user(
|
||||
client: &Client,
|
||||
user: &UserId,
|
||||
user: &OwnedUserId,
|
||||
) -> Result<Vec<Joined>, MatrixError> {
|
||||
// Carries errors through, in case we cannot load joined user IDs
|
||||
// from the room for some reason.
|
||||
|
@ -84,7 +88,7 @@ pub async fn send_message(
|
|||
client: &Client,
|
||||
room_id: &RoomId,
|
||||
message: (&str, &str),
|
||||
reply_to: Option<EventId>,
|
||||
reply_to: Option<OwnedEventId>,
|
||||
) {
|
||||
let (html, plain) = message;
|
||||
let room = match client.get_joined_room(room_id) {
|
||||
|
@ -92,13 +96,13 @@ pub async fn send_message(
|
|||
_ => return,
|
||||
};
|
||||
|
||||
let mut content = MessageEventContent::notice_html(plain.trim(), html);
|
||||
let mut content = RoomMessageEventContent::notice_html(plain.trim(), html);
|
||||
|
||||
content.relates_to = reply_to.map(|event_id| Relation::Reply {
|
||||
in_reply_to: InReplyTo::new(event_id),
|
||||
in_reply_to: InReplyTo::new(event_id)
|
||||
});
|
||||
|
||||
let content = AnyMessageEventContent::RoomMessage(content);
|
||||
let content = AnyMessageLikeEventContent::RoomMessage(content);
|
||||
|
||||
let result = room.send(content, None).await;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::matrix;
|
|||
use crate::{config::Config, db::sqlite::Database};
|
||||
use futures::stream;
|
||||
use futures::{StreamExt, TryFutureExt, TryStreamExt};
|
||||
use matrix_sdk::ruma::UserId;
|
||||
use matrix_sdk::ruma::OwnedUserId;
|
||||
use matrix_sdk::{room::Joined, Client};
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
|
@ -85,7 +85,7 @@ impl Dicebot for DicebotRpcService {
|
|||
request: Request<UserIdRequest>,
|
||||
) -> Result<Response<RoomsListReply>, Status> {
|
||||
let UserIdRequest { user_id } = request.into_inner();
|
||||
let user_id = UserId::try_from(user_id).map_err(BotError::from)?;
|
||||
let user_id = OwnedUserId::try_from(user_id).map_err(BotError::from)?;
|
||||
|
||||
let rooms_for_user = matrix::get_rooms_for_user(&self.client, &user_id)
|
||||
.err_into::<BotError>()
|
||||
|
@ -95,7 +95,7 @@ impl Dicebot for DicebotRpcService {
|
|||
.filter_map(|room: Joined| async move {
|
||||
let room: Result<Room, _> = room.display_name().await.map(|room_name| Room {
|
||||
room_id: room.room_id().to_string(),
|
||||
display_name: room_name,
|
||||
display_name: room_name.to_string(),
|
||||
});
|
||||
|
||||
Some(room)
|
||||
|
|
Loading…
Reference in New Issue