Compare commits
8 commits
17d076ed45
...
10157a24db
Author | SHA1 | Date | |
---|---|---|---|
10157a24db | |||
c9754bc00a | |||
eec42ec369 | |||
ff1b69a198 | |||
6eadec73e8 | |||
8f0c762637 | |||
4d06a1df84 | |||
27214dbc34 |
5 changed files with 996 additions and 653 deletions
1537
Cargo.lock
generated
1537
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
10
Cargo.toml
10
Cargo.toml
|
@ -16,11 +16,11 @@ matrix-sdk = { version = "0.6.2", features = ["e2e-encryption"] }
|
||||||
never-say-never = "6.6.666"
|
never-say-never = "6.6.666"
|
||||||
reqwest = { version = "0.11.12", features = ["json"] }
|
reqwest = { version = "0.11.12", features = ["json"] }
|
||||||
serde = { version = "1.0.147", features = ["derive"] }
|
serde = { version = "1.0.147", features = ["derive"] }
|
||||||
spaceapi = "0.8.1"
|
spaceapi = "0.9.0"
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
time = "0.3.17"
|
time = { version = "0.3.17", features = ["local-offset", "formatting", "macros"] }
|
||||||
tokio = { version = "1.21.2", features = ["full"] }
|
tokio = { version = "1.21.2", features = ["full"] }
|
||||||
toml = "0.5.9"
|
toml = "0.7.6"
|
||||||
url = { version = "2.3.1", features = ["serde"] }
|
url = { version = "2.3.1", features = ["serde"] }
|
||||||
xdg = "2.4.1"
|
xdg = "2.4.1"
|
||||||
|
|
||||||
|
@ -29,7 +29,3 @@ color-eyre = "0.6.2"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
tracing-error = "0.2.0"
|
tracing-error = "0.2.0"
|
||||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
# https://github.com/spaceapi-community/spaceapi-rs/pull/111
|
|
||||||
spaceapi = { git = "https://github.com/Xiretza/spaceapi-rs", branch = "icon-closed-fix" }
|
|
||||||
|
|
92
src/bot.rs
92
src/bot.rs
|
@ -25,7 +25,7 @@ use matrix_sdk::{
|
||||||
use never_say_never::Never;
|
use never_say_never::Never;
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use time::OffsetDateTime;
|
use time::{ext::NumericalDuration, macros::format_description, OffsetDateTime, UtcOffset};
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use tracing::{event, instrument, span, Level};
|
use tracing::{event, instrument, span, Level};
|
||||||
|
|
||||||
|
@ -179,6 +179,7 @@ impl Bot {
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collects the configured announcement rooms and joins them if necessary.
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
async fn join_announce_rooms(&mut self) -> Result<()> {
|
async fn join_announce_rooms(&mut self) -> Result<()> {
|
||||||
for room in &self.config.space.announce_rooms {
|
for room in &self.config.space.announce_rooms {
|
||||||
|
@ -205,6 +206,59 @@ impl Bot {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, ev, room))]
|
||||||
|
async fn handle_command(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
ev: &OriginalRoomMessageEvent,
|
||||||
|
room: &Joined,
|
||||||
|
command: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
let reply = |msg: &str| {
|
||||||
|
// workaround for broken IRC bridge
|
||||||
|
// https://github.com/matrix-org/matrix-appservice-irc/issues/683#issuecomment-1312688727
|
||||||
|
let msg = format!("\n{msg}");
|
||||||
|
|
||||||
|
room.send(
|
||||||
|
RoomMessageEventContent::text_plain(msg).make_reply_to(ev),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
match command {
|
||||||
|
"isitopen" => {
|
||||||
|
match self.update_open_state().await? {
|
||||||
|
OpenState::Open { since } => {
|
||||||
|
if let Ok(offset) = UtcOffset::current_local_offset() {
|
||||||
|
let since = since.to_offset(offset);
|
||||||
|
|
||||||
|
let s = if OffsetDateTime::now_utc() - since > 20.hours() {
|
||||||
|
since.format(format_description!(
|
||||||
|
"[year]-[month]-[day] [hour]:[minute]:[second]"
|
||||||
|
))?
|
||||||
|
} else {
|
||||||
|
since.format(format_description!("[hour]:[minute]:[second]"))?
|
||||||
|
};
|
||||||
|
|
||||||
|
reply(&format!("positive! space has been open since {s}")).await?
|
||||||
|
} else {
|
||||||
|
reply(&format!("positive! space has been open since {since}")).await?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OpenState::Closed => reply("negative!").await?,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"spaceping" => {
|
||||||
|
self.api.ping().await?;
|
||||||
|
reply("Hello Space!").await?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
reply("Unknown command").await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
async fn handle_message(
|
async fn handle_message(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
|
@ -227,41 +281,24 @@ impl Bot {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let reply = |msg: &str| {
|
if let Err(error) = self.handle_command(ev, room, command).await {
|
||||||
// workaround for broken IRC bridge
|
event!(Level::WARN, ?error, "handling command failed");
|
||||||
// https://github.com/matrix-org/matrix-appservice-irc/issues/683#issuecomment-1312688727
|
let _ignore = room
|
||||||
let msg = format!("\n{msg}");
|
.send(
|
||||||
|
RoomMessageEventContent::text_plain("error handling command: {error}"),
|
||||||
room.send(
|
|
||||||
RoomMessageEventContent::text_plain(msg).make_reply_to(ev),
|
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
.await;
|
||||||
};
|
};
|
||||||
|
|
||||||
match command {
|
|
||||||
"isitopen" => {
|
|
||||||
match self.update_open_state().await? {
|
|
||||||
OpenState::Open { since } => {
|
|
||||||
reply(&format!("positive! space has been open since {since}")).await?
|
|
||||||
}
|
|
||||||
OpenState::Closed => reply("negative!").await?,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
"spaceping" => {
|
|
||||||
self.api.ping().await?;
|
|
||||||
reply("Hello Space!").await?;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
reply("Unknown command").await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the bot. This function does not return except in case of error.
|
/// Runs the bot. This function does not return except in case of error.
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
pub async fn run(mut self) -> Result<Never> {
|
pub async fn run(mut self) -> Result<Never> {
|
||||||
|
self.client.sync_once(SyncSettings::default()).await?;
|
||||||
|
|
||||||
self.join_announce_rooms()
|
self.join_announce_rooms()
|
||||||
.await
|
.await
|
||||||
.wrap_err("failed to join announcement rooms")?;
|
.wrap_err("failed to join announcement rooms")?;
|
||||||
|
@ -297,7 +334,8 @@ impl Bot {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.client.sync(SyncSettings::default()).await?;
|
// Box humongous future
|
||||||
|
Box::pin(this.client.sync(SyncSettings::default())).await?;
|
||||||
unreachable!("sync() returned unexpectedly")
|
unreachable!("sync() returned unexpectedly")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use clap::Parser as _;
|
||||||
use color_eyre::{eyre::Context, Result};
|
use color_eyre::{eyre::Context, Result};
|
||||||
use matrix_sdk::Session;
|
use matrix_sdk::Session;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::instrument;
|
use tracing::{instrument, event, Level};
|
||||||
use xdg::BaseDirectories;
|
use xdg::BaseDirectories;
|
||||||
|
|
||||||
mod bot;
|
mod bot;
|
||||||
|
@ -126,6 +126,8 @@ async fn main() -> Result<()> {
|
||||||
.wrap_err("Failed to load bot configuration")?;
|
.wrap_err("Failed to load bot configuration")?;
|
||||||
|
|
||||||
let bot = Bot::new(config).await?;
|
let bot = Bot::new(config).await?;
|
||||||
|
|
||||||
|
event!(Level::INFO, "logged in successfully, starting bot");
|
||||||
bot.run().await?
|
bot.run().await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub(crate) async fn setup(setup: Setup) -> Result<()> {
|
||||||
homeserver_url: setup.homeserver_url,
|
homeserver_url: setup.homeserver_url,
|
||||||
};
|
};
|
||||||
|
|
||||||
tokio::fs::write(crate::session_path()?, toml::to_vec(&data)?).await?;
|
tokio::fs::write(crate::session_path()?, toml::to_string(&data)?).await?;
|
||||||
|
|
||||||
client.sync_once(SyncSettings::default()).await?;
|
client.sync_once(SyncSettings::default()).await?;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue