Merge branch 'dev' of github.com:naiba/nezha-v1 into dev

This commit is contained in:
naiba
2024-11-22 23:57:48 +08:00
16 changed files with 425 additions and 306 deletions

View File

@@ -4,11 +4,12 @@ import (
"context"
"sync"
petname "github.com/dustinkirkland/golang-petname"
"github.com/hashicorp/go-uuid"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"github.com/hashicorp/go-uuid"
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/service/singleton"
)
@@ -30,7 +31,7 @@ func (a *authHandler) Check(ctx context.Context) (uint64, error) {
}
if clientSecret != singleton.Conf.AgentSecretKey {
return 0, status.Errorf(codes.Unauthenticated, "客户端认证失败")
return 0, status.Error(codes.Unauthenticated, "客户端认证失败")
}
var clientUUID string
@@ -39,22 +40,25 @@ func (a *authHandler) Check(ctx context.Context) (uint64, error) {
}
if _, err := uuid.ParseUUID(clientUUID); err != nil {
return 0, status.Errorf(codes.Unauthenticated, "客户端 UUID 不合法")
return 0, status.Error(codes.Unauthenticated, "客户端 UUID 不合法")
}
singleton.ServerLock.RLock()
defer singleton.ServerLock.RUnlock()
clientID, hasID := singleton.ServerUUIDToID[clientUUID]
if !hasID {
s := model.Server{UUID: clientUUID}
s := model.Server{UUID: clientUUID, Name: petname.Generate(2, "-")}
if err := singleton.DB.Create(&s).Error; err != nil {
return 0, status.Errorf(codes.Unauthenticated, err.Error())
return 0, status.Error(codes.Unauthenticated, err.Error())
}
s.Host = &model.Host{}
s.State = &model.HostState{}
s.TaskCloseLock = new(sync.Mutex)
// generate a random silly server name
singleton.ServerList[s.ID] = &s
singleton.ServerUUIDToID[clientUUID] = s.ID
singleton.ReSortServer()
clientID = s.ID
}

View File

@@ -9,9 +9,8 @@ import (
"time"
"github.com/naiba/nezha/pkg/ddns"
"github.com/naiba/nezha/pkg/geoip"
geoipx "github.com/naiba/nezha/pkg/geoip"
"github.com/naiba/nezha/pkg/grpcx"
"github.com/naiba/nezha/pkg/utils"
"github.com/jinzhu/copier"
@@ -126,40 +125,6 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
singleton.ServerLock.RLock()
defer singleton.ServerLock.RUnlock()
// 检查并更新DDNS
if singleton.ServerList[clientID].EnableDDNS && host.IP != "" &&
(singleton.ServerList[clientID].Host == nil || singleton.ServerList[clientID].Host.IP != host.IP) {
ipv4, ipv6, _ := utils.SplitIPAddr(host.IP)
providers, err := singleton.GetDDNSProvidersFromProfiles(singleton.ServerList[clientID].DDNSProfiles, &ddns.IP{Ipv4Addr: ipv4, Ipv6Addr: ipv6})
if err == nil {
for _, provider := range providers {
go func(provider *ddns.Provider) {
provider.UpdateDomain(context.Background())
}(provider)
}
} else {
log.Printf("NEZHA>> 获取DDNS配置时发生错误: %v", err)
}
}
// 发送IP变动通知
if singleton.ServerList[clientID].Host != nil && singleton.Conf.EnableIPChangeNotification &&
((singleton.Conf.Cover == model.ConfigCoverAll && !singleton.Conf.IgnoredIPNotificationServerIDs[clientID]) ||
(singleton.Conf.Cover == model.ConfigCoverIgnoreAll && singleton.Conf.IgnoredIPNotificationServerIDs[clientID])) &&
singleton.ServerList[clientID].Host.IP != "" &&
host.IP != "" &&
singleton.ServerList[clientID].Host.IP != host.IP {
singleton.SendNotification(singleton.Conf.IPChangeNotificationGroupID,
fmt.Sprintf(
"[%s] %s, %s => %s",
singleton.Localizer.T("IP Changed"),
singleton.ServerList[clientID].Name, singleton.IPDesensitize(singleton.ServerList[clientID].Host.IP),
singleton.IPDesensitize(host.IP),
),
nil)
}
/**
* 这里的 singleton 中的数据都是关机前的旧数据
* 当 agent 重启时bootTime 变大agent 端会先上报 host 信息,然后上报 state 信息
@@ -170,11 +135,6 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
singleton.ServerList[clientID].PrevTransferOutSnapshot = singleton.ServerList[clientID].PrevTransferOutSnapshot - int64(singleton.ServerList[clientID].State.NetOutTransfer)
}
// 不要冲掉国家码
if singleton.ServerList[clientID].Host != nil {
host.CountryCode = singleton.ServerList[clientID].Host.CountryCode
}
singleton.ServerList[clientID].Host = &host
return &pb.Receipt{Proced: true}, nil
}
@@ -204,28 +164,73 @@ func (s *NezhaHandler) IOStream(stream pb.NezhaService_IOStreamServer) error {
return nil
}
func (s *NezhaHandler) LookupGeoIP(c context.Context, r *pb.GeoIP) (*pb.GeoIP, error) {
func (s *NezhaHandler) ReportGeoIP(c context.Context, r *pb.GeoIP) (*pb.GeoIP, error) {
var clientID uint64
var err error
if clientID, err = s.Auth.Check(c); err != nil {
return nil, err
}
// 根据内置数据库查询 IP 地理位置
ip := r.GetIp()
netIP := net.ParseIP(ip)
location, err := geoip.Lookup(netIP)
if err != nil {
return nil, err
geoip := model.PB2GeoIP(r)
joinedIP := geoip.IP.Join()
use6 := r.GetUse6()
singleton.ServerLock.RLock()
// 检查并更新DDNS
if singleton.ServerList[clientID].EnableDDNS && joinedIP != "" &&
(singleton.ServerList[clientID].GeoIP == nil || singleton.ServerList[clientID].GeoIP.IP != geoip.IP) {
ipv4 := geoip.IP.IPv4Addr
ipv6 := geoip.IP.IPv6Addr
providers, err := singleton.GetDDNSProvidersFromProfiles(singleton.ServerList[clientID].DDNSProfiles, &ddns.IP{Ipv4Addr: ipv4, Ipv6Addr: ipv6})
if err == nil {
for _, provider := range providers {
go func(provider *ddns.Provider) {
provider.UpdateDomain(context.Background())
}(provider)
}
} else {
log.Printf("NEZHA>> 获取DDNS配置时发生错误: %v", err)
}
}
// 发送IP变动通知
if singleton.ServerList[clientID].GeoIP != nil && singleton.Conf.EnableIPChangeNotification &&
((singleton.Conf.Cover == model.ConfigCoverAll && !singleton.Conf.IgnoredIPNotificationServerIDs[clientID]) ||
(singleton.Conf.Cover == model.ConfigCoverIgnoreAll && singleton.Conf.IgnoredIPNotificationServerIDs[clientID])) &&
singleton.ServerList[clientID].GeoIP.IP.Join() != "" &&
joinedIP != "" &&
singleton.ServerList[clientID].GeoIP.IP != geoip.IP {
singleton.SendNotification(singleton.Conf.IPChangeNotificationGroupID,
fmt.Sprintf(
"[%s] %s, %s => %s",
singleton.Localizer.T("IP Changed"),
singleton.ServerList[clientID].Name, singleton.IPDesensitize(singleton.ServerList[clientID].GeoIP.IP.Join()),
singleton.IPDesensitize(joinedIP),
),
nil)
}
singleton.ServerLock.RUnlock()
// 根据内置数据库查询 IP 地理位置
var ip string
if geoip.IP.IPv6Addr != "" && (use6 || geoip.IP.IPv4Addr == "") {
ip = geoip.IP.IPv6Addr
} else {
ip = geoip.IP.IPv4Addr
}
netIP := net.ParseIP(ip)
location, err := geoipx.Lookup(netIP)
if err != nil {
log.Printf("NEZHA>> geoip.Lookup: %v", err)
}
geoip.CountryCode = location
// 将地区码写入到 Host
singleton.ServerLock.RLock()
defer singleton.ServerLock.RUnlock()
if singleton.ServerList[clientID].Host == nil {
return nil, fmt.Errorf("host not found")
}
singleton.ServerList[clientID].Host.CountryCode = location
singleton.ServerLock.Lock()
defer singleton.ServerLock.Unlock()
singleton.ServerList[clientID].GeoIP = &geoip
return &pb.GeoIP{Ip: ip, CountryCode: location}, nil
return &pb.GeoIP{Ip: nil, CountryCode: location}, err
}

View File

@@ -157,7 +157,7 @@ func checkStatus() {
if alert.TriggerMode == model.ModeAlwaysTrigger || alertsPrevState[alert.ID][server.ID] != _RuleCheckFail {
alertsPrevState[alert.ID][server.ID] = _RuleCheckFail
message := fmt.Sprintf("[%s] %s(%s) %s", Localizer.T("Incident"),
server.Name, IPDesensitize(server.Host.IP), alert.Name)
server.Name, IPDesensitize(server.GeoIP.IP.Join()), alert.Name)
go SendTriggerTasks(alert.FailTriggerTasks, curServer.ID)
go SendNotification(alert.NotificationGroupID, message, NotificationMuteLabel.ServerIncident(server.ID, alert.ID), &curServer)
// 清除恢复通知的静音缓存
@@ -167,7 +167,7 @@ func checkStatus() {
// 本次通过检查但上一次的状态为失败,则发送恢复通知
if alertsPrevState[alert.ID][server.ID] == _RuleCheckFail {
message := fmt.Sprintf("[%s] %s(%s) %s", Localizer.T("Resolved"),
server.Name, IPDesensitize(server.Host.IP), alert.Name)
server.Name, IPDesensitize(server.GeoIP.IP.Join()), alert.Name)
go SendTriggerTasks(alert.RecoverTriggerTasks, curServer.ID)
go SendNotification(alert.NotificationGroupID, message, NotificationMuteLabel.ServerIncidentResolved(server.ID, alert.ID), &curServer)
// 清除失败通知的静音缓存

View File

@@ -68,3 +68,13 @@ func ReSortServer() {
return SortedServerListForGuest[i].DisplayIndex > SortedServerListForGuest[j].DisplayIndex
})
}
func OnServerDelete(sid []uint64) {
ServerLock.Lock()
defer ServerLock.Unlock()
for _, id := range sid {
serverUUID := ServerList[id].UUID
delete(ServerUUIDToID, serverUUID)
delete(ServerList, id)
}
}