mirror of
https://github.com/usual2970/certimate.git
synced 2025-10-05 05:54:53 +00:00
@@ -1,6 +1,7 @@
|
||||
package domains
|
||||
|
||||
import (
|
||||
"certimate/internal/notify"
|
||||
"certimate/internal/utils/app"
|
||||
"context"
|
||||
)
|
||||
@@ -25,6 +26,11 @@ func InitSchedule() {
|
||||
}
|
||||
}
|
||||
|
||||
// 过期提醒
|
||||
app.GetScheduler().Add("expire", "0 0 * * *", func() {
|
||||
notify.PushExpireMsg()
|
||||
})
|
||||
|
||||
// 启动定时任务
|
||||
app.GetScheduler().Start()
|
||||
app.GetApp().Logger().Info("定时任务启动成功", "total", app.GetScheduler().Total())
|
||||
|
98
internal/notify/expire.go
Normal file
98
internal/notify/expire.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"certimate/internal/utils/app"
|
||||
"certimate/internal/utils/xtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
)
|
||||
|
||||
type msg struct {
|
||||
subject string
|
||||
message string
|
||||
}
|
||||
|
||||
const (
|
||||
defaultExpireSubject = "您有{COUNT}张证书即将过期"
|
||||
defaultExpireMsg = "有{COUNT}张证书即将过期,域名分别为{DOMAINS},请保持关注!"
|
||||
)
|
||||
|
||||
func PushExpireMsg() {
|
||||
// 查询即将过期的证书
|
||||
|
||||
records, err := app.GetApp().Dao().FindRecordsByFilter("domains", "expiredAt<{:time}&&certUrl!=''", "-created", 500, 0,
|
||||
dbx.Params{"time": xtime.GetTimeAfter(24 * time.Hour * 15)})
|
||||
if err != nil {
|
||||
app.GetApp().Logger().Error("find expired domains by filter", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 组装消息
|
||||
msg := buildMsg(records)
|
||||
|
||||
if msg == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := Send(msg.subject, msg.message); err != nil {
|
||||
app.GetApp().Logger().Error("send expire msg", "error", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type notifyTemplates struct {
|
||||
NotifyTemplates []notifyTemplate `json:"notifyTemplates"`
|
||||
}
|
||||
|
||||
type notifyTemplate struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
func buildMsg(records []*models.Record) *msg {
|
||||
if len(records) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查询模板信息
|
||||
templateRecord, err := app.GetApp().Dao().FindFirstRecordByFilter("settings", "name='templates'")
|
||||
title := defaultExpireSubject
|
||||
content := defaultExpireMsg
|
||||
|
||||
if err == nil {
|
||||
var templates *notifyTemplates
|
||||
templateRecord.UnmarshalJSONField("content", templates)
|
||||
if templates != nil && len(templates.NotifyTemplates) > 0 {
|
||||
title = templates.NotifyTemplates[0].Title
|
||||
content = templates.NotifyTemplates[0].Content
|
||||
}
|
||||
}
|
||||
|
||||
// 替换变量
|
||||
count := len(records)
|
||||
domains := make([]string, count)
|
||||
|
||||
for i, record := range records {
|
||||
domains[i] = record.GetString("domain")
|
||||
}
|
||||
|
||||
countStr := strconv.Itoa(count)
|
||||
domainStr := strings.Join(domains, ",")
|
||||
|
||||
title = strings.ReplaceAll(title, "{COUNT}", countStr)
|
||||
title = strings.ReplaceAll(title, "{DOMAINS}", domainStr)
|
||||
|
||||
content = strings.ReplaceAll(content, "{COUNT}", countStr)
|
||||
content = strings.ReplaceAll(content, "{DOMAINS}", domainStr)
|
||||
|
||||
// 返回消息
|
||||
return &msg{
|
||||
subject: title,
|
||||
message: content,
|
||||
}
|
||||
|
||||
}
|
129
internal/notify/notify.go
Normal file
129
internal/notify/notify.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"certimate/internal/utils/app"
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
notifyPackage "github.com/nikoksr/notify"
|
||||
|
||||
"github.com/nikoksr/notify/service/dingding"
|
||||
|
||||
"github.com/nikoksr/notify/service/telegram"
|
||||
|
||||
"github.com/nikoksr/notify/service/http"
|
||||
)
|
||||
|
||||
const (
|
||||
notifyChannelDingtalk = "dingtalk"
|
||||
notifyChannelWebhook = "webhook"
|
||||
notifyChannelTelegram = "telegram"
|
||||
)
|
||||
|
||||
func Send(title, content string) error {
|
||||
// 获取所有的推送渠道
|
||||
notifiers, err := getNotifiers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(notifiers) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 添加推送渠道
|
||||
notifyPackage.UseServices(notifiers...)
|
||||
|
||||
// 发送消息
|
||||
return notifyPackage.Send(context.Background(), title, content)
|
||||
}
|
||||
|
||||
func getNotifiers() ([]notifyPackage.Notifier, error) {
|
||||
|
||||
resp, err := app.GetApp().Dao().FindFirstRecordByFilter("settings", "name='notifyChannels'")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("find notifyChannels error: %w", err)
|
||||
}
|
||||
|
||||
notifiers := make([]notifyPackage.Notifier, 0)
|
||||
|
||||
rs := make(map[string]map[string]any)
|
||||
|
||||
if err := resp.UnmarshalJSONField("content", &rs); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal notifyChannels error: %w", err)
|
||||
}
|
||||
|
||||
for k, v := range rs {
|
||||
|
||||
if !getBool(v, "enabled") {
|
||||
continue
|
||||
}
|
||||
|
||||
switch k {
|
||||
case notifyChannelTelegram:
|
||||
temp := getTelegramNotifier(v)
|
||||
if temp == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
notifiers = append(notifiers, temp)
|
||||
case notifyChannelDingtalk:
|
||||
notifiers = append(notifiers, getDingTalkNotifier(v))
|
||||
case notifyChannelWebhook:
|
||||
notifiers = append(notifiers, getWebhookNotifier(v))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return notifiers, nil
|
||||
|
||||
}
|
||||
|
||||
func getWebhookNotifier(conf map[string]any) notifyPackage.Notifier {
|
||||
rs := http.New()
|
||||
|
||||
rs.AddReceiversURLs(getString(conf, "url"))
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
func getTelegramNotifier(conf map[string]any) notifyPackage.Notifier {
|
||||
rs, err := telegram.New(getString(conf, "apiToken"))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
chatId := getString(conf, "chatId")
|
||||
|
||||
id, err := strconv.ParseInt(chatId, 10, 64)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
rs.AddReceivers(id)
|
||||
return rs
|
||||
}
|
||||
|
||||
func getDingTalkNotifier(conf map[string]any) notifyPackage.Notifier {
|
||||
return dingding.New(&dingding.Config{
|
||||
Token: getString(conf, "accessToken"),
|
||||
Secret: getString(conf, "secret"),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func getString(conf map[string]any, key string) string {
|
||||
if _, ok := conf[key]; !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return conf[key].(string)
|
||||
}
|
||||
|
||||
func getBool(conf map[string]any, key string) bool {
|
||||
if _, ok := conf[key]; !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return conf[key].(bool)
|
||||
}
|
@@ -13,3 +13,10 @@ func BeijingTimeStr() string {
|
||||
// 格式化为字符串
|
||||
return now.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func GetTimeAfter(d time.Duration) string {
|
||||
|
||||
t := time.Now().UTC()
|
||||
|
||||
return t.Add(d).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
Reference in New Issue
Block a user