~alarsyo/patches

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
4

[PATCH bad-news v3 0/4] Fixing infinite recursion

Details
Message ID
<20210410000120.1242940-1-bruno@belanyi.fr>
DKIM signature
missing
Download raw message
So turns out my previous patchset did an infinite recursion when trying
to deserialize the configuration file. The fix was quiet simple, as
usual in CS it was simply to add another level of indirection.

-- 
2.31.1

[PATCH bad-news v3 1/4] config: extract Config into its own file

Details
Message ID
<20210410000120.1242940-2-bruno@belanyi.fr>
In-Reply-To
<20210410000120.1242940-1-bruno@belanyi.fr> (view parent)
DKIM signature
missing
Download raw message
Patch: +25 -22
---
 src/config.rs | 23 +++++++++++++++++++++++
 src/main.rs   | 24 ++----------------------
 2 files changed, 25 insertions(+), 22 deletions(-)
 create mode 100644 src/config.rs

diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..9d99a37
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,23 @@
use matrix_sdk::identifiers::RoomId;
use serde::Deserialize;
use std::collections::HashSet;
use std::path::PathBuf;
use url::Url;

/// 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
    pub units: HashSet<String>,
}
diff --git a/src/main.rs b/src/main.rs
index dee3102..877d58e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,20 +1,18 @@
use std::{
    collections::HashSet,
    fs::File,
    io::{self, BufReader},
    path::PathBuf,
};

use clap::Clap;
use matrix_sdk::identifiers::RoomId;
use serde::Deserialize;
use thiserror::Error;
use url::Url;

mod autojoin;
mod bot;
mod config;

use bot::BadNewsBot;
use config::Config;

#[derive(Error, Debug)]
enum BadNewsError {
@@ -32,24 +30,6 @@ struct Opts {
    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]
async fn main() -> anyhow::Result<()> {
    tracing_subscriber::fmt::init();
-- 
2.31.1

[PATCH bad-news v3 2/4] config: add optional filter option for units

Details
Message ID
<20210410000120.1242940-3-bruno@belanyi.fr>
In-Reply-To
<20210410000120.1242940-1-bruno@belanyi.fr> (view parent)
DKIM signature
missing
Download raw message
Patch: +82 -4
This allows the user to write:

```yaml
units:
- foo.service
- bar.service
- name: baz.service
  filter: "^Error: .*$"
```

So a unit can be provided as a string, or as a map which contains both
`name` and `filter`.
---
 Cargo.lock    |  7 +++++
 Cargo.toml    |  1 +
 src/bot.rs    |  2 +-
 src/config.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index c41772e..e2fbccb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -139,6 +139,7 @@ dependencies = [
 "tokio",
 "tracing-subscriber",
 "url",
 "void",
]

[[package]]
@@ -2365,6 +2366,12 @@ version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"

[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"

[[package]]
name = "want"
version = "0.3.0"
diff --git a/Cargo.toml b/Cargo.toml
index 7fe7e51..eb687c7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,6 +17,7 @@ serde_yaml = "0.8"
serde = "1.0"
systemd = "0.8"
thiserror = "1.0"
void = "1"

[dependencies.matrix-sdk]
git = "https://github.com/matrix-org/matrix-rust-sdk"
diff --git a/src/bot.rs b/src/bot.rs
index b2a6387..aa97d32 100644
--- a/src/bot.rs
+++ b/src/bot.rs
@@ -100,7 +100,7 @@ impl BadNewsBot {
        const KEY_MESSAGE: &str = "MESSAGE";

        if let Some(unit) = record.get(KEY_UNIT) {
            if !self.config.units.contains(unit) {
            if !self.config.units.iter().map(|u| &u.name).any(|name| name == unit) {
                return;
            }

diff --git a/src/config.rs b/src/config.rs
index 9d99a37..0a06c3a 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,8 +1,12 @@
use matrix_sdk::identifiers::RoomId;
use serde::Deserialize;
use std::collections::HashSet;
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)]
@@ -19,5 +23,71 @@ pub struct Config {
    /// invitations to this room.
    pub room_id: RoomId,
    /// Units to watch for logs
    pub units: HashSet<String>,
    pub units: Vec<Unit>,
}

/// Holds a single unit's configuration.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
#[serde(from = "SerializedUnit")]
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.
    pub filter: Option<String>, // FIXME: regex
}

#[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 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))
}
-- 
2.31.1

[PATCH bad-news v3 3/4] config: store and parse 'filter' as regex

Details
Message ID
<20210410000120.1242940-4-bruno@belanyi.fr>
In-Reply-To
<20210410000120.1242940-1-bruno@belanyi.fr> (view parent)
DKIM signature
missing
Download raw message
Patch: +38 -2
---
 Cargo.lock    | 24 ++++++++++++++++++++++++
 Cargo.toml    |  2 ++
 src/config.rs | 14 ++++++++++++--
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index e2fbccb..a615ff6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -66,6 +66,15 @@ dependencies = [
 "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]]
name = "ansi_term"
version = "0.12.1"
@@ -132,7 +141,9 @@ dependencies = [
 "clap",
 "futures",
 "matrix-sdk",
 "regex",
 "serde",
 "serde_regex",
 "serde_yaml",
 "systemd",
 "thiserror",
@@ -1439,7 +1450,10 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [
 "aho-corasick",
 "memchr",
 "regex-syntax",
 "thread_local",
]

[[package]]
@@ -1774,6 +1788,16 @@ dependencies = [
 "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]]
name = "serde_urlencoded"
version = "0.7.0"
diff --git a/Cargo.toml b/Cargo.toml
index eb687c7..8004b32 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,9 +10,11 @@ edition = "2018"
anyhow = "1.0"
clap = "3.0.0-beta.2"
futures = "0.3"
regex = "1"
tokio = { version = "1", features = [ "full" ] }
tracing-subscriber = "0.2"
url = { version = "2.2", features = [ "serde" ] }
serde_regex = "1"
serde_yaml = "0.8"
serde = "1.0"
systemd = "0.8"
diff --git a/src/config.rs b/src/config.rs
index 0a06c3a..0a4e40b 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,4 +1,5 @@
use matrix_sdk::identifiers::RoomId;
use regex::Regex;
use serde::de::{self, MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::fmt;
@@ -27,15 +28,24 @@ pub struct Config {
}

/// Holds a single unit's configuration.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
#[derive(Clone, Debug, Deserialize)]
#[serde(from = "SerializedUnit")]
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.
    pub filter: Option<String>, // FIXME: regex
    #[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);
-- 
2.31.1

[PATCH bad-news v3 4/4] bot: apply service filters

Details
Message ID
<20210410000120.1242940-5-bruno@belanyi.fr>
In-Reply-To
<20210410000120.1242940-1-bruno@belanyi.fr> (view parent)
DKIM signature
missing
Download raw message
Patch: +18 -2
---
 src/bot.rs    | 10 +++++++++-
 src/config.rs | 10 +++++++++-
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/src/bot.rs b/src/bot.rs
index aa97d32..eb833db 100644
--- a/src/bot.rs
+++ b/src/bot.rs
@@ -100,11 +100,19 @@ impl BadNewsBot {
        const KEY_MESSAGE: &str = "MESSAGE";

        if let Some(unit) = record.get(KEY_UNIT) {
            if !self.config.units.iter().map(|u| &u.name).any(|name| name == unit) {
            let unit_config = self.config.units.iter().find(|u| &u.name == unit);
            if unit_config.is_none() {
                return;
            }
            let unit_config = unit_config.unwrap();

            let message = record.get(KEY_MESSAGE);
            if let Some(filter) = &unit_config.filter {
                if message.is_none() || !filter.is_match(message.unwrap()) {
                    return;
                }
            }

            let message = format!(
                "[{}] {}",
                unit.strip_suffix(".service").unwrap_or(unit),
diff --git a/src/config.rs b/src/config.rs
index 0a4e40b..ffa367b 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -24,12 +24,12 @@ pub struct Config {
    /// 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)]
#[serde(from = "SerializedUnit")]
pub struct Unit {
    /// Can be serialized from a string only instead of a map.
    pub name: String,
@@ -67,6 +67,14 @@ impl FromStr for Unit {
    }
}

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>,
-- 
2.31.1
Reply to thread Export thread (mbox)