Compare commits

..

No commits in common. "1e1dff9ab01c937cddf358a5b595e733831ff758" and "6f155bba0bee4cb9aff5d33eb18eba5cecc701af" have entirely different histories.

5 changed files with 26 additions and 162 deletions

31
Cargo.lock generated
View file

@ -66,15 +66,6 @@ dependencies = [
"opaque-debug", "opaque-debug",
] ]
[[package]]
name = "aho-corasick"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.12.1" version = "0.12.1"
@ -141,16 +132,13 @@ dependencies = [
"clap", "clap",
"futures", "futures",
"matrix-sdk", "matrix-sdk",
"regex",
"serde", "serde",
"serde_regex",
"serde_yaml", "serde_yaml",
"systemd", "systemd",
"thiserror", "thiserror",
"tokio", "tokio",
"tracing-subscriber", "tracing-subscriber",
"url", "url",
"void",
] ]
[[package]] [[package]]
@ -1450,10 +1438,7 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [ dependencies = [
"aho-corasick",
"memchr",
"regex-syntax", "regex-syntax",
"thread_local",
] ]
[[package]] [[package]]
@ -1788,16 +1773,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_regex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf"
dependencies = [
"regex",
"serde",
]
[[package]] [[package]]
name = "serde_urlencoded" name = "serde_urlencoded"
version = "0.7.0" version = "0.7.0"
@ -2390,12 +2365,6 @@ version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]] [[package]]
name = "want" name = "want"
version = "0.3.0" version = "0.3.0"

View file

@ -10,16 +10,13 @@ edition = "2018"
anyhow = "1.0" anyhow = "1.0"
clap = "3.0.0-beta.2" clap = "3.0.0-beta.2"
futures = "0.3" futures = "0.3"
regex = "1"
tokio = { version = "1", features = [ "full" ] } tokio = { version = "1", features = [ "full" ] }
tracing-subscriber = "0.2" tracing-subscriber = "0.2"
url = { version = "2.2", features = [ "serde" ] } url = { version = "2.2", features = [ "serde" ] }
serde_regex = "1"
serde_yaml = "0.8" serde_yaml = "0.8"
serde = "1.0" serde = "1.0"
systemd = "0.8" systemd = "0.8"
thiserror = "1.0" thiserror = "1.0"
void = "1"
[dependencies.matrix-sdk] [dependencies.matrix-sdk]
git = "https://github.com/matrix-org/matrix-rust-sdk" git = "https://github.com/matrix-org/matrix-rust-sdk"

View file

@ -100,26 +100,15 @@ impl BadNewsBot {
const KEY_MESSAGE: &str = "MESSAGE"; const KEY_MESSAGE: &str = "MESSAGE";
if let Some(unit) = record.get(KEY_UNIT) { if let Some(unit) = record.get(KEY_UNIT) {
let unit_config = match self.config.units.iter().find(|u| &u.name == unit) { if !self.config.units.contains(unit) {
Some(config) => config, return;
None => return,
};
let message = match record.get(KEY_MESSAGE) {
Some(msg) => msg,
None => return,
};
if let Some(filter) = &unit_config.filter {
if !filter.is_match(message) {
return;
}
} }
let message = record.get(KEY_MESSAGE);
let message = format!( let message = format!(
"[{}] {}", "[{}] {}",
unit.strip_suffix(".service").unwrap_or(unit), unit.strip_suffix(".service").unwrap_or(unit),
message, message.map(|m| m.as_ref()).unwrap_or("<EMPTY MESSAGE>")
); );
let content = AnyMessageEventContent::RoomMessage(MessageEventContent::Text( let content = AnyMessageEventContent::RoomMessage(MessageEventContent::Text(
TextMessageEventContent::plain(message), TextMessageEventContent::plain(message),

View file

@ -1,111 +0,0 @@
use matrix_sdk::identifiers::RoomId;
use regex::Regex;
use serde::de::{self, MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::fmt;
use std::marker::PhantomData;
use std::path::PathBuf;
use std::str::FromStr;
use url::Url;
use void::Void;
/// Holds the configuration for the bot.
#[derive(Clone, Deserialize)]
pub struct Config {
/// The URL for the homeserver we should connect to
pub homeserver: Url,
/// The bot's account username
pub username: String,
/// The bot's account password
pub password: String,
/// Path to a directory where the bot will store Matrix state and current session information.
pub state_dir: PathBuf,
/// ID of the Matrix room where the bot should post messages. The bot will only accept
/// invitations to this room.
pub room_id: RoomId,
/// Units to watch for logs
#[serde(deserialize_with = "list_of_units")]
pub units: Vec<Unit>,
}
/// Holds a single unit's configuration.
#[derive(Clone, Debug, Deserialize)]
pub struct Unit {
/// Can be serialized from a string only instead of a map.
pub name: String,
/// Regex to filter each line read from the unit's logs.
#[serde(with = "serde_regex")]
pub filter: Option<Regex>,
}
impl PartialEq for Unit {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Eq for Unit {}
#[derive(Debug, Deserialize)]
#[serde(transparent)]
struct SerializedUnit(#[serde(deserialize_with = "unit_name_or_struct")] Unit);
impl From<SerializedUnit> for Unit {
fn from(s: SerializedUnit) -> Self {
s.0
}
}
impl FromStr for Unit {
type Err = Void;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Unit {
name: s.to_string(),
filter: None,
})
}
}
fn list_of_units<'de, D>(deserializer: D) -> Result<Vec<Unit>, D::Error>
where
D: Deserializer<'de>,
{
let units: Vec<SerializedUnit> = Deserialize::deserialize(deserializer)?;
Ok(units.into_iter().map(From::from).collect())
}
fn unit_name_or_struct<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: Deserialize<'de> + FromStr<Err = Void>,
D: Deserializer<'de>,
{
struct StringOrStruct<T>(PhantomData<fn() -> T>);
impl<'de, T> Visitor<'de> for StringOrStruct<T>
where
T: Deserialize<'de> + FromStr<Err = Void>,
{
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string or map")
}
fn visit_str<E>(self, value: &str) -> Result<T, E>
where
E: de::Error,
{
Ok(FromStr::from_str(value).unwrap())
}
fn visit_map<M>(self, map: M) -> Result<T, M::Error>
where
M: MapAccess<'de>,
{
Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))
}
}
deserializer.deserialize_any(StringOrStruct(PhantomData))
}

View file

@ -1,18 +1,20 @@
use std::{ use std::{
collections::HashSet,
fs::File, fs::File,
io::{self, BufReader}, io::{self, BufReader},
path::PathBuf, path::PathBuf,
}; };
use clap::Clap; use clap::Clap;
use matrix_sdk::identifiers::RoomId;
use serde::Deserialize;
use thiserror::Error; use thiserror::Error;
use url::Url;
mod autojoin; mod autojoin;
mod bot; mod bot;
mod config;
use bot::BadNewsBot; use bot::BadNewsBot;
use config::Config;
#[derive(Error, Debug)] #[derive(Error, Debug)]
enum BadNewsError { enum BadNewsError {
@ -30,6 +32,24 @@ struct Opts {
config: PathBuf, config: PathBuf,
} }
/// Holds the configuration for the bot.
#[derive(Clone, Deserialize)]
pub struct Config {
/// The URL for the homeserver we should connect to
homeserver: Url,
/// The bot's account username
username: String,
/// The bot's account password
password: String,
/// Path to a directory where the bot will store Matrix state and current session information.
state_dir: PathBuf,
/// ID of the Matrix room where the bot should post messages. The bot will only accept
/// invitations to this room.
room_id: RoomId,
/// Units to watch for logs
units: HashSet<String>,
}
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();