121 lines
3.6 KiB
Rust

use std::time::Duration;
use anyhow::Result;
use log::{debug, error};
use matrix_sdk::{
Client, Room, RoomState,
event_handler::Ctx,
ruma::events::room::{
member::StrippedRoomMemberEvent,
message::{MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent},
},
};
use tokio::time::sleep;
use super::Context;
use crate::{
events::call_listeners,
lua::{eval, exec, matrix::room::Room as LuaRoom, reload},
};
pub async fn on_regular_room_message(
event: OriginalSyncRoomMessageEvent,
room: Room,
ctx: Ctx<Context>,
) -> Result<()> {
if room.state() != RoomState::Joined {
return Ok(());
}
let MessageType::Text(text_content) = event.content.msgtype else {
return Ok(());
};
if text_content.body.starts_with(&ctx.name) && ctx.is_owner(&event.sender.to_string()) {
let body = text_content.body[ctx.name.len()..]
.trim_start_matches(':')
.trim();
let split = body.split_once(char::is_whitespace).unzip();
let code = split
.1
.map(|body| body.trim_start_matches("```lua").trim_matches(['`', '\n']));
let mut output = None;
match split.0.unwrap_or(body).to_lowercase().as_str() {
"reload" => {
output = Some(
reload(&ctx.state.lua, None)
.map_or_else(|error| error.to_string(), |()| String::from("ok")),
);
}
"eval" if let Some(code) = code => {
output = Some(
eval(&ctx.state.lua, code, None)
.await
.unwrap_or_else(|error| error.to_string()),
);
}
"exec" if let Some(code) = code => {
output = Some(
exec(&ctx.state.lua, code, None)
.await
.map_or_else(|error| error.to_string(), |()| String::from("ok")),
);
}
"ping" => {
room.send(RoomMessageEventContent::text_plain("pong!"))
.await?;
}
_ => (),
}
if let Some(output) = output {
room.send(RoomMessageEventContent::text_html(
&output,
format!("<pre><code>{output}</code></pre>"),
))
.await?;
}
}
call_listeners(&ctx.state, "matrix_chat", || {
let table = ctx.state.lua.create_table()?;
table.set("room", LuaRoom(room))?;
table.set("sender_id", event.sender.to_string())?;
table.set("body", text_content.body)?;
Ok(table)
})
.await
}
pub async fn on_stripped_state_member(
member: StrippedRoomMemberEvent,
client: Client,
room: Room,
ctx: Ctx<Context>,
) -> Result<()> {
if let Some(user_id) = client.user_id()
&& member.state_key == user_id
&& ctx.is_owner(&member.sender.to_string())
{
debug!("joining room {}", room.room_id());
while let Err(error) = room.join().await {
error!(
"failed to join room {}: {error:?}, retrying...",
room.room_id()
);
sleep(Duration::from_secs(10)).await;
}
debug!("successfully joined room {}", room.room_id());
call_listeners(&ctx.state, "matrix_join_room", || {
let table = ctx.state.lua.create_table()?;
table.set("room", LuaRoom(room))?;
table.set("sender", member.sender.to_string())?;
Ok(table)
})
.await?;
}
Ok(())
}