///|
/// chensuiyi/notify — 多平台通知库:消息模型、平台预设渲染、HTTP/SMTP 投递,
/// 以及一个可选的去重/限流/重试引擎。设计约定:
///
/// - 所有失败原因(返回的 `String?` 中的 `Some`)永不包含凭据——url、secret、
/// password 不出现在任何错误文本里,调用方可以放心把它打进日志。
/// - 所有时间由调用方注入(`now` 参数),库自身不读时钟,保证可测。
/// - 库不写日志、不落盘、不依赖任何业务概念,只投递消息并报告结果。
///|
pub suberror NotifyError {
InvalidPreset(String)
} derive(Debug)
///|
pub impl Show for NotifyError with fn output(self, logger) {
match self {
InvalidPreset(preset) => {
logger.write_string("unknown preset: ")
logger.write_string(preset)
}
}
}
///|
pub extend NotifyError with Show::{to_string, output}
///|
pub extend NotifyError with @debug.Debug::{to_repr}
///|
/// One notification. `key` is what deduplication keys on; `event` is the
/// logical event name carried through to generic webhook payloads.
pub(all) struct Message {
event : String
level : String
title : String
body : String
fields : Array[(String, String)]
ts_ms : UInt64
key : String
} derive(Debug)
///|
pub extend Message with Debug::{to_repr}
///|
pub fn Message::new(
event : String,
level : String,
title : String,
body : String,
key : String,
ts_ms : UInt64,
fields? : Array[(String, String)] = [],
) -> Message {
{ event, level, title, body, fields, ts_ms, key, }
}
///|
/// One delivery destination. `preset` selects the payload shape (a closed set:
/// feishu / dingtalk / wecom / slack / discord / webhook / email); the rest are
/// endpoint and credential fields.
pub(all) struct Target {
name : String
preset : String
url : String
secret : String?
format : String?
from : String?
to : Array[String]?
username : String?
password : String?
} derive(Debug)
///|
pub extend Target with Debug::{to_repr}
///|
/// A rendered request: what the transport hands to the network. Kept separate
/// from the message so one message can be rendered per target.
pub(all) struct Delivery {
url : String
http_method : String
content_type : String?
headers : Array[(String, String)]
body : String
/// email: the complete RFC5322 message.
mail : String?
} derive(Debug)
///|
pub extend Delivery with Debug::{to_repr}
///|
/// Who is sending: appears in message footers (`product @ host`) and in the
/// SMTP EHLO greeting. Passed in by the caller so the library stays
/// platform-agnostic.
pub(all) struct Context {
host : String
product : String
} derive(Debug)
///|
pub extend Context with Debug::{to_repr}
///|
/// The default context for callers that do not care about branding.
pub fn Context::default() -> Context {
{ host: "localhost", product: "notify", }
}