wip: 通知

This commit is contained in:
Akizon77
2025-09-12 03:01:42 +00:00
parent 1b83644788
commit 0f0e359c63
5 changed files with 90 additions and 11 deletions

View File

@@ -25,17 +25,18 @@ func Get() (models.Config, error) {
if err := db.First(&config).Error; err != nil {
if err == gorm.ErrRecordNotFound {
config = models.Config{
ID: 1,
Sitename: "Komari",
Description: "Komari Monitor, a simple server monitoring tool.",
AllowCors: false,
OAuthEnabled: false,
GeoIpEnabled: true,
GeoIpProvider: "ip-api",
NezhaCompatEnabled: false,
NezhaCompatListen: "",
UpdatedAt: models.FromTime(time.Now()),
CreatedAt: models.FromTime(time.Now()),
ID: 1,
Sitename: "Komari",
Description: "Komari Monitor, a simple server monitoring tool.",
AllowCors: false,
OAuthEnabled: false,
GeoIpEnabled: true,
GeoIpProvider: "ipinfo",
NezhaCompatEnabled: false,
NezhaCompatListen: "",
NotificationTemplate: "{{event}}: {{client}}\n{{time}}",
UpdatedAt: models.FromTime(time.Now()),
CreatedAt: models.FromTime(time.Now()),
}
if err := db.Create(&config).Error; err != nil {
log.Fatal("Failed to create default config:", err)

View File

@@ -25,6 +25,7 @@ type Config struct {
// 通知
NotificationEnabled bool `json:"notification_enabled" gorm:"default:false"` // 通知总开关
NotificationMethod string `json:"notification_method" gorm:"type:varchar(64);default:'none'"`
NotificationTemplate string `json:"notification_template" gorm:"type:longtext;default:'{{event}}: {{client}}\n{{time}}'"`
ExpireNotificationEnabled bool `json:"expire_notification_enabled" gorm:"default:false"` // 是否启用过期通知
ExpireNotificationLeadDays int `json:"expire_notification_lead_days" gorm:"default:7"` // 过期前多少天通知默认7天
LoginNotification bool `json:"login_notification" gorm:"default:false"` // 登录通知

View File

@@ -0,0 +1,11 @@
package messageevent
const (
Offline = "Offline"
Online = "Online"
Expire = "Expire"
Renew = "Renew"
Login = "Login"
Alert = "Alert"
Traffic = "Traffic"
)

View File

@@ -1,6 +1,16 @@
package models
import "time"
type MessageSenderProvider struct {
Name string `json:"name" gorm:"primaryKey;unique;not null"`
Addition string `json:"addition" gorm:"type:longtext" default:"{}"`
}
type EventMessage struct {
Event string `json:"event"`
Clients []Client `json:"clients"`
Time time.Time `json:"time"`
Message string `json:"message"`
Emoji string `json:"emoji"`
}

View File

@@ -4,7 +4,9 @@ import (
"encoding/json"
"fmt"
"log"
"strings"
"sync"
"time"
"github.com/komari-monitor/komari/database"
"github.com/komari-monitor/komari/database/auditlog"
@@ -89,3 +91,57 @@ func SendTextMessage(message string, title string) error {
auditlog.Log("", "", "Failed to send message after 3 attempts: "+err.Error()+","+title, "error")
return err
}
func SendEvent(event models.EventMessage) error {
if CurrentProvider() == nil {
return fmt.Errorf("message sender provider is not initialized")
}
var err error
cfg, err := config.Get()
if err != nil {
return err
}
if !cfg.NotificationEnabled {
return nil
}
messageTemplate := cfg.NotificationTemplate
if messageTemplate == "" {
messageTemplate = "{{event}}: {{client}}\n{{time}}"
}
messageTemplate = parseTemplate(messageTemplate, event)
for i := 0; i < 3; i++ {
err = CurrentProvider().SendTextMessage(messageTemplate, event.Event)
if err == nil {
auditlog.Log("", "", "Event message sent: "+event.Event, "info")
return nil
}
}
auditlog.Log("", "", "Failed to send event message after 3 attempts: "+err.Error()+","+event.Event, "error")
return err
}
func parseTemplate(messageTemplate string, event models.EventMessage) string {
// Aggregate client names. If Name is empty, fall back to UUID.
clientNames := make([]string, 0, len(event.Clients))
for _, c := range event.Clients {
name := c.Name
if strings.TrimSpace(name) == "" {
// fallback to UUID when name is not set
name = c.UUID
}
clientNames = append(clientNames, name)
}
joinedClients := strings.Join(clientNames, ", ")
replaceMap := map[string]string{
"{{event}}": event.Event,
"{{client}}": joinedClients,
"{{time}}": event.Time.Format(time.RFC3339),
"{{message}}": event.Message,
}
result := messageTemplate
for placeholder, value := range replaceMap {
result = strings.ReplaceAll(result, placeholder, value)
}
return result
}