Skip to content

Commit 4299e7e

Browse files
committed
Allow platform-specific extra NotificationOption
1 parent 39756b0 commit 4299e7e

File tree

5 files changed

+107
-63
lines changed

5 files changed

+107
-63
lines changed

src/config/mod.rs

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use crate::{
1717
notify::NotifierConfig,
1818
platform::*,
1919
reporter::{ConfigReporterRaw, ReporterParams},
20-
serde_impl_default_for,
2120
source::SourceConfig,
2221
};
2322

@@ -191,17 +190,21 @@ pub struct SubscriptionRef<'a> {
191190

192191
// Should be always used with `#[serde(flatten)]`
193192
#[derive(Clone, Debug, PartialEq, Deserialize)]
194-
pub struct NotifierBase {
193+
pub struct NotifierBase<O = ()> {
195194
#[serde(default)]
196195
pub switch: NotificationSwitch,
197196
#[serde(default)]
198-
pub option: NotificationOption,
197+
pub option: NotificationOption<O>,
199198
}
200199

201-
serde_impl_default_for!(NotifierBase);
200+
impl<'a, O: Default + Deserialize<'a>> Default for NotifierBase<O> {
201+
fn default() -> Self {
202+
helper::serde_default()
203+
}
204+
}
202205

203-
impl Overridable for NotifierBase {
204-
type Override = NotifierBaseOverride;
206+
impl<'a, O: Deserialize<'a> + Overridable> Overridable for NotifierBase<O> {
207+
type Override = NotifierBaseOverride<O::Override>;
205208

206209
fn override_into(self, new: Self::Override) -> Self
207210
where
@@ -222,9 +225,9 @@ impl Overridable for NotifierBase {
222225

223226
// Should be always used with `#[serde(flatten)]`
224227
#[derive(Clone, Debug, PartialEq, Deserialize)]
225-
pub struct NotifierBaseOverride {
228+
pub struct NotifierBaseOverride<O = ()> {
226229
switch: Option<NotificationSwitchOverride>,
227-
option: Option<NotificationOptionOverride>,
230+
option: Option<NotificationOptionOverride<O>>,
228231
}
229232

230233
#[derive(Clone, Debug, PartialEq, Deserialize)]
@@ -243,7 +246,11 @@ pub struct NotificationSwitch {
243246
pub document: bool,
244247
}
245248

246-
serde_impl_default_for!(NotificationSwitch);
249+
impl Default for NotificationSwitch {
250+
fn default() -> Self {
251+
helper::serde_default()
252+
}
253+
}
247254

248255
impl Overridable for NotificationSwitch {
249256
type Override = NotificationSwitchOverride;
@@ -274,37 +281,41 @@ pub struct NotificationSwitchOverride {
274281
}
275282

276283
#[derive(Clone, Debug, PartialEq, Deserialize)]
277-
pub struct NotificationOption {
284+
pub struct NotificationOption<O> {
278285
#[serde(default = "helper::refl_bool::<false>")]
279286
pub author_name: bool,
280-
281-
// TODO: For temporary use on QQ platform, due to demand from a particular user. We eventually
282-
// want to support custom text via pattern templates (similar to spdlog-rs, but more generic).
283-
// And because they are temporary, we do not currently support their overriding.
284-
pub __live_text: Option<String>,
285-
pub __post_text: Option<String>,
287+
#[serde(default, flatten)]
288+
pub ext: O,
286289
}
287290

288-
serde_impl_default_for!(NotificationOption);
291+
impl<'a, O: Default + Deserialize<'a>> Default for NotificationOption<O> {
292+
fn default() -> Self {
293+
helper::serde_default()
294+
}
295+
}
289296

290-
impl Overridable for NotificationOption {
291-
type Override = NotificationOptionOverride;
297+
impl<'a, O: Deserialize<'a> + Overridable> Overridable for NotificationOption<O> {
298+
type Override = NotificationOptionOverride<O::Override>;
292299

293300
fn override_into(self, new: Self::Override) -> Self
294301
where
295302
Self: Sized,
296303
{
297304
Self {
298305
author_name: new.author_name.unwrap_or(self.author_name),
299-
__live_text: self.__live_text,
300-
__post_text: self.__post_text,
306+
ext: match new.ext {
307+
Some(ext) => self.ext.override_into(ext),
308+
None => self.ext,
309+
},
301310
}
302311
}
303312
}
304313

305314
#[derive(Clone, Debug, PartialEq, Deserialize)]
306-
pub struct NotificationOptionOverride {
315+
pub struct NotificationOptionOverride<O> {
307316
pub author_name: Option<bool>,
317+
#[serde(flatten)]
318+
pub ext: Option<O>,
308319
}
309320

310321
#[derive(Debug, PartialEq, Deserialize)]
@@ -470,8 +481,7 @@ notify = ["meow", "woof", { ref = "woof", id = 123 }]
470481
},
471482
option: NotificationOption {
472483
author_name: false,
473-
__live_text: None,
474-
__post_text: None,
484+
ext: ()
475485
}
476486
},
477487
chat: telegram::ConfigChat::Id(5678),

src/config/overridable.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
use serde::de::DeserializeOwned;
1+
use serde::Deserialize;
22

33
pub trait Overridable {
4-
type Override: DeserializeOwned;
4+
type Override: for<'a> Deserialize<'a>;
55

66
fn override_into(self, new: Self::Override) -> Self
77
where
88
Self: Sized;
99
}
10+
11+
impl Overridable for () {
12+
type Override = ();
13+
14+
fn override_into(self, _: Self::Override) -> Self {}
15+
}

src/helper.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::{convert::identity, path::Path, time::Duration};
33
use anyhow::{anyhow, ensure};
44
use humantime_serde::re::humantime;
55
use reqwest::header::{self, HeaderMap, HeaderValue};
6+
use serde::Deserialize;
67
use tokio::process::Command;
78

89
use crate::prop;
@@ -38,20 +39,13 @@ macro_rules! refl_fn {
3839

3940
refl_fn!(bool);
4041

41-
#[macro_export]
42-
macro_rules! serde_impl_default_for {
43-
( $struct:ident ) => {
44-
impl Default for $struct {
45-
fn default() -> Self {
46-
// https://stackoverflow.com/a/77858562
47-
Self::deserialize(serde::de::value::MapDeserializer::<
48-
_,
49-
serde::de::value::Error,
50-
>::new(std::iter::empty::<((), ())>()))
51-
.unwrap()
52-
}
53-
}
54-
};
42+
pub fn serde_default<'a, T: Default + Deserialize<'a>>() -> T {
43+
// https://stackoverflow.com/a/77858562
44+
T::deserialize(serde::de::value::MapDeserializer::<
45+
_,
46+
serde::de::value::Error,
47+
>::new(std::iter::empty::<((), ())>()))
48+
.unwrap()
5549
}
5650

5751
pub fn format_duration_in_sec(dur: Duration) -> String {

src/platform/qq/notify/mod.rs

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,39 @@ use crate::{
1515
},
1616
};
1717

18+
#[derive(Clone, Debug, PartialEq, Deserialize, Default)]
19+
pub struct OptionExt {
20+
// TODO: For temporary use on QQ platform, due to demand from a particular user. We eventually
21+
// want to support custom text via pattern templates (similar to spdlog-rs, but more generic).
22+
// And because they are temporary, we do not currently support their overriding.
23+
pub __live_text: Option<String>,
24+
pub __post_text: Option<String>,
25+
}
26+
27+
#[derive(Clone, Debug, PartialEq, Deserialize, Default)]
28+
pub struct OptionExtOverride {
29+
pub __live_text: Option<String>,
30+
pub __post_text: Option<String>,
31+
}
32+
33+
impl Overridable for OptionExt {
34+
type Override = OptionExtOverride;
35+
36+
fn override_into(self, new: Self::Override) -> Self
37+
where
38+
Self: Sized,
39+
{
40+
Self {
41+
__live_text: new.__live_text.or(self.__live_text),
42+
__post_text: new.__post_text.or(self.__post_text),
43+
}
44+
}
45+
}
46+
1847
#[derive(Clone, Debug, PartialEq, Deserialize)]
1948
pub struct ConfigParams {
2049
#[serde(default, flatten)]
21-
pub base: config::NotifierBase,
50+
pub base: config::NotifierBase<OptionExt>,
2251
#[serde(flatten)]
2352
pub chat: ConfigChat,
2453
#[serde(default)]
@@ -56,7 +85,7 @@ impl fmt::Display for ConfigParams {
5685
#[serde(deny_unknown_fields)]
5786
pub struct ConfigOverride {
5887
#[serde(flatten)]
59-
pub base: Option<config::NotifierBaseOverride>,
88+
pub base: Option<config::NotifierBaseOverride<OptionExtOverride>>,
6089
#[serde(flatten)]
6190
pub chat: Option<ConfigChat>,
6291
pub mention_all: Option<bool>,
@@ -151,23 +180,24 @@ impl Notifier {
151180

152181
if let LiveStatusKind::Online { start_time: _ } = live_status.kind {
153182
let builder = lagrange::Message::builder().image(&live_status.cover_image_url);
154-
let message = if let Some(custom_live_text) = &self.params.base.option.__live_text {
155-
builder.text(format!("{custom_live_text}\n{}", live_status.live_url))
156-
} else {
157-
builder.text(format!(
158-
"[{}] 🟢 {}{}\n{}",
159-
source.platform.display_name,
160-
if self.params.base.option.author_name {
161-
Cow::Owned(format!("[{}] ", live_status.streamer_name))
162-
} else {
163-
Cow::Borrowed("")
164-
},
165-
live_status.title,
166-
live_status.live_url
167-
))
168-
}
169-
.mention_all_if(self.params.mention_all, true)
170-
.build();
183+
let message =
184+
if let Some(custom_live_text) = &self.params.base.option.ext.__live_text {
185+
builder.text(format!("{custom_live_text}\n{}", live_status.live_url))
186+
} else {
187+
builder.text(format!(
188+
"[{}] 🟢 {}{}\n{}",
189+
source.platform.display_name,
190+
if self.params.base.option.author_name {
191+
Cow::Owned(format!("[{}] ", live_status.streamer_name))
192+
} else {
193+
Cow::Borrowed("")
194+
},
195+
live_status.title,
196+
live_status.live_url
197+
))
198+
}
199+
.mention_all_if(self.params.mention_all, true)
200+
.build();
171201
self.backend
172202
.send_message(&self.params.chat, message)
173203
.await?;
@@ -230,7 +260,7 @@ impl Notifier {
230260
async fn notify_post(&self, post: &Post, source: &StatusSource) -> anyhow::Result<()> {
231261
let mut builder = lagrange::Message::builder();
232262

233-
if let Some(custom_post_text) = &self.params.base.option.__post_text {
263+
if let Some(custom_post_text) = &self.params.base.option.ext.__post_text {
234264
builder.ref_text(custom_post_text);
235265
for url in post
236266
.urls_recursive()
@@ -279,7 +309,7 @@ impl Notifier {
279309
builder.ref_text(post.content.fallback());
280310
}
281311
}
282-
if self.params.base.option.__post_text.is_none() {
312+
if self.params.base.option.ext.__post_text.is_none() {
283313
builder.ref_text("\n");
284314
for url in post
285315
.urls_recursive()

src/platform/telegram/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use serde::Deserialize;
77
use serde_json as json;
88
use spdlog::prelude::*;
99

10-
use crate::{config::Validator, secret_enum, serde_impl_default_for};
10+
use crate::{config::Validator, helper, secret_enum};
1111

1212
// Base
1313
//
@@ -88,4 +88,8 @@ pub struct ConfigExperimental {
8888
pub send_live_image_as_preview: Option<bool>,
8989
}
9090

91-
serde_impl_default_for!(ConfigExperimental);
91+
impl Default for ConfigExperimental {
92+
fn default() -> Self {
93+
helper::serde_default()
94+
}
95+
}

0 commit comments

Comments
 (0)