make actually work with messages

This commit is contained in:
Taylor C. Richberger 2020-04-21 22:19:15 -06:00
parent 81b8b2c0cc
commit 6d180734d5
3 changed files with 68 additions and 9 deletions

View File

@ -1,4 +1,5 @@
use crate::matrix::{Event, MessageContent, RoomEvent, SyncCommand};
use crate::matrix::{Event, MessageContent, RoomEvent, SyncCommand, NoticeMessage};
use crate::commands::parse_command;
use reqwest::{Client, Url};
use serde::{self, Deserialize, Serialize};
use std::fs;
@ -15,6 +16,8 @@ pub struct MatrixConfig {
/// The next batch to grab. This should be set automatically
pub next_batch: Option<String>,
#[serde(default)]
pub txn_id: u64,
pub login: toml::Value,
}
@ -34,6 +37,7 @@ pub struct DiceBot {
next_batch: Option<String>,
client: Client,
home_server: Url,
txn_id: u64,
}
#[derive(Deserialize, Debug)]
@ -60,6 +64,7 @@ impl DiceBot {
.await?;
let body: LoginResponse = serde_json::from_str(&response.text().await?)?;
let next_batch = config.matrix.next_batch.clone();
let txn_id = config.matrix.txn_id;
Ok(DiceBot {
home_server,
config_path,
@ -67,6 +72,7 @@ impl DiceBot {
config,
access_token: body.access_token,
next_batch,
txn_id,
})
}
@ -84,9 +90,9 @@ impl DiceBot {
/// Build a url using the current home server and the given path, as well as appending the
/// access token
fn url(&self, path: &str, query: &[(&str, &str)]) -> Url {
fn url<S: AsRef<str>>(&self, path: S, query: &[(&str, &str)]) -> Url {
let mut url = self.home_server.clone();
url.set_path(path);
url.set_path(path.as_ref());
{
let mut query_pairs = url.query_pairs_mut();
query_pairs.append_pair("access_token", &self.access_token);
@ -118,7 +124,7 @@ impl DiceBot {
let sync: SyncCommand = serde_json::from_str(&body).unwrap();
// First join invited rooms
for room in sync.rooms.invite.keys() {
let join_url = self.url(&format!("/_matrix/client/r0/rooms/{}/join", room), &[]);
let join_url = self.url(format!("/_matrix/client/r0/rooms/{}/join", room), &[]);
self.client
.post(join_url)
.header("user-agent", USER_AGENT)
@ -126,16 +132,45 @@ impl DiceBot {
.await?;
}
for (_room_id, room) in sync.rooms.join.iter() {
for (room_id, room) in sync.rooms.join.iter() {
for event in &room.timeline.events {
if let Event::Room(RoomEvent {
sender,
event_id,
content: MessageContent::Text(message),
..
}) = event
{
// TODO: create command parser (maybe command.rs) to parse !roll/!r commands
// and reply
println!("Body: {}", message.body());
let (plain, html): (String, String) = match parse_command(message.body()) {
Ok(Some(command)) => {
let command = command.execute();
(command.plain().into(), command.html().into())
},
Ok(None) => continue,
Err(e) => {
let message = format!("Error parsing command: {}", e);
let html_message = format!("<p><strong>{}</strong></p>", message);
(message, html_message)
},
};
let plain = format!("{}\n{}", sender, plain);
let html = format!("<p>{}</p>\n{}", sender, plain);
let message = NoticeMessage {
body: plain,
format: Some("org.matrix.custom.html".into()),
formatted_body: Some(html),
};
self.txn_id += 1;
let mut send_url = self.url(format!("/_matrix/client/r0/rooms/{}/send/m.room.message/{}", room_id, self.txn_id), &[]);
self.client
.put(send_url)
.header("user-agent", USER_AGENT)
.body(serde_json::to_string(&message)?)
.send()
.await?;
}
}
}
@ -155,6 +190,7 @@ impl DiceBot {
.await?;
self.config.matrix.next_batch = self.next_batch;
self.config.matrix.txn_id = self.txn_id;
if let Some(config_path) = self.config_path {
let config = toml::to_string_pretty(&self.config)?;

View File

@ -29,13 +29,16 @@ impl Command for RollCommand {
let roll = self.0.roll();
let plain = format!("Dice: {}\nResult: {}", self.0, roll);
let html = format!(
"<strong>Dice:</strong> {}<br><strong>Result</strong>: {}",
"<p><strong>Dice:</strong> {}</p><p><strong>Result</strong>: {}</p>",
self.0, roll
);
Execution { plain, html }
}
}
/// Parse a command string into a dynamic command execution trait object.
/// Returns an error if a command was recognized but not parsed correctly. Returns None if no
/// command was recognized.
pub fn parse_command(s: &str) -> Result<Option<Box<dyn Command>>, String> {
// Ignore trailing input, if any.
match parser::parse_command(s) {

View File

@ -1,11 +1,30 @@
use serde::{self, Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "msgtype")]
#[serde(rename = "m.notice")]
pub struct NoticeMessage {
pub body: String,
#[serde(default)]
pub format: Option<String>,
#[serde(default)]
pub formatted_body: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "msgtype")]
#[serde(rename = "m.text")]
pub struct TextMessage {
body: String,
#[serde(default)]
format: Option<String>,
#[serde(default)]
formatted_body: Option<String>,
}
impl TextMessage {
@ -26,6 +45,7 @@ pub enum MessageContent {
pub struct RoomEvent {
pub content: MessageContent,
pub event_id: String,
pub sender: String,
}
#[derive(Serialize, Deserialize, Debug)]