From c7784725715483c8b540efc44308522159fdd761 Mon Sep 17 00:00:00 2001 From: Bot Date: Wed, 1 Jul 2026 23:36:21 +0800 Subject: [PATCH] fix: panic on nil pointer dereference in notification sending and fix date parsing formats --- model/notification.go | 113 +++++++++++++++++++++++------------- service/singleton/domain.go | 9 +++ 2 files changed, 83 insertions(+), 39 deletions(-) diff --git a/model/notification.go b/model/notification.go index a9857f6..3ad46e8 100644 --- a/model/notification.go +++ b/model/notification.go @@ -233,48 +233,83 @@ func (ns *NotificationServerBundle) replaceParamsInString(str string, message st "#SERVER.EXPIRE_DATE#", mod(expiresStr), "#SERVER.BILLING_AMOUNT#", mod(amountStr), "#SERVER.BILLING_CYCLE#", mod(cycleStr), - - // Converted metrics - "#SERVER.CPU#", mod(ns.formatUsage(false, ns.Server.State.CPU)), - "#SERVER.MEM#", mod(ns.formatUsage(true, float64(ns.Server.State.MemUsed)/float64(ns.Server.Host.MemTotal))), - "#SERVER.SWAP#", mod(ns.formatUsage(true, float64(ns.Server.State.SwapUsed)/float64(ns.Server.Host.SwapTotal))), - "#SERVER.DISK#", mod(ns.formatUsage(true, float64(ns.Server.State.DiskUsed)/float64(ns.Server.Host.DiskTotal))), - "#SERVER.SPEEDIN#", mod(fmt.Sprintf("%s/s", ns.formatSize(ns.Server.State.NetInSpeed))), - "#SERVER.SPEEDOUT#", mod(fmt.Sprintf("%s/s", ns.formatSize(ns.Server.State.NetOutSpeed))), - "#SERVER.TRANSFERIN#", mod(ns.formatSize(ns.Server.State.NetInTransfer)), - "#SERVER.TRANSFEROUT#", mod(ns.formatSize(ns.Server.State.NetOutTransfer)), - - // Raw metrics - "#SERVER.CPUUSED#", mod(fmt.Sprintf("%f", ns.Server.State.CPU)), - "#SERVER.MEMUSED#", mod(fmt.Sprintf("%d", ns.Server.State.MemUsed)), - "#SERVER.SWAPUSED#", mod(fmt.Sprintf("%d", ns.Server.State.SwapUsed)), - "#SERVER.DISKUSED#", mod(fmt.Sprintf("%d", ns.Server.State.DiskUsed)), - "#SERVER.MEMTOTAL#", mod(fmt.Sprintf("%d", ns.Server.Host.MemTotal)), - "#SERVER.SWAPTOTAL#", mod(fmt.Sprintf("%d", ns.Server.Host.SwapTotal)), - "#SERVER.DISKTOTAL#", mod(fmt.Sprintf("%d", ns.Server.Host.DiskTotal)), - "#SERVER.NETINSPEED#", mod(fmt.Sprintf("%d", ns.Server.State.NetInSpeed)), - "#SERVER.NETOUTSPEED#", mod(fmt.Sprintf("%d", ns.Server.State.NetOutSpeed)), - "#SERVER.NETINTRANSFER#", mod(fmt.Sprintf("%d", ns.Server.State.NetInTransfer)), - "#SERVER.NETOUTTRANSFER#", mod(fmt.Sprintf("%d", ns.Server.State.NetOutTransfer)), - "#SERVER.LOAD1#", mod(fmt.Sprintf("%f", ns.Server.State.Load1)), - "#SERVER.LOAD5#", mod(fmt.Sprintf("%f", ns.Server.State.Load5)), - "#SERVER.LOAD15#", mod(fmt.Sprintf("%f", ns.Server.State.Load15)), - "#SERVER.TCPCONNCOUNT#", mod(fmt.Sprintf("%d", ns.Server.State.TcpConnCount)), - "#SERVER.UDPCONNCOUNT#", mod(fmt.Sprintf("%d", ns.Server.State.UdpConnCount)), ) - var ipv4, ipv6, validIP string - ip := ns.Server.GeoIP.IP - if ip.IPv4Addr != "" && ip.IPv6Addr != "" { - ipv4 = ip.IPv4Addr - ipv6 = ip.IPv6Addr - validIP = ipv4 - } else if ip.IPv4Addr != "" { - ipv4 = ip.IPv4Addr - validIP = ipv4 + if ns.Server.State != nil && ns.Server.Host != nil { + replacements = append(replacements, + // Converted metrics + "#SERVER.CPU#", mod(ns.formatUsage(false, ns.Server.State.CPU)), + "#SERVER.MEM#", mod(ns.formatUsage(true, float64(ns.Server.State.MemUsed)/float64(ns.Server.Host.MemTotal))), + "#SERVER.SWAP#", mod(ns.formatUsage(true, float64(ns.Server.State.SwapUsed)/float64(ns.Server.Host.SwapTotal))), + "#SERVER.DISK#", mod(ns.formatUsage(true, float64(ns.Server.State.DiskUsed)/float64(ns.Server.Host.DiskTotal))), + "#SERVER.SPEEDIN#", mod(fmt.Sprintf("%s/s", ns.formatSize(ns.Server.State.NetInSpeed))), + "#SERVER.SPEEDOUT#", mod(fmt.Sprintf("%s/s", ns.formatSize(ns.Server.State.NetOutSpeed))), + "#SERVER.TRANSFERIN#", mod(ns.formatSize(ns.Server.State.NetInTransfer)), + "#SERVER.TRANSFEROUT#", mod(ns.formatSize(ns.Server.State.NetOutTransfer)), + + // Raw metrics + "#SERVER.CPUUSED#", mod(fmt.Sprintf("%f", ns.Server.State.CPU)), + "#SERVER.MEMUSED#", mod(fmt.Sprintf("%d", ns.Server.State.MemUsed)), + "#SERVER.SWAPUSED#", mod(fmt.Sprintf("%d", ns.Server.State.SwapUsed)), + "#SERVER.DISKUSED#", mod(fmt.Sprintf("%d", ns.Server.State.DiskUsed)), + "#SERVER.NETINSPEED#", mod(fmt.Sprintf("%d", ns.Server.State.NetInSpeed)), + "#SERVER.NETOUTSPEED#", mod(fmt.Sprintf("%d", ns.Server.State.NetOutSpeed)), + "#SERVER.TRANSFERINRAW#", mod(fmt.Sprintf("%d", ns.Server.State.NetInTransfer)), + "#SERVER.TRANSFEROUTRAW#", mod(fmt.Sprintf("%d", ns.Server.State.NetOutTransfer)), + "#SERVER.UPTIME#", mod(fmt.Sprintf("%d", ns.Server.State.Uptime)), + "#SERVER.MEMTOTAL#", mod(fmt.Sprintf("%d", ns.Server.Host.MemTotal)), + "#SERVER.SWAPTOTAL#", mod(fmt.Sprintf("%d", ns.Server.Host.SwapTotal)), + "#SERVER.DISKTOTAL#", mod(fmt.Sprintf("%d", ns.Server.Host.DiskTotal)), + "#SERVER.LOAD1#", mod(fmt.Sprintf("%f", ns.Server.State.Load1)), + "#SERVER.LOAD5#", mod(fmt.Sprintf("%f", ns.Server.State.Load5)), + "#SERVER.LOAD15#", mod(fmt.Sprintf("%f", ns.Server.State.Load15)), + "#SERVER.TCPCONNCOUNT#", mod(fmt.Sprintf("%d", ns.Server.State.TcpConnCount)), + "#SERVER.UDPCONNCOUNT#", mod(fmt.Sprintf("%d", ns.Server.State.UdpConnCount)), + ) } else { - ipv6 = ip.IPv6Addr - validIP = ipv6 + replacements = append(replacements, + "#SERVER.CPU#", mod("N/A"), + "#SERVER.MEM#", mod("N/A"), + "#SERVER.SWAP#", mod("N/A"), + "#SERVER.DISK#", mod("N/A"), + "#SERVER.SPEEDIN#", mod("N/A"), + "#SERVER.SPEEDOUT#", mod("N/A"), + "#SERVER.TRANSFERIN#", mod("N/A"), + "#SERVER.TRANSFEROUT#", mod("N/A"), + "#SERVER.CPUUSED#", mod("0"), + "#SERVER.MEMUSED#", mod("0"), + "#SERVER.SWAPUSED#", mod("0"), + "#SERVER.DISKUSED#", mod("0"), + "#SERVER.NETINSPEED#", mod("0"), + "#SERVER.NETOUTSPEED#", mod("0"), + "#SERVER.TRANSFERINRAW#", mod("0"), + "#SERVER.TRANSFEROUTRAW#", mod("0"), + "#SERVER.UPTIME#", mod("0"), + "#SERVER.MEMTOTAL#", mod("0"), + "#SERVER.SWAPTOTAL#", mod("0"), + "#SERVER.DISKTOTAL#", mod("0"), + "#SERVER.LOAD1#", mod("0"), + "#SERVER.LOAD5#", mod("0"), + "#SERVER.LOAD15#", mod("0"), + "#SERVER.TCPCONNCOUNT#", mod("0"), + "#SERVER.UDPCONNCOUNT#", mod("0"), + ) + } + + var ipv4, ipv6, validIP string + if ns.Server.GeoIP != nil { + ip := ns.Server.GeoIP.IP + if ip.IPv4Addr != "" && ip.IPv6Addr != "" { + ipv4 = ip.IPv4Addr + ipv6 = ip.IPv6Addr + validIP = ipv4 + } else if ip.IPv4Addr != "" { + ipv4 = ip.IPv4Addr + validIP = ipv4 + } else { + ipv6 = ip.IPv6Addr + validIP = ipv6 + } } replacements = append(replacements, diff --git a/service/singleton/domain.go b/service/singleton/domain.go index 49e398a..b4df6a7 100644 --- a/service/singleton/domain.go +++ b/service/singleton/domain.go @@ -405,6 +405,8 @@ func CronJobForDomainStatus() { var err error if len(endDateStr) == 10 { // YYYY-MM-DD endDate, err = time.Parse("2006-01-02", endDateStr) + } else if len(endDateStr) == 19 && endDateStr[10] == ' ' { // YYYY-MM-DD HH:MM:SS + endDate, err = time.Parse("2006-01-02 15:04:05", endDateStr) } else { endDate, err = time.Parse(time.RFC3339, endDateStr) } @@ -487,12 +489,19 @@ func CronJobForServerStatus() { continue } + // 忽略前端默认生成的空日期 + if strings.HasPrefix(pn.BillingDataMod.EndDate, "0000-00-00") { + continue + } + // 处理类似 2026-10-10 甚至其他不带时区的格式 endDateStr := pn.BillingDataMod.EndDate var endDate time.Time var err error if len(endDateStr) == 10 { // YYYY-MM-DD endDate, err = time.Parse("2006-01-02", endDateStr) + } else if len(endDateStr) == 19 && endDateStr[10] == ' ' { // YYYY-MM-DD HH:MM:SS + endDate, err = time.Parse("2006-01-02 15:04:05", endDateStr) } else { endDate, err = time.Parse(time.RFC3339, endDateStr) }