Skip to content

全局通知中心 ​

聚合 13 类业务事件为站内通知(持久化 + WS 实时推送 + 外发 bark/tg/webhook),Web/移动端铃铛通知中心。

架构 ​

后端 internal/notice/:

  • models.Notice(Source 事件 tag / Key 去重键 / Title/Body/Level(info/success/warning/danger) / Read / CreatedAt),AutoMigrate。
  • oper.NoticeOper:CRUD + ExistsSince(去重查询) + CountUnread(铃铛角标) + Cleanup + ClearAll(一键清空)。
  • notice.Service.Notice(ctx, Input, dedup):dedup=true 按 Source+Key 当天去重(周期事件);false 一次性。流程:去重 → 写库 → WS 广播 → 外发渠道。
  • 循环依赖解耦:Service 用 Store 接口(oper.NoticeOper 隐式实现,不 import oper,因 oper→monitor→notice)+ Broadcaster func([]byte) 回调(app.go 适配 ws.Hub.Broadcast,不 import ws,因 ws→oper→monitor→notice)+ 外发用 notification.Manager(不用 chain.NotificationChain,避免 chain↔notice)。notice 包只 import db/models + notification。
  • WS notice 消息体:{type:"notice",data:{id,source,title,body,level,created_at}}。
  • 每日 notice-cleanup 清 30 天前已读通知。

13 类事件 Source ​

Source事件触发点去重
site_anniv今日站庆savept-refresh cron(AlertCelebration/Info)当天
new_mail新邮件messages cron(seen ID diff)当天
assess_pass考核完成assessment.assessSite(Status→COMPLETED)当天
assess_fail考核失败assessment.assessSite(Status→FAILED)当天
announce新公告runAnnouncements(RawText hash diff)当天
host_offline服务器掉线monitor Alerter(metric=offline, type=host)当天
nas_offlineNAS 掉线monitor Alerter(metric=offline, type=nas)当天
reseed_done辅种完成keepseed.Resolve(Status=added)一次性
dl_done下载完成ws.Broadcaster.detectDone(种子状态 diff)当天
site_offline站点掉线cookie-keepalive(!LoggedIn)当天
backup_done备份完成backup handler Export一次性
backup_import备份导入成功backup handler Import一次性
freeleech今日站免runFreeleech(Active 站)当天

API(guarded 组) ​

方法路径说明
GET/notices通知列表(?unread=true 仅未读;?limit=)
POST/notices/:id/read标单条已读
POST/notices/read-all全部已读
POST/notices/clear一键清空全部通知(含未读)
DELETE/notices/:id删除单条

去重与 diff 策略 ​

  • 周期事件(站庆/站免/公告/掉线/考核/下载完成/新邮件):dedup=true,Source+Key 当天去重,避免 cron 刷屏。
  • 一次性事件(备份完成/导入、辅种完成):dedup=false。
  • 新邮件:messages-check cron(MESSAGES_CRON)调 MessagesAll,seen message ID 集合存 SystemConfig(key mail:seen:站名 JSON),diff 出新 ID 通知。
  • 下载完成:ws.Broadcaster 每 2s 聚合所有种子,内存 map[dlID:hash]→done diff(State=completed 或 CompletedAt 非零);冷启动首轮只填充 map 不通知(primed 标记),避免重启把所有已完成种子当新通知。
  • 新公告:RawText 的 sha256 存 SystemConfig(key announce:seen:站名),变化才通知;首次不通知。
  • 考核:assessSite 在 BatchUpsert 前 FindBySite 读旧 Status,转换到 COMPLETED/FAILED 才通知;首次该任务无旧记录跳过。

配置 ​

变量默认说明
MESSAGES_CRON*/30 * * * *站点私信新邮件轮询(通知中心「新邮件」来源)

外发通道(outbound channels) ​

外发通道由 internal/notification/ 实现(Channel 接口 + Manager 并发扇出/错误隔离),凭据走 SystemConfig 单 key notify.settings JSON blob(NotificationSettingsProvider 热改 → Manager.Replace 即时生效,回退 env 引导默认)。三端配置入口:Web Settings→通知、移动端 通知设置 页。

共 19 个通道(Name() 即通道标识):

通道鉴权说明
bark / telegram / qq / wechat / webhook / dingtalk / feishu / email—原有 8 通道(Bark/TG/QQ 开放平台/微信 ClawBot/Webhook/钉钉/飞书/SMTP 邮件)
pushplustokenpushplus.plus,转发微信/邮件子渠道
pushdeerpushkey(+server)PushDeer,官方或自建 api2.pushdeer.com
ntfytopic(+token)ntfy.sh 或自建,按 topic 订阅,级别→Priority 头
gotifytoken(+server)自建 Gotify 服务
appriseapikey(+server)Apprise API 统一转发上百终端
workwechatwebhook url企业微信群机器人(区别于个人微信 ClawBot)
wxpusherappToken(+uid/topic_id)WxPusher 微信推送
larkwebhook urlLark 国际版飞书(与 feishu 中国版并列)
discordwebhook urlDiscord 频道 Webhook,2000 字符截断
mqttbroker+topic(+user/pass)MQTT 3.1.1 QoS0 发布,纯标准库自实现报文编解码(CONNECT→CONNACK→PUBLISH→DISCONNECT,不引 paho),支持 mqtt:// mqtts://
serverchanSendKeyServer酱 Turbo(sct.ftqq.com)

秘密字段(token/key/password 等)在 ApplySettings 时空串=保留旧值(UI 不重输秘密时回填);URL 类(workwechat/lark/discord/webhook,同 dingtalk/feishu 惯例)不脱敏,空串=清空/禁用。GetConfig 返回脱敏值 + *_configured 标记。

三端入口 ​

  • Web:MainLayout topbar 铃铛(NotificationCenter.vue)+ 未读角标 + 下拉列表(单条已读/删除/全部已读/清空);WS notice 实时追加(useWs.notices)+ noticeApi.list 初始。
  • Mobile:home_shell FAB 铃铛(ValueListenableBuilder noticeUnread)+ NoticePage(滑动删除/全部已读/清空);WsClient.notices 流 + refreshNoticeUnread。

注入 ​

noticeSvc 在 app.go notifMgr 后构造,注入:automation.New(+cfgOp) / monitor.NewService / savept cron 闭包 / chain.NewAssessmentChain / chain.NewKeepSeedChain / NewBackupHandler(d.Backup,d.Notice) / ws.Broadcaster.SetNotice(setter,避构造顺序)。