nezha/service/rpc/nezha.go

148 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rpc
import (
"context"
"fmt"
"log"
"strings"
"time"
"github.com/naiba/nezha/model"
pb "github.com/naiba/nezha/proto"
"github.com/naiba/nezha/service/dao"
)
type NezhaHandler struct {
Auth *AuthHandler
}
func (s *NezhaHandler) ReportTask(c context.Context, r *pb.TaskResult) (*pb.Receipt, error) {
var err error
var clientID uint64
if clientID, err = s.Auth.Check(c); err != nil {
return nil, err
}
if r.GetType() == model.TaskTypeHTTPGET {
// SSL 证书报警
var errMsg string
if strings.HasPrefix(r.GetData(), "SSL证书错误") {
// 排除 i/o timeont、connection timeout、EOF 错误
if !strings.HasSuffix(r.GetData(), "timeout") &&
!strings.HasSuffix(r.GetData(), "EOF") &&
!strings.HasSuffix(r.GetData(), "timed out") {
errMsg = r.GetData()
}
} else {
var last model.MonitorHistory
var newCert = strings.Split(r.GetData(), "|")
if len(newCert) > 1 {
expiresNew, _ := time.Parse("2006-01-02 15:04:05 -0700 MST", newCert[1])
// 证书过期提醒
if expiresNew.Before(time.Now().AddDate(0, 0, 7)) {
errMsg = fmt.Sprintf(
"SSL证书将在七天内过期过期时间%s。",
expiresNew.Format("2006-01-02 15:04:05"))
}
// 证书变更提醒
if err := dao.DB.Where("monitor_id = ? AND data LIKE ?", r.GetId(), "%|%").Order("id DESC").First(&last).Error; err == nil {
var oldCert = strings.Split(last.Data, "|")
var expiresOld time.Time
if len(oldCert) > 1 {
expiresOld, _ = time.Parse("2006-01-02 15:04:05 -0700 MST", oldCert[1])
}
if last.Data != "" && oldCert[0] != newCert[0] && !expiresNew.Equal(expiresOld) {
errMsg = fmt.Sprintf(
"SSL证书变更%s, %s 过期;新:%s, %s 过期。",
oldCert[0], expiresOld.Format("2006-01-02 15:04:05"), newCert[0], expiresNew.Format("2006-01-02 15:04:05"))
}
}
}
}
if errMsg != "" {
var monitor model.Monitor
dao.DB.First(&monitor, "id = ?", r.GetId())
dao.SendNotification(fmt.Sprintf("服务监控:%s %s", monitor.Name, errMsg), true)
}
}
if r.GetType() == model.TaskTypeCommand {
// 处理上报的计划任务
dao.CronLock.RLock()
defer dao.CronLock.RUnlock()
cr := dao.Crons[r.GetId()]
if cr != nil {
if cr.PushSuccessful && r.GetSuccessful() {
dao.SendNotification(fmt.Sprintf("成功计划任务:%s ,服务器:%d日志\n%s", cr.Name, clientID, r.GetData()), false)
}
if !r.GetSuccessful() {
dao.SendNotification(fmt.Sprintf("失败计划任务:%s ,服务器:%d日志\n%s", cr.Name, clientID, r.GetData()), false)
}
dao.DB.Model(cr).Updates(model.Cron{
LastExecutedAt: time.Now().Add(time.Second * -1 * time.Duration(r.GetDelay())),
LastResult: r.GetSuccessful(),
})
}
} else {
// 存入历史记录
mh := model.PB2MonitorHistory(r)
if err := dao.DB.Create(&mh).Error; err != nil {
return nil, err
}
}
return &pb.Receipt{Proced: true}, nil
}
func (s *NezhaHandler) RequestTask(h *pb.Host, stream pb.NezhaService_RequestTaskServer) error {
var clientID uint64
var err error
if clientID, err = s.Auth.Check(stream.Context()); err != nil {
return err
}
closeCh := make(chan error)
dao.ServerLock.RLock()
dao.ServerList[clientID].TaskStream = stream
dao.ServerList[clientID].TaskClose = closeCh
dao.ServerLock.RUnlock()
select {
case err = <-closeCh:
return err
}
}
func (s *NezhaHandler) ReportSystemState(c context.Context, r *pb.State) (*pb.Receipt, error) {
var clientID uint64
var err error
if clientID, err = s.Auth.Check(c); err != nil {
return nil, err
}
state := model.PB2State(r)
dao.ServerLock.RLock()
defer dao.ServerLock.RUnlock()
dao.ServerList[clientID].LastActive = time.Now()
dao.ServerList[clientID].State = &state
return &pb.Receipt{Proced: true}, nil
}
func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Receipt, error) {
var clientID uint64
var err error
if clientID, err = s.Auth.Check(c); err != nil {
return nil, err
}
host := model.PB2Host(r)
dao.ServerLock.RLock()
defer dao.ServerLock.RUnlock()
log.Println(dao.Conf.IgnoredIPNotificationServerIDs)
if dao.Conf.EnableIPChangeNotification &&
dao.Conf.IgnoredIPNotificationServerIDs[clientID] != struct{}{} &&
dao.ServerList[clientID].Host != nil &&
dao.ServerList[clientID].Host.IP != "" &&
host.IP != "" &&
dao.ServerList[clientID].Host.IP != host.IP {
dao.SendNotification(fmt.Sprintf(
"IP变更提醒 服务器:%s 旧IP%s新IP%s。",
dao.ServerList[clientID].Name, dao.ServerList[clientID].Host.IP, host.IP), true)
}
dao.ServerList[clientID].Host = &host
return &pb.Receipt{Proced: true}, nil
}