2022-11-13 00:19:16 +01:00
|
|
|
#![forbid(unsafe_code)]
|
|
|
|
#![deny(unused_must_use)]
|
|
|
|
#![warn(clippy::pedantic, clippy::as_conversions)]
|
|
|
|
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
|
|
|
use bot::{Bot, Config};
|
|
|
|
use clap::Parser as _;
|
|
|
|
use color_eyre::{eyre::Context, Result};
|
|
|
|
use matrix_sdk::Session;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use tracing::instrument;
|
|
|
|
use xdg::BaseDirectories;
|
|
|
|
|
|
|
|
mod bot;
|
|
|
|
mod its_api;
|
|
|
|
mod setup;
|
|
|
|
|
|
|
|
/// The session data required by the bot to log in. Stored as TOML at the path
|
|
|
|
/// given by [`session_path()`].
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
|
|
pub struct SessionData {
|
|
|
|
pub homeserver_url: Option<String>,
|
|
|
|
pub session: Session,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(clap::Parser)]
|
|
|
|
struct Cli {
|
2022-11-13 00:40:18 +01:00
|
|
|
/// Override path to the bot's configuration file
|
2022-11-13 00:19:16 +01:00
|
|
|
#[arg(long, short = 'c')]
|
|
|
|
config: Option<PathBuf>,
|
|
|
|
#[command(subcommand)]
|
2022-11-13 00:40:18 +01:00
|
|
|
sub: Subcommand,
|
2022-11-13 00:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(clap::Subcommand, Debug)]
|
|
|
|
enum Subcommand {
|
|
|
|
Setup(setup::Setup),
|
2022-11-13 00:40:18 +01:00
|
|
|
/// Run the bot
|
|
|
|
Run,
|
2022-11-13 00:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the default path to the bot's configuration file.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// Returns an error if the directory containing the configuration file
|
|
|
|
/// could not be created.
|
|
|
|
fn default_config_path() -> Result<PathBuf> {
|
|
|
|
let base_dirs = BaseDirectories::with_prefix("its-matrix-bot")?;
|
|
|
|
let path = base_dirs.place_config_file("config.toml")?;
|
|
|
|
|
|
|
|
Ok(path)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the path to the bot's session file.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// Returns an error if the directory containing the session file
|
|
|
|
/// could not be created.
|
|
|
|
fn session_path() -> Result<PathBuf> {
|
|
|
|
let base_dirs = BaseDirectories::with_prefix("its-matrix-bot")?;
|
|
|
|
let path = base_dirs.place_data_file("state.toml")?;
|
|
|
|
|
|
|
|
Ok(path)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the path to the bot's internal database.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// Returns an error if no base directory could be determined (e.g. because
|
|
|
|
/// no home directory is set).
|
|
|
|
fn sled_store_path() -> Result<PathBuf> {
|
|
|
|
let base_dirs = BaseDirectories::with_prefix("gavel")?;
|
|
|
|
Ok(base_dirs.get_data_home())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[instrument]
|
|
|
|
async fn load_config(path: &Path) -> Result<Config> {
|
|
|
|
let config = toml::from_str(&tokio::fs::read_to_string(path).await?)?;
|
|
|
|
|
|
|
|
Ok(config)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn install_tracing() {
|
|
|
|
use tracing_subscriber::{
|
|
|
|
prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, EnvFilter,
|
|
|
|
};
|
|
|
|
|
|
|
|
let fmt_layer = tracing_subscriber::fmt::layer().with_target(false);
|
|
|
|
let filter_layer = tracing_subscriber::EnvFilter::try_from_default_env()
|
|
|
|
.or_else(|_| EnvFilter::try_from("info"))
|
|
|
|
.unwrap();
|
|
|
|
let error_layer = tracing_error::ErrorLayer::default();
|
|
|
|
|
|
|
|
tracing_subscriber::registry()
|
|
|
|
.with(fmt_layer)
|
|
|
|
.with(filter_layer)
|
|
|
|
.with(error_layer)
|
|
|
|
.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() -> Result<()> {
|
|
|
|
install_tracing();
|
|
|
|
color_eyre::install()?;
|
|
|
|
|
|
|
|
let args = Cli::parse();
|
|
|
|
|
|
|
|
match args.sub {
|
2022-11-13 00:40:18 +01:00
|
|
|
Subcommand::Setup(setup) => {
|
2022-11-13 00:19:16 +01:00
|
|
|
setup::setup(setup).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-11-13 00:40:18 +01:00
|
|
|
Subcommand::Run => {
|
2022-11-13 00:19:16 +01:00
|
|
|
let config_path = if let Some(config) = args.config {
|
|
|
|
config
|
|
|
|
} else {
|
|
|
|
default_config_path()?
|
|
|
|
};
|
|
|
|
|
|
|
|
let config = load_config(&config_path)
|
|
|
|
.await
|
|
|
|
.wrap_err("Failed to load bot configuration")?;
|
|
|
|
|
|
|
|
let bot = Bot::new(config).await?;
|
|
|
|
bot.run().await?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|