Compare commits
No commits in common. "1e1dff9ab01c937cddf358a5b595e733831ff758" and "6f155bba0bee4cb9aff5d33eb18eba5cecc701af" have entirely different histories.
1e1dff9ab0
...
6f155bba0b
31
Cargo.lock
generated
31
Cargo.lock
generated
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
19
src/bot.rs
19
src/bot.rs
|
@ -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),
|
||||||
|
|
111
src/config.rs
111
src/config.rs
|
@ -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))
|
|
||||||
}
|
|
24
src/main.rs
24
src/main.rs
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue