mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-21 00:24:12 +08:00
559 lines
16 KiB
Go
559 lines
16 KiB
Go
package repo
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
|
"github.com/1Panel-dev/1Panel/agent/global"
|
|
"google.golang.org/genproto/googleapis/type/date"
|
|
"gorm.io/gorm"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
type AlertRepo struct{}
|
|
|
|
type IAlertRepo interface {
|
|
WithByType(alertType string) DBOption
|
|
WithByStatusIn(status []string) DBOption
|
|
WithByProject(project string) DBOption
|
|
WithByCount(count uint) DBOption
|
|
WithByAlertId(alertId uint) DBOption
|
|
WithByCreateAt(date *date.Date) DBOption
|
|
WithByLicenseId(licenseId string) DBOption
|
|
WithByRecordId(recordId uint) DBOption
|
|
WithByAlertMethodContainsConfigID(id uint) DBOption
|
|
WithByMethodConfigIDs(ids []uint) DBOption
|
|
|
|
Create(alert *model.Alert) error
|
|
Get(opts ...DBOption) (model.Alert, error)
|
|
Page(page, size int, opts ...DBOption) (int64, []model.Alert, error)
|
|
List(opts ...DBOption) ([]model.Alert, error)
|
|
Delete(opts ...DBOption) error
|
|
Save(alert *model.Alert) error
|
|
Update(maps map[string]interface{}, opts ...DBOption) error
|
|
|
|
GetLog(opts ...DBOption) (model.AlertLog, error)
|
|
CreateLog(alertLog *model.AlertLog) error
|
|
PageLog(limit, offset int, opts ...DBOption) (int64, []model.AlertLog, error)
|
|
ListLog(opts ...DBOption) ([]model.AlertLog, error)
|
|
UpdateLog(id uint, maps map[string]interface{}) error
|
|
BatchUpdateLogBy(maps map[string]interface{}, opts ...DBOption) error
|
|
DeleteLog(opts ...DBOption) error
|
|
CleanAlertLogs() error
|
|
|
|
CreateAlertTask(alertTaskBase *model.AlertTask) error
|
|
DeleteAlertTask(opts ...DBOption) error
|
|
GetAlertTask(opts ...DBOption) (model.AlertTask, error)
|
|
LoadTaskCount(alertType string, project string, method string) (uint, uint, error)
|
|
GetTaskLog(alertType string, alertId uint) (time.Time, error)
|
|
GetLicensePushCount(method string) (uint, error)
|
|
|
|
GetConfig(opts ...DBOption) (model.AlertConfig, error)
|
|
GetConfigById(id uint) (model.AlertConfig, error)
|
|
AlertConfigList(opts ...DBOption) ([]model.AlertConfig, error)
|
|
UpdateAlertConfig(maps map[string]interface{}, opts ...DBOption) error
|
|
CreateAlertConfig(config *model.AlertConfig) error
|
|
DeleteAlertConfig(opts ...DBOption) error
|
|
|
|
WithByTypeNotIn(types []string) DBOption
|
|
PageAlertConfig(page, size int, opts ...DBOption) (int64, []model.AlertConfig, error)
|
|
|
|
SyncAll(data []model.AlertConfig) error
|
|
}
|
|
|
|
func NewIAlertRepo() IAlertRepo {
|
|
return &AlertRepo{}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByType(alertType string) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("`type` = ?", alertType)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByStatusIn(status []string) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("status in (?)", status)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByCount(count uint) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("count = ?", count)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByProject(project string) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("project = ?", project)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByAlertId(alertId uint) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("alert_id = ?", alertId)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByLicenseId(licenseId string) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("license_id = ?", licenseId)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByRecordId(recordId uint) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("record_id = ?", recordId)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByAlertMethodContainsConfigID(id uint) DBOption {
|
|
method := strconv.Itoa(int(id))
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("(method = ? OR method LIKE ? OR method LIKE ? OR method LIKE ?)", method, method+",%", "%,"+method, "%,"+method+",%")
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByMethodConfigIDs(ids []uint) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
methods := make([]string, 0, len(ids))
|
|
for _, id := range ids {
|
|
methods = append(methods, strconv.Itoa(int(id)))
|
|
}
|
|
return g.Where("method IN ?", methods)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) WithByCreateAt(createAt *date.Date) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("DATE(created_at) = DATE(?)", createAt)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) Create(alert *model.Alert) error {
|
|
return global.AlertDB.Model(&model.Alert{}).Create(alert).Error
|
|
}
|
|
|
|
func (a *AlertRepo) Save(alert *model.Alert) error {
|
|
return global.AlertDB.Save(alert).Error
|
|
}
|
|
|
|
func (a *AlertRepo) Get(opts ...DBOption) (model.Alert, error) {
|
|
var alert model.Alert
|
|
db, _ := getAlertDB(opts...)
|
|
err := db.First(&alert).Error
|
|
return alert, err
|
|
}
|
|
|
|
func (a *AlertRepo) Page(page, size int, opts ...DBOption) (int64, []model.Alert, error) {
|
|
var alerts []model.Alert
|
|
alertDb, _ := getAlertDB(opts...)
|
|
db := alertDb.Model(&model.Alert{})
|
|
count := int64(0)
|
|
db = db.Count(&count)
|
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&alerts).Error
|
|
return count, alerts, err
|
|
}
|
|
|
|
func (a *AlertRepo) List(opts ...DBOption) ([]model.Alert, error) {
|
|
var alert []model.Alert
|
|
db, _ := getAlertDB(opts...)
|
|
err := db.Find(&alert).Error
|
|
return alert, err
|
|
}
|
|
|
|
func (a *AlertRepo) Update(maps map[string]interface{}, opts ...DBOption) error {
|
|
db, _ := getAlertDB(opts...)
|
|
return db.Model(&model.Alert{}).Updates(maps).Error
|
|
}
|
|
|
|
func (a *AlertRepo) Delete(opts ...DBOption) error {
|
|
db, _ := getAlertDB(opts...)
|
|
return db.Delete(&model.Alert{}).Error
|
|
}
|
|
|
|
func (a *AlertRepo) GetLog(opts ...DBOption) (model.AlertLog, error) {
|
|
var alertLog model.AlertLog
|
|
db, _ := getAlertDB(opts...)
|
|
err := db.First(&alertLog).Error
|
|
return alertLog, err
|
|
}
|
|
|
|
func (a *AlertRepo) CreateLog(log *model.AlertLog) error {
|
|
return global.AlertDB.Model(&model.AlertLog{}).Create(&log).Error
|
|
}
|
|
|
|
func (a *AlertRepo) UpdateLog(id uint, maps map[string]interface{}) error {
|
|
return global.AlertDB.Model(&model.AlertLog{}).Where("id = ?", id).Updates(maps).Error
|
|
}
|
|
|
|
func (a *AlertRepo) BatchUpdateLogBy(maps map[string]interface{}, opts ...DBOption) error {
|
|
db, _ := getAlertDB(opts...)
|
|
if len(opts) == 0 {
|
|
db = db.Where("1=1")
|
|
}
|
|
return db.Model(&model.AlertLog{}).Updates(&maps).Error
|
|
}
|
|
|
|
func (a *AlertRepo) PageLog(page, size int, opts ...DBOption) (int64, []model.AlertLog, error) {
|
|
var alerts []model.AlertLog
|
|
db := global.AlertDB.Model(&model.AlertLog{})
|
|
for _, opt := range opts {
|
|
db = opt(db)
|
|
}
|
|
count := int64(0)
|
|
db = db.Order("created_at desc").Count(&count)
|
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&alerts).Error
|
|
return count, alerts, err
|
|
}
|
|
|
|
func (a *AlertRepo) ListLog(opts ...DBOption) ([]model.AlertLog, error) {
|
|
var alertLog []model.AlertLog
|
|
db, _ := getAlertDB(opts...)
|
|
err := db.Find(&alertLog).Error
|
|
return alertLog, err
|
|
}
|
|
|
|
func (a *AlertRepo) DeleteLog(opts ...DBOption) error {
|
|
db, _ := getAlertDB(opts...)
|
|
return db.Delete(&model.AlertLog{}).Error
|
|
}
|
|
|
|
func (a *AlertRepo) CleanAlertLogs() error {
|
|
return global.AlertDB.Where("1 = 1").Delete(&model.AlertLog{}).Error
|
|
}
|
|
|
|
func (a *AlertRepo) CreateAlertTask(alertTaskBase *model.AlertTask) error {
|
|
return global.AlertDB.Model(&model.AlertTask{}).Create(&alertTaskBase).Error
|
|
}
|
|
|
|
func (a *AlertRepo) DeleteAlertTask(opts ...DBOption) error {
|
|
db, _ := getAlertDB(opts...)
|
|
return db.Delete(&model.AlertTask{}).Error
|
|
}
|
|
|
|
func (a *AlertRepo) GetAlertTask(opts ...DBOption) (model.AlertTask, error) {
|
|
var data model.AlertTask
|
|
db, _ := getAlertDB(opts...)
|
|
err := db.First(&data).Error
|
|
return data, err
|
|
}
|
|
|
|
func (a *AlertRepo) LoadTaskCount(alertType string, project string, method string) (uint, uint, error) {
|
|
var (
|
|
todayCount int64
|
|
totalCount int64
|
|
)
|
|
_ = global.AlertDB.Model(&model.AlertTask{}).Where("type = ? AND quota_type = ? AND method = ?", alertType, project, method).Count(&totalCount).Error
|
|
|
|
now := time.Now()
|
|
todayMidnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
|
tomorrowMidnight := todayMidnight.Add(24 * time.Hour)
|
|
err := global.AlertDB.Model(&model.AlertTask{}).Where("type = ? AND quota_type = ? AND method = ? AND created_at > ? AND created_at < ?", alertType, project, method, todayMidnight, tomorrowMidnight).Count(&todayCount).Error
|
|
return uint(todayCount), uint(totalCount), err
|
|
}
|
|
|
|
func (a *AlertRepo) GetTaskLog(alertType string, alertId uint) (time.Time, error) {
|
|
var newDate time.Time
|
|
status := []string{constant.AlertSuccess, constant.AlertPushSuccess, constant.AlertSyncError, constant.AlertPushing}
|
|
now := time.Now()
|
|
todayMidnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
|
tomorrowMidnight := todayMidnight.Add(24 * time.Hour)
|
|
err := global.AlertDB.Model(&model.AlertLog{}).
|
|
Where("type = ? AND alert_id = ? AND status in ? AND created_at > ? AND created_at < ?", alertType, alertId, status, todayMidnight, tomorrowMidnight).
|
|
Order("created_at DESC").
|
|
Limit(1).
|
|
Pluck("created_at", &newDate).Error
|
|
if err != nil {
|
|
return time.Time{}, err
|
|
}
|
|
|
|
if newDate.IsZero() {
|
|
return time.Time{}, nil
|
|
}
|
|
|
|
return newDate, nil
|
|
}
|
|
|
|
func getAlertDB(opts ...DBOption) (*gorm.DB, error) {
|
|
var db *gorm.DB
|
|
db = global.AlertDB
|
|
for _, opt := range opts {
|
|
db = opt(db)
|
|
}
|
|
return db, nil
|
|
}
|
|
|
|
func (a *AlertRepo) GetLicensePushCount(method string) (uint, error) {
|
|
var (
|
|
todayCount int64
|
|
)
|
|
now := time.Now()
|
|
todayMidnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
|
tomorrowMidnight := todayMidnight.Add(24 * time.Hour)
|
|
err := global.AlertDB.Model(&model.AlertTask{}).Where("created_at > ? AND created_at < ? AND method = ?", todayMidnight, tomorrowMidnight, method).Count(&todayCount).Error
|
|
return uint(todayCount), err
|
|
}
|
|
|
|
func (a *AlertRepo) AlertConfigList(opts ...DBOption) ([]model.AlertConfig, error) {
|
|
var config []model.AlertConfig
|
|
db, _ := getAlertDB(opts...)
|
|
err := db.Find(&config).Error
|
|
return config, err
|
|
}
|
|
|
|
func (a *AlertRepo) UpdateAlertConfig(maps map[string]interface{}, opts ...DBOption) error {
|
|
db, _ := getAlertDB(opts...)
|
|
return db.Model(&model.AlertConfig{}).Updates(maps).Error
|
|
}
|
|
|
|
func (a *AlertRepo) CreateAlertConfig(config *model.AlertConfig) error {
|
|
return global.AlertDB.Model(&model.AlertConfig{}).Create(config).Error
|
|
}
|
|
|
|
func (a *AlertRepo) DeleteAlertConfig(opts ...DBOption) error {
|
|
db, _ := getAlertDB(opts...)
|
|
return db.Delete(&model.AlertConfig{}).Error
|
|
}
|
|
|
|
func (a *AlertRepo) GetConfig(opts ...DBOption) (model.AlertConfig, error) {
|
|
var alertConfig model.AlertConfig
|
|
db, _ := getAlertDB(opts...)
|
|
err := db.First(&alertConfig).Error
|
|
return alertConfig, err
|
|
}
|
|
|
|
func (a *AlertRepo) GetConfigById(id uint) (model.AlertConfig, error) {
|
|
var config model.AlertConfig
|
|
err := global.AlertDB.First(&config, id).Error
|
|
return config, err
|
|
}
|
|
|
|
func (a *AlertRepo) WithByTypeNotIn(types []string) DBOption {
|
|
return func(g *gorm.DB) *gorm.DB {
|
|
return g.Where("`type` NOT IN (?)", types)
|
|
}
|
|
}
|
|
|
|
func (a *AlertRepo) PageAlertConfig(page, size int, opts ...DBOption) (int64, []model.AlertConfig, error) {
|
|
var configs []model.AlertConfig
|
|
db := global.AlertDB.Model(&model.AlertConfig{})
|
|
for _, opt := range opts {
|
|
db = opt(db)
|
|
}
|
|
count := int64(0)
|
|
db = db.Count(&count)
|
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&configs).Error
|
|
return count, configs, err
|
|
}
|
|
|
|
var singletonTypes = map[string]bool{
|
|
constant.CommonConfig: true,
|
|
}
|
|
|
|
func (a *AlertRepo) SyncAll(data []model.AlertConfig) error {
|
|
tx := global.AlertDB.Begin()
|
|
if tx.Error != nil {
|
|
return tx.Error
|
|
}
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
tx.Rollback()
|
|
panic(r)
|
|
}
|
|
}()
|
|
|
|
var oldConfigs []model.AlertConfig
|
|
if err := tx.Find(&oldConfigs).Error; err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
|
|
usedConfigIDs, err := loadUsedAlertConfigIDs(tx)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
|
|
oldConfigMap := make(map[string]uint)
|
|
oldConfigByType := make(map[string][]model.AlertConfig)
|
|
oldConfigByKey := make(map[string][]model.AlertConfig)
|
|
consumedConfigIDs := make(map[uint]struct{})
|
|
for _, item := range oldConfigs {
|
|
if singletonTypes[item.Type] {
|
|
oldConfigMap[item.Type] = item.ID
|
|
continue
|
|
}
|
|
oldConfigByType[item.Type] = append(oldConfigByType[item.Type], item)
|
|
oldConfigByKey[alertConfigSyncKey(item)] = append(oldConfigByKey[alertConfigSyncKey(item)], item)
|
|
}
|
|
for _, item := range data {
|
|
if singletonTypes[item.Type] {
|
|
if val, ok := oldConfigMap[item.Type]; ok {
|
|
item.ID = val
|
|
delete(oldConfigMap, item.Type)
|
|
consumedConfigIDs[item.ID] = struct{}{}
|
|
} else {
|
|
item.ID = 0
|
|
}
|
|
if item.ID == 0 {
|
|
if err := tx.Create(&item).Error; err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
} else if err := tx.Save(&item).Error; err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
continue
|
|
}
|
|
|
|
key := alertConfigSyncKey(item)
|
|
if matched, ok := popAlertConfigByKey(oldConfigByKey, key); ok {
|
|
item.ID = matched.ID
|
|
consumedConfigIDs[item.ID] = struct{}{}
|
|
if err := tx.Save(&item).Error; err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
deleteAlertConfigByID(oldConfigByType, matched.ID)
|
|
continue
|
|
}
|
|
|
|
if matched, ok := popUnusedAlertConfigByType(oldConfigByType, usedConfigIDs, item.Type); ok {
|
|
item.ID = matched.ID
|
|
consumedConfigIDs[item.ID] = struct{}{}
|
|
if err := tx.Save(&item).Error; err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
continue
|
|
}
|
|
|
|
item.ID = 0
|
|
if err := tx.Create(&item).Error; err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
for _, item := range oldConfigs {
|
|
if _, used := usedConfigIDs[item.ID]; used {
|
|
continue
|
|
}
|
|
if _, kept := consumedConfigIDs[item.ID]; kept {
|
|
continue
|
|
}
|
|
if err := tx.Where("id = ?", item.ID).Delete(&model.AlertConfig{}).Error; err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
if err := tx.Commit().Error; err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func loadUsedAlertConfigIDs(tx *gorm.DB) (map[uint]struct{}, error) {
|
|
var alerts []model.Alert
|
|
if err := tx.Select("method").Find(&alerts).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
usedIDs := make(map[uint]struct{})
|
|
for _, alert := range alerts {
|
|
for _, item := range strings.Split(alert.Method, ",") {
|
|
item = strings.TrimSpace(item)
|
|
if item == "" {
|
|
continue
|
|
}
|
|
id, err := strconv.ParseUint(item, 10, 64)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
usedIDs[uint(id)] = struct{}{}
|
|
}
|
|
}
|
|
return usedIDs, nil
|
|
}
|
|
|
|
func alertConfigSyncKey(item model.AlertConfig) string {
|
|
return item.Type + "::" + normalizeAlertConfigJSON(item.Config)
|
|
}
|
|
|
|
func normalizeAlertConfigJSON(config string) string {
|
|
trimmed := strings.TrimSpace(config)
|
|
if trimmed == "" {
|
|
return ""
|
|
}
|
|
|
|
var data any
|
|
if err := json.Unmarshal([]byte(trimmed), &data); err != nil {
|
|
return trimmed
|
|
}
|
|
buf, err := json.Marshal(data)
|
|
if err != nil {
|
|
return trimmed
|
|
}
|
|
return string(buf)
|
|
}
|
|
|
|
func popAlertConfigByKey(configMap map[string][]model.AlertConfig, key string) (model.AlertConfig, bool) {
|
|
items := configMap[key]
|
|
if len(items) == 0 {
|
|
return model.AlertConfig{}, false
|
|
}
|
|
|
|
item := items[0]
|
|
if len(items) == 1 {
|
|
delete(configMap, key)
|
|
} else {
|
|
configMap[key] = items[1:]
|
|
}
|
|
return item, true
|
|
}
|
|
|
|
func popUnusedAlertConfigByType(configMap map[string][]model.AlertConfig, usedConfigIDs map[uint]struct{}, configType string) (model.AlertConfig, bool) {
|
|
items := configMap[configType]
|
|
if len(items) == 0 {
|
|
return model.AlertConfig{}, false
|
|
}
|
|
|
|
for idx, item := range items {
|
|
if _, used := usedConfigIDs[item.ID]; used {
|
|
continue
|
|
}
|
|
if idx == 0 {
|
|
if len(items) == 1 {
|
|
delete(configMap, configType)
|
|
} else {
|
|
configMap[configType] = items[1:]
|
|
}
|
|
} else {
|
|
configMap[configType] = append(items[:idx], items[idx+1:]...)
|
|
}
|
|
return item, true
|
|
}
|
|
return model.AlertConfig{}, false
|
|
}
|
|
|
|
func deleteAlertConfigByID(configMap map[string][]model.AlertConfig, id uint) {
|
|
for key, items := range configMap {
|
|
for idx, item := range items {
|
|
if item.ID != id {
|
|
continue
|
|
}
|
|
if len(items) == 1 {
|
|
delete(configMap, key)
|
|
} else {
|
|
configMap[key] = append(items[:idx], items[idx+1:]...)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|