Files
iotlcm/server/internal/logic/simwarning/dedupe.go
T
MiFaZhan 59eb34976a chore: 初始开源发布
iotlcm-admin-svr:管理后台服务。

- Go module:iotlcm → git.5iot.com/iotlcm-public/iotlcm-admin-svr(729 文件)
- 凭据与地址脱敏:JWT signingKey(含代码里的 MustGet 默认值)、
  MySQL DSN、Redis 口令、告警邮件发件人邮箱全部改为占位;
  私网 IP → 文档地址段;库名 xiujie_admin → iotlcm
- 真实手机号/邮箱 → 合法 11 位编造号 / example.com
- 移除内部资产:CI 触发器、过时 DDL(sql/db_iotlcm.sql)、
  私有依赖 go get 行、明文 registry 登录口令
- 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名
- Dockerfile 改用公共基础镜像
- 拼错的 RADEME.md → README.md,README 重写
- 需要真实数据库的用例改为可用 IOTLCM_TEST_WITH_DB=1 显式启用
- 补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes

数据库 schema 不随本仓发布(生产 DDL 已过时),README 已说明。
2026-10-23 14:48:30 +08:00

152 lines
3.4 KiB
Go

package simwarning
import (
"context"
"fmt"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/cache"
"strings"
"time"
"github.com/gogf/gf/v2/errors/gerror"
)
const (
warnDedupeKeyPrefix = "iotlcm:warning"
warnDedupeMinTTL = 24 * time.Hour
)
func acquireWarningDedupe(ctx context.Context, hit warningHit, runTime time.Time) (bool, string, error) {
key := warningDedupeKey(hit)
if key == "" {
return false, "", gerror.New("warning dedupe key is empty")
}
ok, err := cache.Instance().SetIfNotExist(ctx, key, "1", warningDedupeTTL(hit, runTime))
return ok, key, err
}
func acquireWarningActionDedupe(ctx context.Context, hit warningHit, action string, runTime time.Time) (bool, string, error) {
action = strings.TrimSpace(action)
if action == "" {
return false, "", gerror.New("warning action is empty")
}
key := warningActionDedupeKey(hit, action)
if key == "" {
return false, "", gerror.New("warning action dedupe key is empty")
}
ok, err := cache.Instance().SetIfNotExist(ctx, key, "1", warningDedupeTTL(hit, runTime))
return ok, key, err
}
func releaseWarningDedupe(ctx context.Context, key string) {
key = strings.TrimSpace(key)
if key == "" {
return
}
_, _ = cache.Instance().Remove(ctx, key)
}
func warningDedupeKey(hit warningHit) string {
if hit.Config.TenantId == "" || hit.Config.Id == 0 || hit.Config.ItemId == 0 || hit.WarnStage == 0 {
return ""
}
return fmt.Sprintf(
"%s:hit:%d:%d:%s:%d:%d:%d:%s",
warnDedupeKeyPrefix,
hit.Config.ItemType,
hit.Config.WarnUnit,
hit.Config.TenantId,
hit.Config.Id,
hit.Config.ItemId,
hit.WarnStage,
warningPeriodKey(hit),
)
}
func warningActionDedupeKey(hit warningHit, action string) string {
if hit.Config.TenantId == "" || hit.Config.Id == 0 || hit.Config.ItemId == 0 || hit.WarnStage == 0 {
return ""
}
return fmt.Sprintf(
"%s:act:%s:%d:%d:%s:%d:%d:%d:%s",
warnDedupeKeyPrefix,
action,
hit.Config.ItemType,
hit.Config.WarnUnit,
hit.Config.TenantId,
hit.Config.Id,
hit.Config.ItemId,
hit.WarnStage,
warningPeriodKey(hit),
)
}
func warningDedupeTTL(hit warningHit, runTime time.Time) time.Duration {
if runTime.IsZero() {
runTime = time.Now()
}
expireAt := warningDedupeExpireAt(hit)
if expireAt.IsZero() {
return warnDedupeMinTTL
}
ttl := expireAt.Sub(runTime)
if ttl <= 0 {
return warnDedupeMinTTL
}
return ttl
}
func warningDedupeExpireAt(hit warningHit) time.Time {
if !hit.DedupeExpireAt.IsZero() {
return hit.DedupeExpireAt
}
if !hit.WindowEnd.IsZero() {
return hit.WindowEnd
}
if !hit.PeriodEnd.IsZero() {
return hit.PeriodEnd.AddDate(0, 1, 0)
}
return time.Time{}
}
func warnUnix(value time.Time) int64 {
if value.IsZero() {
return 0
}
return value.Unix()
}
func warningPeriodKey(hit warningHit) string {
begin, end := warningWindow(hit)
return fmt.Sprintf("%d-%d", warnUnix(begin), warnUnix(end))
}
func warningWindow(hit warningHit) (time.Time, time.Time) {
begin := hit.WindowBegin
end := hit.WindowEnd
if begin.IsZero() {
begin = hit.PeriodBegin
}
if end.IsZero() {
end = hit.PeriodEnd
}
return begin, end
}
func isTrafficKind(kind string) bool {
switch kind {
case warnKindTrafficMb, warnKindTrafficPercent, warnKindPoolTrafficPercent:
return true
default:
return false
}
}
func isExpireKind(kind string) bool {
switch kind {
case warnKindExpireDay, warnKindExpireMonth:
return true
default:
return false
}
}