mirror of
				https://github.com/komari-monitor/komari.git
				synced 2025-10-31 03:53:39 +00:00 
			
		
		
		
	wip: 通知
This commit is contained in:
		| @@ -31,9 +31,10 @@ func Get() (models.Config, error) { | |||||||
| 				AllowCors:            false, | 				AllowCors:            false, | ||||||
| 				OAuthEnabled:         false, | 				OAuthEnabled:         false, | ||||||
| 				GeoIpEnabled:         true, | 				GeoIpEnabled:         true, | ||||||
| 				GeoIpProvider:      "ip-api", | 				GeoIpProvider:        "ipinfo", | ||||||
| 				NezhaCompatEnabled:   false, | 				NezhaCompatEnabled:   false, | ||||||
| 				NezhaCompatListen:    "", | 				NezhaCompatListen:    "", | ||||||
|  | 				NotificationTemplate: "{{event}}: {{client}}\n{{time}}", | ||||||
| 				UpdatedAt:            models.FromTime(time.Now()), | 				UpdatedAt:            models.FromTime(time.Now()), | ||||||
| 				CreatedAt:            models.FromTime(time.Now()), | 				CreatedAt:            models.FromTime(time.Now()), | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ type Config struct { | |||||||
| 	// 通知 | 	// 通知 | ||||||
| 	NotificationEnabled        bool    `json:"notification_enabled" gorm:"default:false"` // 通知总开关 | 	NotificationEnabled        bool    `json:"notification_enabled" gorm:"default:false"` // 通知总开关 | ||||||
| 	NotificationMethod         string  `json:"notification_method" gorm:"type:varchar(64);default:'none'"` | 	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"` // 是否启用过期通知 | 	ExpireNotificationEnabled  bool    `json:"expire_notification_enabled" gorm:"default:false"` // 是否启用过期通知 | ||||||
| 	ExpireNotificationLeadDays int     `json:"expire_notification_lead_days" gorm:"default:7"`   // 过期前多少天通知,默认7天 | 	ExpireNotificationLeadDays int     `json:"expire_notification_lead_days" gorm:"default:7"`   // 过期前多少天通知,默认7天 | ||||||
| 	LoginNotification          bool    `json:"login_notification" gorm:"default:false"`          // 登录通知 | 	LoginNotification          bool    `json:"login_notification" gorm:"default:false"`          // 登录通知 | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								database/models/messageEvent/MessageEvent.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								database/models/messageEvent/MessageEvent.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | package messageevent | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	Offline = "Offline" | ||||||
|  | 	Online  = "Online" | ||||||
|  | 	Expire  = "Expire" | ||||||
|  | 	Renew   = "Renew" | ||||||
|  | 	Login   = "Login" | ||||||
|  | 	Alert   = "Alert" | ||||||
|  | 	Traffic = "Traffic" | ||||||
|  | ) | ||||||
| @@ -1,6 +1,16 @@ | |||||||
| package models | package models | ||||||
|  |  | ||||||
|  | import "time" | ||||||
|  |  | ||||||
| type MessageSenderProvider struct { | type MessageSenderProvider struct { | ||||||
| 	Name     string `json:"name" gorm:"primaryKey;unique;not null"` | 	Name     string `json:"name" gorm:"primaryKey;unique;not null"` | ||||||
| 	Addition string `json:"addition" gorm:"type:longtext" default:"{}"` | 	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"` | ||||||
|  | } | ||||||
|   | |||||||
| @@ -4,7 +4,9 @@ import ( | |||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log" | 	"log" | ||||||
|  | 	"strings" | ||||||
| 	"sync" | 	"sync" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/komari-monitor/komari/database" | 	"github.com/komari-monitor/komari/database" | ||||||
| 	"github.com/komari-monitor/komari/database/auditlog" | 	"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") | 	auditlog.Log("", "", "Failed to send message after 3 attempts: "+err.Error()+","+title, "error") | ||||||
| 	return err | 	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 | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user