mirror of
https://github.com/nezhahq/nezha.git
synced 2025-01-22 12:48:14 -05:00
💥 v2.0 必须更新面板,新增服务监控
This commit is contained in:
parent
0ce8017875
commit
a41c792577
@ -3,7 +3,7 @@ RUN apk --no-cache --no-progress add \
|
||||
gcc git musl-dev
|
||||
WORKDIR /dashboard
|
||||
COPY . .
|
||||
RUN cd cmd/dashboard && go build -o app -ldflags="-s -w -X github.com/naiba/nezha/service/dao.Version=$(git rev-parse HEAD)"
|
||||
RUN cd cmd/dashboard && go build -o app -ldflags="-s -w"
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk --no-cache --no-progress add \
|
||||
|
10
README.md
10
README.md
@ -179,3 +179,13 @@ URL 里面也可放置占位符,请求时会进行简单的字符串替换。
|
||||
- [哪吒面板,一个便携服务器状态监控面板搭建教程,不想拥有一个自己的探针吗?](https://haoduck.com/644.html)
|
||||
- [哪吒面板:小鸡们的最佳探针](https://www.zhujizixun.com/2843.html) *(已过时)*
|
||||
- [>>更多教程](https://www.google.com/search?q=%22%E5%93%AA%E5%90%92%E9%9D%A2%E6%9D%BF%22+%22%E6%95%99%E7%A8%8B%22) (Google)
|
||||
|
||||
## 变更日志
|
||||
|
||||
- `0.2.0` **重大更新**
|
||||
|
||||
增加了服务监控(TCP端口延迟、Ping、HTTP-SSL 证书)功能,此版本 Agent 与旧面板不兼容,而 Agent 是通过 GitHub Release 自动更新的 所以务必更新面板开启最新功能。
|
||||
|
||||
- `0.1.23` 新增 IP 变更通知功能
|
||||
|
||||
在后台设置界面启用。
|
||||
|
@ -2,13 +2,18 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/genkiroid/cert"
|
||||
"github.com/go-ping/ping"
|
||||
"github.com/p14yground/go-github-selfupdate/selfupdate"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc"
|
||||
@ -105,7 +110,6 @@ func run(cmd *cobra.Command, args []string) {
|
||||
|
||||
var err error
|
||||
var conn *grpc.ClientConn
|
||||
var hc pb.NezhaService_HeartbeatClient
|
||||
|
||||
retry := func() {
|
||||
log.Println("Error to close connection ...")
|
||||
@ -125,43 +129,90 @@ func run(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
client = pb.NewNezhaServiceClient(conn)
|
||||
// 第一步注册
|
||||
_, err = client.Register(ctx, monitor.GetHost().PB())
|
||||
_, err = client.ReportSystemInfo(ctx, monitor.GetHost().PB())
|
||||
if err != nil {
|
||||
log.Printf("client.Register err: %v", err)
|
||||
log.Printf("client.ReportSystemInfo err: %v", err)
|
||||
retry()
|
||||
continue
|
||||
}
|
||||
// 心跳接收控制命令
|
||||
hc, err = client.Heartbeat(ctx, &pb.Beat{
|
||||
Timestamp: fmt.Sprintf("%v", time.Now()),
|
||||
})
|
||||
// 执行 Task
|
||||
tasks, err := client.RequestTask(ctx, monitor.GetHost().PB())
|
||||
if err != nil {
|
||||
log.Printf("client.Heartbeat err: %v", err)
|
||||
log.Printf("client.RequestTask err: %v", err)
|
||||
retry()
|
||||
continue
|
||||
}
|
||||
err = receiveCommand(hc)
|
||||
err = receiveTasks(tasks)
|
||||
log.Printf("receiveCommand exit to main: %v", err)
|
||||
retry()
|
||||
}
|
||||
}
|
||||
|
||||
func receiveCommand(hc pb.NezhaService_HeartbeatClient) error {
|
||||
func receiveTasks(tasks pb.NezhaService_RequestTaskClient) error {
|
||||
var err error
|
||||
var action *pb.Command
|
||||
defer log.Printf("receiveCommand exit %v %v => %v", time.Now(), action, err)
|
||||
var task *pb.Task
|
||||
defer log.Printf("receiveTasks exit %v %v => %v", time.Now(), task, err)
|
||||
for {
|
||||
action, err = hc.Recv()
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
task, err = tasks.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch action.GetType() {
|
||||
var result pb.TaskResult
|
||||
result.Id = task.GetId()
|
||||
switch task.GetType() {
|
||||
case model.MonitorTypeHTTPGET:
|
||||
start := time.Now()
|
||||
resp, err := http.Get(task.GetData())
|
||||
if err == nil {
|
||||
result.Delay = float32(time.Now().Sub(start).Microseconds()) / 1000.0
|
||||
if resp.StatusCode > 299 || resp.StatusCode < 200 {
|
||||
err = errors.New("\n应用错误:" + resp.Status)
|
||||
}
|
||||
}
|
||||
var certs cert.Certs
|
||||
if err == nil {
|
||||
if strings.HasPrefix(task.GetData(), "https://") {
|
||||
certs, err = cert.NewCerts([]string{task.GetData()})
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if len(certs) == 0 {
|
||||
err = errors.New("\n获取SSL证书错误:未获取到证书")
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
result.Data = certs[0].Issuer
|
||||
result.Successful = true
|
||||
} else {
|
||||
result.Data = err.Error()
|
||||
}
|
||||
case model.MonitorTypeICMPPing:
|
||||
pinger, err := ping.NewPinger(task.GetData())
|
||||
if err == nil {
|
||||
pinger.Count = 10
|
||||
err = pinger.Run() // Blocks until finished.
|
||||
}
|
||||
if err == nil {
|
||||
stat := pinger.Statistics()
|
||||
result.Delay = float32(stat.AvgRtt.Microseconds()) / 1000.0
|
||||
result.Successful = true
|
||||
} else {
|
||||
result.Data = err.Error()
|
||||
}
|
||||
case model.MonitorTypeTCPPing:
|
||||
start := time.Now()
|
||||
conn, err := net.DialTimeout("tcp", task.GetData(), time.Second*10)
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
result.Delay = float32(time.Now().Sub(start).Microseconds()) / 1000.0
|
||||
result.Successful = true
|
||||
} else {
|
||||
result.Data = err.Error()
|
||||
}
|
||||
default:
|
||||
log.Printf("Unknown action: %v", action)
|
||||
log.Printf("Unknown action: %v", task)
|
||||
}
|
||||
client.ReportTask(ctx, &result)
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,14 +223,14 @@ func reportState() {
|
||||
for {
|
||||
if client != nil {
|
||||
monitor.TrackNetworkSpeed()
|
||||
_, err = client.ReportState(ctx, monitor.GetState(dao.ReportDelay).PB())
|
||||
_, err = client.ReportSystemState(ctx, monitor.GetState(dao.ReportDelay).PB())
|
||||
if err != nil {
|
||||
log.Printf("reportState error %v", err)
|
||||
time.Sleep(delayWhenError)
|
||||
}
|
||||
if lastReportHostInfo.Before(time.Now().Add(-10 * time.Minute)) {
|
||||
lastReportHostInfo = time.Now()
|
||||
client.Register(ctx, monitor.GetHost().PB())
|
||||
client.ReportSystemInfo(ctx, monitor.GetHost().PB())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,64 @@ func (cp *commonPage) serve() {
|
||||
cr := cp.r.Group("")
|
||||
cr.Use(mygin.Authorize(mygin.AuthorizeOption{}))
|
||||
cr.GET("/", cp.home)
|
||||
cr.GET("/service", cp.service)
|
||||
cr.GET("/ws", cp.ws)
|
||||
}
|
||||
|
||||
type ServiceItem struct {
|
||||
Monitor model.Monitor
|
||||
TotalUp uint64
|
||||
TotalDown uint64
|
||||
Delay *[30]float32
|
||||
Up *[30]int
|
||||
Down *[30]int
|
||||
}
|
||||
|
||||
func (p *commonPage) service(c *gin.Context) {
|
||||
var ms []model.Monitor
|
||||
dao.DB.Find(&ms)
|
||||
year, month, day := time.Now().Date()
|
||||
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
|
||||
var mhs []model.MonitorHistory
|
||||
dao.DB.Where("created_at >= ?", today.AddDate(0, 0, -29)).Find(&mhs)
|
||||
|
||||
msm := make(map[uint64]*ServiceItem)
|
||||
for i := 0; i < len(ms); i++ {
|
||||
msm[ms[i].ID] = &ServiceItem{
|
||||
Monitor: ms[i],
|
||||
Delay: &[30]float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
Up: &[30]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
Down: &[30]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
}
|
||||
}
|
||||
|
||||
// 整合数据
|
||||
for i := 0; i < len(mhs); i++ {
|
||||
dayIndex := 29
|
||||
if mhs[i].CreatedAt.Before(today) {
|
||||
dayIndex = 28 - (int(today.Sub(mhs[i].CreatedAt).Hours()) / 24)
|
||||
}
|
||||
if mhs[i].Successful {
|
||||
msm[mhs[i].MonitorID].TotalUp++
|
||||
msm[mhs[i].MonitorID].Delay[dayIndex] = (msm[mhs[i].MonitorID].Delay[dayIndex]*float32(msm[mhs[i].MonitorID].Up[dayIndex]) + mhs[i].Delay) / float32(msm[mhs[i].MonitorID].Up[dayIndex]+1)
|
||||
msm[mhs[i].MonitorID].Up[dayIndex]++
|
||||
} else {
|
||||
msm[mhs[i].MonitorID].TotalDown++
|
||||
msm[mhs[i].MonitorID].Down[dayIndex]++
|
||||
}
|
||||
}
|
||||
|
||||
u, ok := c.Get(model.CtxKeyAuthorizedUser)
|
||||
data := mygin.CommonEnvironment(c, gin.H{
|
||||
"Title": "服务状态",
|
||||
"Services": msm,
|
||||
})
|
||||
if ok {
|
||||
data["Admin"] = u
|
||||
}
|
||||
c.HTML(http.StatusOK, "theme-"+dao.Conf.Site.Theme+"/service", data)
|
||||
}
|
||||
|
||||
func (cp *commonPage) home(c *gin.Context) {
|
||||
dao.ServerLock.RLock()
|
||||
defer dao.ServerLock.RUnlock()
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"github.com/naiba/nezha/service/dao"
|
||||
)
|
||||
|
||||
// ServeWeb ..
|
||||
func ServeWeb(port uint) {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
if dao.Conf.Debug {
|
||||
@ -43,6 +42,35 @@ func ServeWeb(port uint) {
|
||||
"ts": func(s string) string {
|
||||
return strings.TrimSpace(s)
|
||||
},
|
||||
"divU64": func(a, b uint64) float32 {
|
||||
if b == 0 {
|
||||
if a > 0 {
|
||||
return 100
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return float32(a) / float32(b) * 100
|
||||
},
|
||||
"div": func(a, b int) float32 {
|
||||
if b == 0 {
|
||||
if a > 0 {
|
||||
return 100
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return float32(a) / float32(b) * 100
|
||||
},
|
||||
"addU64": func(a, b uint64) uint64 {
|
||||
return a + b
|
||||
},
|
||||
"add": func(a, b int) int {
|
||||
return a + b
|
||||
},
|
||||
"dayBefore": func(i int) string {
|
||||
year, month, day := time.Now().Date()
|
||||
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
|
||||
return today.AddDate(0, 0, i-29).Format("1月2号")
|
||||
},
|
||||
})
|
||||
r.Static("/static", "resource/static")
|
||||
r.LoadHTMLGlob("resource/template/**/*")
|
||||
|
@ -33,6 +33,7 @@ func (ma *memberAPI) serve() {
|
||||
|
||||
mr.POST("/logout", ma.logout)
|
||||
mr.POST("/server", ma.addOrEditServer)
|
||||
mr.POST("/monitor", ma.addOrEditMonitor)
|
||||
mr.POST("/notification", ma.addOrEditNotification)
|
||||
mr.POST("/alert-rule", ma.addOrEditAlertRule)
|
||||
mr.POST("/setting", ma.updateSetting)
|
||||
@ -64,6 +65,8 @@ func (ma *memberAPI) delete(c *gin.Context) {
|
||||
if err == nil {
|
||||
alertmanager.OnDeleteNotification(id)
|
||||
}
|
||||
case "monitor":
|
||||
err = dao.DB.Delete(&model.Monitor{}, "id = ?", id).Error
|
||||
case "alert-rule":
|
||||
err = dao.DB.Delete(&model.AlertRule{}, "id = ?", id).Error
|
||||
if err == nil {
|
||||
@ -125,7 +128,7 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
|
||||
s.State = dao.ServerList[s.ID].State
|
||||
} else {
|
||||
s.Host = &model.Host{}
|
||||
s.State = &model.State{}
|
||||
s.State = &model.HostState{}
|
||||
}
|
||||
dao.ServerList[s.ID] = &s
|
||||
dao.ReSortServer()
|
||||
@ -134,6 +137,42 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
type monitorForm struct {
|
||||
ID uint64
|
||||
Name string
|
||||
Target string
|
||||
Type uint8
|
||||
}
|
||||
|
||||
func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
|
||||
var mf monitorForm
|
||||
var m model.Monitor
|
||||
err := c.ShouldBindJSON(&mf)
|
||||
if err == nil {
|
||||
m.Name = mf.Name
|
||||
m.Target = mf.Target
|
||||
m.Type = mf.Type
|
||||
m.ID = mf.ID
|
||||
}
|
||||
if err == nil {
|
||||
if m.ID == 0 {
|
||||
err = dao.DB.Create(&m).Error
|
||||
} else {
|
||||
err = dao.DB.Save(&m).Error
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Response{
|
||||
Code: http.StatusBadRequest,
|
||||
Message: fmt.Sprintf("请求错误:%s", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Response{
|
||||
Code: http.StatusOK,
|
||||
})
|
||||
}
|
||||
|
||||
type notificationForm struct {
|
||||
ID uint64
|
||||
Name string
|
||||
|
@ -23,6 +23,7 @@ func (mp *memberPage) serve() {
|
||||
Redirect: "/login",
|
||||
}))
|
||||
mr.GET("/server", mp.server)
|
||||
mr.GET("/monitor", mp.monitor)
|
||||
mr.GET("/notification", mp.notification)
|
||||
mr.GET("/setting", mp.setting)
|
||||
}
|
||||
@ -36,6 +37,15 @@ func (mp *memberPage) server(c *gin.Context) {
|
||||
}))
|
||||
}
|
||||
|
||||
func (mp *memberPage) monitor(c *gin.Context) {
|
||||
var monitors []model.Monitor
|
||||
dao.DB.Find(&monitors)
|
||||
c.HTML(http.StatusOK, "dashboard/monitor", mygin.CommonEnvironment(c, gin.H{
|
||||
"Title": "服务监控",
|
||||
"Monitors": monitors,
|
||||
}))
|
||||
}
|
||||
|
||||
func (mp *memberPage) notification(c *gin.Context) {
|
||||
var nf []model.Notification
|
||||
dao.DB.Find(&nf)
|
||||
|
@ -34,14 +34,16 @@ func init() {
|
||||
}
|
||||
|
||||
func initDB() {
|
||||
dao.DB.AutoMigrate(model.Server{}, model.User{}, model.Notification{}, model.AlertRule{})
|
||||
dao.DB.AutoMigrate(model.Server{}, model.User{},
|
||||
model.Notification{}, model.AlertRule{}, model.Monitor{},
|
||||
model.MonitorHistory{})
|
||||
// load cache
|
||||
var servers []model.Server
|
||||
dao.DB.Find(&servers)
|
||||
for _, s := range servers {
|
||||
innerS := s
|
||||
innerS.Host = &model.Host{}
|
||||
innerS.State = &model.State{}
|
||||
innerS.State = &model.HostState{}
|
||||
dao.ServerList[innerS.ID] = &innerS
|
||||
}
|
||||
dao.ReSortServer()
|
||||
@ -50,5 +52,6 @@ func initDB() {
|
||||
func main() {
|
||||
go controller.ServeWeb(dao.Conf.HTTPPort)
|
||||
go rpc.ServeRPC(5555)
|
||||
go rpc.DispatchTask(time.Minute * 10)
|
||||
alertmanager.Start()
|
||||
}
|
||||
|
@ -2,15 +2,18 @@ package rpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/naiba/nezha/model"
|
||||
pb "github.com/naiba/nezha/proto"
|
||||
"github.com/naiba/nezha/service/dao"
|
||||
rpcService "github.com/naiba/nezha/service/rpc"
|
||||
)
|
||||
|
||||
// ServeRPC ...
|
||||
func ServeRPC(port uint) {
|
||||
server := grpc.NewServer()
|
||||
pb.RegisterNezhaServiceServer(server, &rpcService.NezhaHandler{
|
||||
@ -22,3 +25,34 @@ func ServeRPC(port uint) {
|
||||
}
|
||||
server.Serve(listen)
|
||||
}
|
||||
|
||||
func DispatchTask(duration time.Duration) {
|
||||
var index uint64 = 0
|
||||
for {
|
||||
var tasks []model.Monitor
|
||||
var hasAliveAgent bool
|
||||
dao.DB.Find(&tasks)
|
||||
dao.ServerLock.RLock()
|
||||
for i := 0; i < len(tasks); i++ {
|
||||
if index >= uint64(len(dao.SortedServerList)) {
|
||||
index = 0
|
||||
if !hasAliveAgent {
|
||||
break
|
||||
}
|
||||
hasAliveAgent = false
|
||||
}
|
||||
if dao.SortedServerList[index].TaskStream == nil {
|
||||
i--
|
||||
index++
|
||||
continue
|
||||
}
|
||||
hasAliveAgent = true
|
||||
log.Println("DispatchTask 确认派发 >>>>>", i, index)
|
||||
dao.SortedServerList[index].TaskStream.Send(tasks[i].PB())
|
||||
log.Println("DispatchTask 确认派发 <<<<<", i, index)
|
||||
index++
|
||||
}
|
||||
dao.ServerLock.RUnlock()
|
||||
time.Sleep(duration)
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/genkiroid/cert"
|
||||
"github.com/go-ping/ping"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conn, err := net.DialTimeout("tcp", "example.com:80", time.Second*10)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
println(conn)
|
||||
pinger, err := ping.NewPinger("example.com")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pinger.Count = 3
|
||||
err = pinger.Run() // Blocks until finished.
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("%+v", pinger.Statistics())
|
||||
certs, err := cert.NewCerts([]string{"example.com"})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(certs)
|
||||
dparts, _ := disk.Partitions(false)
|
||||
for _, part := range dparts {
|
||||
u, _ := disk.Usage(part.Mountpoint)
|
||||
@ -18,12 +43,12 @@ func main() {
|
||||
}
|
||||
|
||||
func cmdExec() {
|
||||
cmd := exec.Command("ping", "qiongbi.net", "-c2")
|
||||
cmd := exec.Command("ping", "example.com", "-c2")
|
||||
output, err := cmd.Output()
|
||||
log.Println("output:", string(output))
|
||||
log.Println("err:", err)
|
||||
|
||||
cmd = exec.Command("ping", "qiongbi", "-c2")
|
||||
cmd = exec.Command("ping", "example", "-c2")
|
||||
output, err = cmd.Output()
|
||||
log.Println("output:", string(output))
|
||||
log.Println("err:", err)
|
||||
|
2
go.mod
2
go.mod
@ -6,7 +6,9 @@ require (
|
||||
code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/genkiroid/cert v0.0.0-20191007122723-897560fbbe50
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-ping/ping v0.0.0-20201115131931-3300c582a663
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
|
6
go.sum
6
go.sum
@ -83,6 +83,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/genkiroid/cert v0.0.0-20191007122723-897560fbbe50 h1:vLwmYBduhnWWqShoUGbVgDulhcLdanoYtCQxYMzwaqQ=
|
||||
github.com/genkiroid/cert v0.0.0-20191007122723-897560fbbe50/go.mod h1:Pb7nyGYAfDyE/IkU6AJeRshIFko0wJC9cOqeYzYQffk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
@ -96,6 +98,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-ping/ping v0.0.0-20201115131931-3300c582a663 h1:jI2GiiRh+pPbey52EVmbU6kuLiXqwy4CXZ4gwUBj8Y0=
|
||||
github.com/go-ping/ping v0.0.0-20201115131931-3300c582a663/go.mod h1:35JbSyV/BYqHwwRA6Zr1uVDm1637YlNOU61wI797NPI=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
@ -417,6 +421,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -118,7 +118,7 @@ func (r *AlertRule) Check(points [][]interface{}) (int, string) {
|
||||
fail++
|
||||
}
|
||||
}
|
||||
if fail/total > 0.3 {
|
||||
if fail/total > 0.5 {
|
||||
count++
|
||||
dist.WriteString(fmt.Sprintf("%+v\n", r.Rules[i]))
|
||||
}
|
||||
|
@ -2,13 +2,10 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
// CtxKeyAuthorizedUser ..
|
||||
const CtxKeyAuthorizedUser = "ckau"
|
||||
|
||||
// CtxKeyOauth2State ..
|
||||
const CtxKeyOauth2State = "cko2s"
|
||||
|
||||
// Common ..
|
||||
type Common struct {
|
||||
ID uint64 `gorm:"primary_key"`
|
||||
CreatedAt time.Time
|
||||
@ -16,7 +13,6 @@ type Common struct {
|
||||
DeletedAt *time.Time `sql:"index"`
|
||||
}
|
||||
|
||||
// Response ..
|
||||
type Response struct {
|
||||
Code uint64 `json:"code,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
|
@ -29,7 +29,6 @@ type Config struct {
|
||||
v *viper.Viper
|
||||
}
|
||||
|
||||
// ReadInConfig ..
|
||||
func (c *Config) Read(path string) error {
|
||||
c.v = viper.New()
|
||||
c.v.SetConfigFile(path)
|
||||
|
114
model/host.go
Normal file
114
model/host.go
Normal file
@ -0,0 +1,114 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
pb "github.com/naiba/nezha/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
|
||||
MTReportHostState
|
||||
)
|
||||
|
||||
type HostState struct {
|
||||
CPU float64
|
||||
MemUsed uint64
|
||||
SwapUsed uint64
|
||||
DiskUsed uint64
|
||||
NetInTransfer uint64
|
||||
NetOutTransfer uint64
|
||||
NetInSpeed uint64
|
||||
NetOutSpeed uint64
|
||||
Uptime uint64
|
||||
}
|
||||
|
||||
func (s *HostState) PB() *pb.State {
|
||||
return &pb.State{
|
||||
Cpu: s.CPU,
|
||||
MemUsed: s.MemUsed,
|
||||
SwapUsed: s.SwapUsed,
|
||||
DiskUsed: s.DiskUsed,
|
||||
NetInTransfer: s.NetInTransfer,
|
||||
NetOutTransfer: s.NetOutTransfer,
|
||||
NetInSpeed: s.NetInSpeed,
|
||||
NetOutSpeed: s.NetOutSpeed,
|
||||
Uptime: s.Uptime,
|
||||
}
|
||||
}
|
||||
|
||||
func PB2State(s *pb.State) HostState {
|
||||
return HostState{
|
||||
CPU: s.GetCpu(),
|
||||
MemUsed: s.GetMemUsed(),
|
||||
SwapUsed: s.GetSwapUsed(),
|
||||
DiskUsed: s.GetDiskUsed(),
|
||||
NetInTransfer: s.GetNetInTransfer(),
|
||||
NetOutTransfer: s.GetNetOutTransfer(),
|
||||
NetInSpeed: s.GetNetInSpeed(),
|
||||
NetOutSpeed: s.GetNetOutSpeed(),
|
||||
Uptime: s.GetUptime(),
|
||||
}
|
||||
}
|
||||
|
||||
type Host struct {
|
||||
Platform string
|
||||
PlatformVersion string
|
||||
CPU []string
|
||||
MemTotal uint64
|
||||
DiskTotal uint64
|
||||
SwapTotal uint64
|
||||
Arch string
|
||||
Virtualization string
|
||||
BootTime uint64
|
||||
IP string `json:"-"`
|
||||
CountryCode string
|
||||
Version string
|
||||
}
|
||||
|
||||
func (h *Host) PB() *pb.Host {
|
||||
return &pb.Host{
|
||||
Platform: h.Platform,
|
||||
PlatformVersion: h.PlatformVersion,
|
||||
Cpu: h.CPU,
|
||||
MemTotal: h.MemTotal,
|
||||
DiskTotal: h.DiskTotal,
|
||||
SwapTotal: h.SwapTotal,
|
||||
Arch: h.Arch,
|
||||
Virtualization: h.Virtualization,
|
||||
BootTime: h.BootTime,
|
||||
Ip: h.IP,
|
||||
CountryCode: h.CountryCode,
|
||||
Version: h.Version,
|
||||
}
|
||||
}
|
||||
|
||||
func PB2Host(h *pb.Host) Host {
|
||||
|
||||
cpuCount := make(map[string]int, 0)
|
||||
cpus := h.GetCpu()
|
||||
for _, u := range cpus {
|
||||
cpuCount[u]++
|
||||
}
|
||||
|
||||
var distCpu []string
|
||||
for u, num := range cpuCount {
|
||||
distCpu = append(distCpu, fmt.Sprintf("%sx%d", u, num))
|
||||
}
|
||||
|
||||
return Host{
|
||||
Platform: h.GetPlatform(),
|
||||
PlatformVersion: h.GetPlatformVersion(),
|
||||
CPU: distCpu,
|
||||
MemTotal: h.GetMemTotal(),
|
||||
DiskTotal: h.GetDiskTotal(),
|
||||
SwapTotal: h.GetSwapTotal(),
|
||||
Arch: h.GetArch(),
|
||||
Virtualization: h.GetVirtualization(),
|
||||
BootTime: h.GetBootTime(),
|
||||
IP: h.GetIp(),
|
||||
CountryCode: h.GetCountryCode(),
|
||||
Version: h.GetVersion(),
|
||||
}
|
||||
}
|
119
model/monitor.go
119
model/monitor.go
@ -1,120 +1,27 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
pb "github.com/naiba/nezha/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
// MTReportState ..
|
||||
MTReportState
|
||||
MonitorTypeHTTPGET
|
||||
MonitorTypeICMPPing
|
||||
MonitorTypeTCPPing
|
||||
)
|
||||
|
||||
// State ..
|
||||
type State struct {
|
||||
CPU float64
|
||||
MemUsed uint64
|
||||
SwapUsed uint64
|
||||
DiskUsed uint64
|
||||
NetInTransfer uint64
|
||||
NetOutTransfer uint64
|
||||
NetInSpeed uint64
|
||||
NetOutSpeed uint64
|
||||
Uptime uint64
|
||||
type Monitor struct {
|
||||
Common
|
||||
Name string
|
||||
Type uint8
|
||||
Target string
|
||||
}
|
||||
|
||||
// PB ..
|
||||
func (s *State) PB() *pb.State {
|
||||
return &pb.State{
|
||||
Cpu: s.CPU,
|
||||
MemUsed: s.MemUsed,
|
||||
SwapUsed: s.SwapUsed,
|
||||
DiskUsed: s.DiskUsed,
|
||||
NetInTransfer: s.NetInTransfer,
|
||||
NetOutTransfer: s.NetOutTransfer,
|
||||
NetInSpeed: s.NetInSpeed,
|
||||
NetOutSpeed: s.NetOutSpeed,
|
||||
Uptime: s.Uptime,
|
||||
}
|
||||
}
|
||||
|
||||
// PB2State ..
|
||||
func PB2State(s *pb.State) State {
|
||||
return State{
|
||||
CPU: s.GetCpu(),
|
||||
MemUsed: s.GetMemUsed(),
|
||||
SwapUsed: s.GetSwapUsed(),
|
||||
DiskUsed: s.GetDiskUsed(),
|
||||
NetInTransfer: s.GetNetInTransfer(),
|
||||
NetOutTransfer: s.GetNetOutTransfer(),
|
||||
NetInSpeed: s.GetNetInSpeed(),
|
||||
NetOutSpeed: s.GetNetOutSpeed(),
|
||||
Uptime: s.GetUptime(),
|
||||
}
|
||||
}
|
||||
|
||||
// Host ..
|
||||
type Host struct {
|
||||
Platform string
|
||||
PlatformVersion string
|
||||
CPU []string
|
||||
MemTotal uint64
|
||||
DiskTotal uint64
|
||||
SwapTotal uint64
|
||||
Arch string
|
||||
Virtualization string
|
||||
BootTime uint64
|
||||
IP string `json:"-"`
|
||||
CountryCode string
|
||||
Version string
|
||||
}
|
||||
|
||||
// PB ..
|
||||
func (h *Host) PB() *pb.Host {
|
||||
return &pb.Host{
|
||||
Platform: h.Platform,
|
||||
PlatformVersion: h.PlatformVersion,
|
||||
Cpu: h.CPU,
|
||||
MemTotal: h.MemTotal,
|
||||
DiskTotal: h.DiskTotal,
|
||||
SwapTotal: h.SwapTotal,
|
||||
Arch: h.Arch,
|
||||
Virtualization: h.Virtualization,
|
||||
BootTime: h.BootTime,
|
||||
Ip: h.IP,
|
||||
CountryCode: h.CountryCode,
|
||||
Version: h.Version,
|
||||
}
|
||||
}
|
||||
|
||||
// PB2Host ...
|
||||
func PB2Host(h *pb.Host) Host {
|
||||
|
||||
cpuCount := make(map[string]int, 0)
|
||||
cpus := h.GetCpu()
|
||||
for _, u := range cpus {
|
||||
cpuCount[u]++
|
||||
}
|
||||
|
||||
var distCpu []string
|
||||
for u, num := range cpuCount {
|
||||
distCpu = append(distCpu, fmt.Sprintf("%sx%d", u, num))
|
||||
}
|
||||
|
||||
return Host{
|
||||
Platform: h.GetPlatform(),
|
||||
PlatformVersion: h.GetPlatformVersion(),
|
||||
CPU: distCpu,
|
||||
MemTotal: h.GetMemTotal(),
|
||||
DiskTotal: h.GetDiskTotal(),
|
||||
SwapTotal: h.GetSwapTotal(),
|
||||
Arch: h.GetArch(),
|
||||
Virtualization: h.GetVirtualization(),
|
||||
BootTime: h.GetBootTime(),
|
||||
IP: h.GetIp(),
|
||||
CountryCode: h.GetCountryCode(),
|
||||
Version: h.GetVersion(),
|
||||
func (m *Monitor) PB() *pb.Task {
|
||||
return &pb.Task{
|
||||
Id: m.ID,
|
||||
Type: uint64(m.Type),
|
||||
Data: m.Target,
|
||||
}
|
||||
}
|
||||
|
22
model/monitor_history.go
Normal file
22
model/monitor_history.go
Normal file
@ -0,0 +1,22 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
pb "github.com/naiba/nezha/proto"
|
||||
)
|
||||
|
||||
type MonitorHistory struct {
|
||||
Common
|
||||
MonitorID uint64
|
||||
Delay float32 // 延迟,毫秒
|
||||
Data string
|
||||
Successful bool // 是否成功
|
||||
}
|
||||
|
||||
func PB2MonitorHistory(r *pb.TaskResult) MonitorHistory {
|
||||
return MonitorHistory{
|
||||
Delay: r.GetDelay(),
|
||||
Successful: r.GetSuccessful(),
|
||||
MonitorID: r.GetId(),
|
||||
Data: r.GetData(),
|
||||
}
|
||||
}
|
@ -8,19 +8,18 @@ import (
|
||||
pb "github.com/naiba/nezha/proto"
|
||||
)
|
||||
|
||||
// Server ..
|
||||
type Server struct {
|
||||
Common
|
||||
Name string
|
||||
DisplayIndex int // 展示权重,越大越靠前
|
||||
Secret string `json:"-"`
|
||||
Tag string
|
||||
Host *Host `gorm:"-"`
|
||||
State *State `gorm:"-"`
|
||||
Host *Host `gorm:"-"`
|
||||
State *HostState `gorm:"-"`
|
||||
LastActive time.Time
|
||||
|
||||
Stream pb.NezhaService_HeartbeatServer `gorm:"-" json:"-"`
|
||||
StreamClose chan<- error `gorm:"-" json:"-"`
|
||||
TaskClose chan error `gorm:"-" json:"-"`
|
||||
TaskStream pb.NezhaService_RequestTaskServer `gorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
func (s Server) Marshal() template.JS {
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"github.com/naiba/com"
|
||||
)
|
||||
|
||||
// User ...
|
||||
type User struct {
|
||||
Common
|
||||
Login string `gorm:"UNIQUE_INDEX" json:"login,omitempty"` // 登录名
|
||||
@ -26,7 +25,6 @@ type User struct {
|
||||
TeamsID []uint64 `gorm:"-"`
|
||||
}
|
||||
|
||||
// NewUserFromGitHub ..
|
||||
func NewUserFromGitHub(gu *github.User) User {
|
||||
var u User
|
||||
u.ID = uint64(gu.GetID())
|
||||
@ -45,7 +43,6 @@ func NewUserFromGitHub(gu *github.User) User {
|
||||
return u
|
||||
}
|
||||
|
||||
// IssueNewToken ...
|
||||
func (u *User) IssueNewToken() {
|
||||
u.Token = com.MD5(fmt.Sprintf("%d%d%s", time.Now().UnixNano(), u.ID, u.Login))
|
||||
u.TokenExpired = time.Now().AddDate(0, 2, 0)
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"github.com/naiba/nezha/service/dao"
|
||||
)
|
||||
|
||||
// AuthorizeOption ..
|
||||
type AuthorizeOption struct {
|
||||
Guest bool
|
||||
Member bool
|
||||
@ -21,7 +20,6 @@ type AuthorizeOption struct {
|
||||
Btn string
|
||||
}
|
||||
|
||||
// Authorize ..
|
||||
func Authorize(opt AuthorizeOption) func(*gin.Context) {
|
||||
return func(c *gin.Context) {
|
||||
token, err := c.Cookie(dao.Conf.Site.CookieName)
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"github.com/naiba/nezha/model"
|
||||
)
|
||||
|
||||
// ErrInfo ..
|
||||
type ErrInfo struct {
|
||||
Code uint64
|
||||
Title string
|
||||
@ -17,7 +16,6 @@ type ErrInfo struct {
|
||||
Btn string
|
||||
}
|
||||
|
||||
// ShowErrorPage ..
|
||||
func ShowErrorPage(c *gin.Context, i ErrInfo, isPage bool) {
|
||||
if isPage {
|
||||
c.HTML(http.StatusOK, "dashboard/error", CommonEnvironment(c, gin.H{
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"github.com/naiba/nezha/service/dao"
|
||||
)
|
||||
|
||||
// CommonEnvironment ..
|
||||
func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
|
||||
data["MatchedPath"] = c.MustGet("MatchedPath")
|
||||
data["Version"] = dao.Version
|
||||
@ -27,7 +26,6 @@ func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
|
||||
return data
|
||||
}
|
||||
|
||||
// RecordPath ..
|
||||
func RecordPath(c *gin.Context) {
|
||||
url := c.Request.URL.String()
|
||||
for _, p := range c.Params {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.13.0
|
||||
// protoc v3.14.0
|
||||
// source: proto/nezha.proto
|
||||
|
||||
package proto
|
||||
@ -275,6 +275,148 @@ func (x *State) GetUptime() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
type Task struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Type uint64 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Task) Reset() {
|
||||
*x = Task{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_nezha_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Task) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Task) ProtoMessage() {}
|
||||
|
||||
func (x *Task) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_nezha_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Task.ProtoReflect.Descriptor instead.
|
||||
func (*Task) Descriptor() ([]byte, []int) {
|
||||
return file_proto_nezha_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Task) GetId() uint64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Task) GetType() uint64 {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Task) GetData() string {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type TaskResult struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Type uint64 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Delay float32 `protobuf:"fixed32,3,opt,name=delay,proto3" json:"delay,omitempty"`
|
||||
Data string `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
|
||||
Successful bool `protobuf:"varint,5,opt,name=successful,proto3" json:"successful,omitempty"`
|
||||
}
|
||||
|
||||
func (x *TaskResult) Reset() {
|
||||
*x = TaskResult{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_nezha_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *TaskResult) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TaskResult) ProtoMessage() {}
|
||||
|
||||
func (x *TaskResult) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_nezha_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TaskResult.ProtoReflect.Descriptor instead.
|
||||
func (*TaskResult) Descriptor() ([]byte, []int) {
|
||||
return file_proto_nezha_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *TaskResult) GetId() uint64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TaskResult) GetType() uint64 {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TaskResult) GetDelay() float32 {
|
||||
if x != nil {
|
||||
return x.Delay
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TaskResult) GetData() string {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TaskResult) GetSuccessful() bool {
|
||||
if x != nil {
|
||||
return x.Successful
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Receipt struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -286,7 +428,7 @@ type Receipt struct {
|
||||
func (x *Receipt) Reset() {
|
||||
*x = Receipt{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_nezha_proto_msgTypes[2]
|
||||
mi := &file_proto_nezha_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -299,7 +441,7 @@ func (x *Receipt) String() string {
|
||||
func (*Receipt) ProtoMessage() {}
|
||||
|
||||
func (x *Receipt) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_nezha_proto_msgTypes[2]
|
||||
mi := &file_proto_nezha_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -312,7 +454,7 @@ func (x *Receipt) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Receipt.ProtoReflect.Descriptor instead.
|
||||
func (*Receipt) Descriptor() ([]byte, []int) {
|
||||
return file_proto_nezha_proto_rawDescGZIP(), []int{2}
|
||||
return file_proto_nezha_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *Receipt) GetProced() bool {
|
||||
@ -322,108 +464,6 @@ func (x *Receipt) GetProced() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type Beat struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Timestamp string `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Beat) Reset() {
|
||||
*x = Beat{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_nezha_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Beat) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Beat) ProtoMessage() {}
|
||||
|
||||
func (x *Beat) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_nezha_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Beat.ProtoReflect.Descriptor instead.
|
||||
func (*Beat) Descriptor() ([]byte, []int) {
|
||||
return file_proto_nezha_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Beat) GetTimestamp() string {
|
||||
if x != nil {
|
||||
return x.Timestamp
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Command struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Type uint64 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Data string `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Command) Reset() {
|
||||
*x = Command{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_nezha_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Command) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Command) ProtoMessage() {}
|
||||
|
||||
func (x *Command) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_nezha_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Command.ProtoReflect.Descriptor instead.
|
||||
func (*Command) Descriptor() ([]byte, []int) {
|
||||
return file_proto_nezha_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *Command) GetType() uint64 {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Command) GetData() string {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_proto_nezha_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_proto_nezha_proto_rawDesc = []byte{
|
||||
@ -468,25 +508,36 @@ var file_proto_nezha_proto_rawDesc = []byte{
|
||||
0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x70,
|
||||
0x65, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x4f, 0x75,
|
||||
0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x21,
|
||||
0x0a, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x63, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65,
|
||||
0x64, 0x22, 0x24, 0x0a, 0x04, 0x42, 0x65, 0x61, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d,
|
||||
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69,
|
||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x31, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x96, 0x01, 0x0a, 0x0c, 0x4e,
|
||||
0x65, 0x7a, 0x68, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x09, 0x48,
|
||||
0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x42, 0x65, 0x61, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2d, 0x0a, 0x0b, 0x52, 0x65, 0x70,
|
||||
0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52,
|
||||
0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x29, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69,
|
||||
0x73, 0x74, 0x65, 0x72, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x6f, 0x73,
|
||||
0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70,
|
||||
0x74, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x3e,
|
||||
0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61,
|
||||
0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x7a,
|
||||
0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0e, 0x0a, 0x02,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52,
|
||||
0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x75,
|
||||
0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a,
|
||||
0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x22, 0x21, 0x0a, 0x07, 0x52, 0x65,
|
||||
0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x32, 0xd6, 0x01,
|
||||
0x0a, 0x0c, 0x4e, 0x65, 0x7a, 0x68, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33,
|
||||
0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x53, 0x74,
|
||||
0x61, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74,
|
||||
0x65, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70,
|
||||
0x74, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73,
|
||||
0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63,
|
||||
0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74,
|
||||
0x54, 0x61, 0x73, 0x6b, 0x12, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73,
|
||||
0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x0b, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61,
|
||||
0x73, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x42, 0x07, 0x5a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -503,21 +554,23 @@ func file_proto_nezha_proto_rawDescGZIP() []byte {
|
||||
|
||||
var file_proto_nezha_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_proto_nezha_proto_goTypes = []interface{}{
|
||||
(*Host)(nil), // 0: proto.Host
|
||||
(*State)(nil), // 1: proto.State
|
||||
(*Receipt)(nil), // 2: proto.Receipt
|
||||
(*Beat)(nil), // 3: proto.Beat
|
||||
(*Command)(nil), // 4: proto.Command
|
||||
(*Host)(nil), // 0: proto.Host
|
||||
(*State)(nil), // 1: proto.State
|
||||
(*Task)(nil), // 2: proto.Task
|
||||
(*TaskResult)(nil), // 3: proto.TaskResult
|
||||
(*Receipt)(nil), // 4: proto.Receipt
|
||||
}
|
||||
var file_proto_nezha_proto_depIdxs = []int32{
|
||||
3, // 0: proto.NezhaService.Heartbeat:input_type -> proto.Beat
|
||||
1, // 1: proto.NezhaService.ReportState:input_type -> proto.State
|
||||
0, // 2: proto.NezhaService.Register:input_type -> proto.Host
|
||||
4, // 3: proto.NezhaService.Heartbeat:output_type -> proto.Command
|
||||
2, // 4: proto.NezhaService.ReportState:output_type -> proto.Receipt
|
||||
2, // 5: proto.NezhaService.Register:output_type -> proto.Receipt
|
||||
3, // [3:6] is the sub-list for method output_type
|
||||
0, // [0:3] is the sub-list for method input_type
|
||||
1, // 0: proto.NezhaService.ReportSystemState:input_type -> proto.State
|
||||
0, // 1: proto.NezhaService.ReportSystemInfo:input_type -> proto.Host
|
||||
3, // 2: proto.NezhaService.ReportTask:input_type -> proto.TaskResult
|
||||
0, // 3: proto.NezhaService.RequestTask:input_type -> proto.Host
|
||||
4, // 4: proto.NezhaService.ReportSystemState:output_type -> proto.Receipt
|
||||
4, // 5: proto.NezhaService.ReportSystemInfo:output_type -> proto.Receipt
|
||||
4, // 6: proto.NezhaService.ReportTask:output_type -> proto.Receipt
|
||||
2, // 7: proto.NezhaService.RequestTask:output_type -> proto.Task
|
||||
4, // [4:8] is the sub-list for method output_type
|
||||
0, // [0:4] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
@ -554,7 +607,7 @@ func file_proto_nezha_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_nezha_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Receipt); i {
|
||||
switch v := v.(*Task); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -566,7 +619,7 @@ func file_proto_nezha_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_nezha_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Beat); i {
|
||||
switch v := v.(*TaskResult); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -578,7 +631,7 @@ func file_proto_nezha_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_nezha_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Command); i {
|
||||
switch v := v.(*Receipt); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -622,9 +675,10 @@ const _ = grpc.SupportPackageIsVersion6
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type NezhaServiceClient interface {
|
||||
Heartbeat(ctx context.Context, in *Beat, opts ...grpc.CallOption) (NezhaService_HeartbeatClient, error)
|
||||
ReportState(ctx context.Context, in *State, opts ...grpc.CallOption) (*Receipt, error)
|
||||
Register(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error)
|
||||
ReportSystemState(ctx context.Context, in *State, opts ...grpc.CallOption) (*Receipt, error)
|
||||
ReportSystemInfo(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error)
|
||||
ReportTask(ctx context.Context, in *TaskResult, opts ...grpc.CallOption) (*Receipt, error)
|
||||
RequestTask(ctx context.Context, in *Host, opts ...grpc.CallOption) (NezhaService_RequestTaskClient, error)
|
||||
}
|
||||
|
||||
type nezhaServiceClient struct {
|
||||
@ -635,12 +689,39 @@ func NewNezhaServiceClient(cc grpc.ClientConnInterface) NezhaServiceClient {
|
||||
return &nezhaServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *nezhaServiceClient) Heartbeat(ctx context.Context, in *Beat, opts ...grpc.CallOption) (NezhaService_HeartbeatClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_NezhaService_serviceDesc.Streams[0], "/proto.NezhaService/Heartbeat", opts...)
|
||||
func (c *nezhaServiceClient) ReportSystemState(ctx context.Context, in *State, opts ...grpc.CallOption) (*Receipt, error) {
|
||||
out := new(Receipt)
|
||||
err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportSystemState", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &nezhaServiceHeartbeatClient{stream}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *nezhaServiceClient) ReportSystemInfo(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error) {
|
||||
out := new(Receipt)
|
||||
err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportSystemInfo", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *nezhaServiceClient) ReportTask(ctx context.Context, in *TaskResult, opts ...grpc.CallOption) (*Receipt, error) {
|
||||
out := new(Receipt)
|
||||
err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportTask", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *nezhaServiceClient) RequestTask(ctx context.Context, in *Host, opts ...grpc.CallOption) (NezhaService_RequestTaskClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_NezhaService_serviceDesc.Streams[0], "/proto.NezhaService/RequestTask", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &nezhaServiceRequestTaskClient{stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -650,140 +731,148 @@ func (c *nezhaServiceClient) Heartbeat(ctx context.Context, in *Beat, opts ...gr
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type NezhaService_HeartbeatClient interface {
|
||||
Recv() (*Command, error)
|
||||
type NezhaService_RequestTaskClient interface {
|
||||
Recv() (*Task, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type nezhaServiceHeartbeatClient struct {
|
||||
type nezhaServiceRequestTaskClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *nezhaServiceHeartbeatClient) Recv() (*Command, error) {
|
||||
m := new(Command)
|
||||
func (x *nezhaServiceRequestTaskClient) Recv() (*Task, error) {
|
||||
m := new(Task)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *nezhaServiceClient) ReportState(ctx context.Context, in *State, opts ...grpc.CallOption) (*Receipt, error) {
|
||||
out := new(Receipt)
|
||||
err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportState", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *nezhaServiceClient) Register(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error) {
|
||||
out := new(Receipt)
|
||||
err := c.cc.Invoke(ctx, "/proto.NezhaService/Register", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// NezhaServiceServer is the server API for NezhaService service.
|
||||
type NezhaServiceServer interface {
|
||||
Heartbeat(*Beat, NezhaService_HeartbeatServer) error
|
||||
ReportState(context.Context, *State) (*Receipt, error)
|
||||
Register(context.Context, *Host) (*Receipt, error)
|
||||
ReportSystemState(context.Context, *State) (*Receipt, error)
|
||||
ReportSystemInfo(context.Context, *Host) (*Receipt, error)
|
||||
ReportTask(context.Context, *TaskResult) (*Receipt, error)
|
||||
RequestTask(*Host, NezhaService_RequestTaskServer) error
|
||||
}
|
||||
|
||||
// UnimplementedNezhaServiceServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedNezhaServiceServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedNezhaServiceServer) Heartbeat(*Beat, NezhaService_HeartbeatServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method Heartbeat not implemented")
|
||||
func (*UnimplementedNezhaServiceServer) ReportSystemState(context.Context, *State) (*Receipt, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ReportSystemState not implemented")
|
||||
}
|
||||
func (*UnimplementedNezhaServiceServer) ReportState(context.Context, *State) (*Receipt, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ReportState not implemented")
|
||||
func (*UnimplementedNezhaServiceServer) ReportSystemInfo(context.Context, *Host) (*Receipt, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ReportSystemInfo not implemented")
|
||||
}
|
||||
func (*UnimplementedNezhaServiceServer) Register(context.Context, *Host) (*Receipt, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Register not implemented")
|
||||
func (*UnimplementedNezhaServiceServer) ReportTask(context.Context, *TaskResult) (*Receipt, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ReportTask not implemented")
|
||||
}
|
||||
func (*UnimplementedNezhaServiceServer) RequestTask(*Host, NezhaService_RequestTaskServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method RequestTask not implemented")
|
||||
}
|
||||
|
||||
func RegisterNezhaServiceServer(s *grpc.Server, srv NezhaServiceServer) {
|
||||
s.RegisterService(&_NezhaService_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _NezhaService_Heartbeat_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(Beat)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(NezhaServiceServer).Heartbeat(m, &nezhaServiceHeartbeatServer{stream})
|
||||
}
|
||||
|
||||
type NezhaService_HeartbeatServer interface {
|
||||
Send(*Command) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type nezhaServiceHeartbeatServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *nezhaServiceHeartbeatServer) Send(m *Command) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func _NezhaService_ReportState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
func _NezhaService_ReportSystemState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(State)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(NezhaServiceServer).ReportState(ctx, in)
|
||||
return srv.(NezhaServiceServer).ReportSystemState(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.NezhaService/ReportState",
|
||||
FullMethod: "/proto.NezhaService/ReportSystemState",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(NezhaServiceServer).ReportState(ctx, req.(*State))
|
||||
return srv.(NezhaServiceServer).ReportSystemState(ctx, req.(*State))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _NezhaService_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
func _NezhaService_ReportSystemInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Host)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(NezhaServiceServer).Register(ctx, in)
|
||||
return srv.(NezhaServiceServer).ReportSystemInfo(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.NezhaService/Register",
|
||||
FullMethod: "/proto.NezhaService/ReportSystemInfo",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(NezhaServiceServer).Register(ctx, req.(*Host))
|
||||
return srv.(NezhaServiceServer).ReportSystemInfo(ctx, req.(*Host))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _NezhaService_ReportTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(TaskResult)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(NezhaServiceServer).ReportTask(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.NezhaService/ReportTask",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(NezhaServiceServer).ReportTask(ctx, req.(*TaskResult))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _NezhaService_RequestTask_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(Host)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(NezhaServiceServer).RequestTask(m, &nezhaServiceRequestTaskServer{stream})
|
||||
}
|
||||
|
||||
type NezhaService_RequestTaskServer interface {
|
||||
Send(*Task) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type nezhaServiceRequestTaskServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *nezhaServiceRequestTaskServer) Send(m *Task) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
var _NezhaService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "proto.NezhaService",
|
||||
HandlerType: (*NezhaServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "ReportState",
|
||||
Handler: _NezhaService_ReportState_Handler,
|
||||
MethodName: "ReportSystemState",
|
||||
Handler: _NezhaService_ReportSystemState_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Register",
|
||||
Handler: _NezhaService_Register_Handler,
|
||||
MethodName: "ReportSystemInfo",
|
||||
Handler: _NezhaService_ReportSystemInfo_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ReportTask",
|
||||
Handler: _NezhaService_ReportTask_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "Heartbeat",
|
||||
Handler: _NezhaService_Heartbeat_Handler,
|
||||
StreamName: "RequestTask",
|
||||
Handler: _NezhaService_RequestTask_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
|
@ -1,11 +1,13 @@
|
||||
syntax = "proto3";
|
||||
option go_package = "proto";
|
||||
|
||||
package proto;
|
||||
|
||||
service NezhaService {
|
||||
rpc Heartbeat(Beat)returns(stream Command){}
|
||||
rpc ReportState(State)returns(Receipt){}
|
||||
rpc Register(Host)returns(Receipt){}
|
||||
rpc ReportSystemState(State)returns(Receipt){}
|
||||
rpc ReportSystemInfo(Host)returns(Receipt){}
|
||||
rpc ReportTask(TaskResult)returns(Receipt){}
|
||||
rpc RequestTask(Host)returns(stream Task){}
|
||||
}
|
||||
|
||||
message Host {
|
||||
@ -35,15 +37,20 @@ message State {
|
||||
uint64 uptime = 10;
|
||||
}
|
||||
|
||||
message Task {
|
||||
uint64 id = 1;
|
||||
uint64 type = 2;
|
||||
string data = 3;
|
||||
}
|
||||
|
||||
message TaskResult {
|
||||
uint64 id = 1;
|
||||
uint64 type = 2;
|
||||
float delay = 3;
|
||||
string data = 4;
|
||||
bool successful = 5;
|
||||
}
|
||||
|
||||
message Receipt{
|
||||
bool proced = 1;
|
||||
}
|
||||
|
||||
message Beat {
|
||||
string timestamp = 1;
|
||||
}
|
||||
|
||||
message Command {
|
||||
uint64 type = 1;
|
||||
string data = 2;
|
||||
}
|
||||
|
@ -76,4 +76,57 @@
|
||||
line-height: 1.75em;
|
||||
color: rgba(255, 255, 255, .7);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.service-status .round>i {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: .5rem;
|
||||
display: inline-block;
|
||||
margin-right: .3rem;
|
||||
background-color: slategray;
|
||||
}
|
||||
|
||||
.service-status .danger.button {
|
||||
background-color: crimson;
|
||||
}
|
||||
|
||||
.service-status .good.button {
|
||||
background-color: rgb(0, 235, 139);
|
||||
}
|
||||
|
||||
.service-status .warning.button {
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.service-status .danger>i {
|
||||
background-color: crimson;
|
||||
}
|
||||
|
||||
.service-status .good>i {
|
||||
background-color: rgb(0, 235, 139);
|
||||
}
|
||||
|
||||
.service-status .warning>i {
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.service-status .three.column p {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.service-status .three.column p:last-child {
|
||||
float: right;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.service-status .eleven.column {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.service-status .eleven.column>.ui.button {
|
||||
width: 8px !important;
|
||||
padding: unset !important;
|
||||
margin-top: unset !important;
|
||||
margin-bottom: unset !important;
|
||||
}
|
@ -39,7 +39,7 @@ function showFormModal(modelSelector, formID, URL, getData) {
|
||||
obj[item.name] = (item.name.endsWith('_id') ||
|
||||
item.name === 'id' || item.name === 'ID' ||
|
||||
item.name === 'RequestType' || item.name === 'RequestMethod' ||
|
||||
item.name === 'DisplayIndex') ? parseInt(item.value) : item.value;
|
||||
item.name === 'DisplayIndex' || item.name === 'Type') ? parseInt(item.value) : item.value;
|
||||
return obj;
|
||||
}, {});
|
||||
$.post(URL, JSON.stringify(data)).done(function (resp) {
|
||||
@ -118,6 +118,17 @@ function addOrEditServer(server) {
|
||||
showFormModal('.server.modal', '#serverForm', '/api/server')
|
||||
}
|
||||
|
||||
function addOrEditMonitor(monitor) {
|
||||
const modal = $('.monitor.modal')
|
||||
modal.children('.header').text((monitor ? '修改' : '添加') + '监控')
|
||||
modal.find('.positive.button').html(monitor ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>')
|
||||
modal.find('input[name=ID]').val(monitor ? monitor.ID : null)
|
||||
modal.find('input[name=Name]').val(monitor ? monitor.Name : null)
|
||||
modal.find('input[name=Target]').val(monitor ? monitor.Target : null)
|
||||
modal.find('select[name=Type]').val(monitor ? monitor.Type : 1)
|
||||
showFormModal('.monitor.modal', '#monitorForm', '/api/monitor')
|
||||
}
|
||||
|
||||
function deleteRequest(api) {
|
||||
$.ajax({
|
||||
url: api,
|
||||
|
@ -1,8 +1,7 @@
|
||||
{{define "common/footer"}}
|
||||
<div class="ui inverted vertical footer segment">
|
||||
<div class="ui center aligned is-size-7 container">
|
||||
Powered by <a href="https://github.com/naiba/nezha" style="color: white;" target="_blank">哪吒面板</a> build ·
|
||||
{{.Version}}
|
||||
Powered by <a href="https://github.com/naiba/nezha" style="color: white;" target="_blank">哪吒面板</a> {{.Version}}
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<title>{{.Title}}</title>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.1/dist/semantic.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="/static/main.css?v202012252026">
|
||||
<link rel="stylesheet" type="text/css" href="/static/main.css?v202101160044">
|
||||
<link rel="shortcut icon" type="image/png" href="/static/logo.png" />
|
||||
</head>
|
||||
|
||||
|
@ -5,13 +5,14 @@
|
||||
<img src="/static/logo.png">
|
||||
</div>
|
||||
<a class="item{{if eq .MatchedPath " /"}} active{{end}}" href="/">首页</a>
|
||||
<a class="item{{if eq .MatchedPath " /service"}} active{{end}}" href="/service">服务状态</a>
|
||||
{{if .Admin}}
|
||||
<a class="item{{if eq .MatchedPath " /server"}} active{{end}}" href="/server">服务器</a>
|
||||
<a class="item{{if eq .MatchedPath " /monitor"}} active{{end}}" href="/monitor">监控</a>
|
||||
<a class="item{{if eq .MatchedPath " /notification"}} active{{end}}" href="/notification">通知</a>
|
||||
<a class="item{{if eq .MatchedPath " /setting"}} active{{end}}" href="/setting">设置</a>
|
||||
{{end}}
|
||||
<div class="right menu">
|
||||
<a class="item" href="https://github.com/naiba/nezha/issues" target="_blank">反馈</a>
|
||||
<div class="item">
|
||||
{{if .Admin}}
|
||||
<div class="ui simple dropdown">
|
||||
|
31
resource/template/component/monitor.html
Normal file
31
resource/template/component/monitor.html
Normal file
@ -0,0 +1,31 @@
|
||||
{{define "component/monitor"}}
|
||||
<div class="ui tiny monitor modal transition hidden">
|
||||
<div class="header">添加监控</div>
|
||||
<div class="content">
|
||||
<form id="monitorForm" class="ui form">
|
||||
<input type="hidden" name="ID">
|
||||
<div class="field">
|
||||
<label>备注</label>
|
||||
<input type="text" name="Name" placeholder="博客">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>目标</label>
|
||||
<input type="text" name="Target" placeholder="https://t.tt,t.tt,t.tt:80">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>类型</label>
|
||||
<select name="Type" class="ui fluid dropdown">
|
||||
<option value="1">HTTP-GET</option>
|
||||
<option value="2">ICMP-Ping</option>
|
||||
<option value="3">TCP-Ping</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class=" actions">
|
||||
<div class="ui negative button">取消</div>
|
||||
<button class="ui positive right labeled icon button">确认<i class="checkmark icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
49
resource/template/dashboard/monitor.html
Normal file
49
resource/template/dashboard/monitor.html
Normal file
@ -0,0 +1,49 @@
|
||||
{{define "dashboard/monitor"}}
|
||||
{{template "common/header" .}}
|
||||
{{template "common/menu" .}}
|
||||
<div class="nb-container">
|
||||
<div class="ui container">
|
||||
<div class="ui grid">
|
||||
<div class="right floated right aligned twelve wide column">
|
||||
<button class="ui right labeled positive icon button" onclick="addOrEditMonitor()"><i
|
||||
class="add icon"></i> 添加监控
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<table class="ui very basic table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>备注</th>
|
||||
<th>类型</th>
|
||||
<th>目标</th>
|
||||
<th>管理</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $monitor := .Monitors}}
|
||||
<tr>
|
||||
<td>{{$monitor.ID}}</td>
|
||||
<td>{{$monitor.Name}}</td>
|
||||
<td>{{$monitor.Target}}</td>
|
||||
<td>{{$monitor.Type}}</td>
|
||||
<td>
|
||||
<div class="ui mini icon buttons">
|
||||
<button class="ui button" onclick="addOrEditMonitor({{$monitor}})">
|
||||
<i class="edit icon"></i>
|
||||
</button>
|
||||
<button class="ui button"
|
||||
onclick="showConfirm('删除监控','确认删除此监控?',deleteRequest,'/api/monitor/'+{{$monitor.ID}})">
|
||||
<i class="delete icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{template "component/monitor"}}
|
||||
{{template "common/footer" .}}
|
||||
{{end}}
|
@ -14,8 +14,8 @@
|
||||
</div>
|
||||
<div class="field">
|
||||
<select name="Theme">
|
||||
<option value="default">默认主题</option>
|
||||
<option value="hotaru">CakeMine-Hotaru</option>
|
||||
<option value="default"{{if eq .Conf.Site.Theme "default"}} selected="selected"{{end}}>默认主题</option>
|
||||
<option value="hotaru"{{if eq .Conf.Site.Theme "hotaru"}} selected="selected"{{end}}>CokeMine Hotaru</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
|
42
resource/template/theme-default/service.html
Normal file
42
resource/template/theme-default/service.html
Normal file
@ -0,0 +1,42 @@
|
||||
{{define "theme-default/service"}}
|
||||
{{template "common/header" .}}
|
||||
{{template "common/menu" .}}
|
||||
<div class="nb-container">
|
||||
<div class="ui container">
|
||||
<div class="ui segment service-status">
|
||||
{{range $service := .Services}}
|
||||
<div class="ui grid">
|
||||
<div class="three wide column">
|
||||
<p>{{$service.Monitor.Name}}</p>
|
||||
<p>30天在线率{{divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)}}%</p>
|
||||
</div>
|
||||
<div class="eleven wide column">
|
||||
{{range $i,$d := $service.Delay}}
|
||||
<div class="ui icon button{{if gt (add (index $service.Up $i) (index $service.Down $i)) 0}}
|
||||
{{if gt (div (index $service.Down $i) (add (index $service.Up $i) (index $service.Down $i))) 30.0}}danger
|
||||
{{else if gt (div (index $service.Down $i) (add (index $service.Up $i) (index $service.Down $i))) 10.0}}
|
||||
warning{{else}}good{{end}}
|
||||
{{end}}" data-tooltip="{{dayBefore $i}},平均延迟:{{$d}}ms">
|
||||
<i class="delay"></i>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="two wide column round{{if gt (addU64 $service.TotalUp $service.TotalDown) 0}}
|
||||
{{if gt (divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)) 30.0}}danger{{else if gt (divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)) 10.0}}warning{{else}}good{{end}}
|
||||
{{end}}">
|
||||
<i></i>
|
||||
{{if gt (addU64 $service.TotalUp $service.TotalDown) 0}}
|
||||
{{if gt (divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)) 30.0}}故障
|
||||
{{else if gt (divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)) 10.0}}
|
||||
低可用{{else}}良好{{end}}
|
||||
{{else}}无数据
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "common/footer" .}}
|
||||
{{end}}
|
@ -8,7 +8,6 @@ import (
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/naiba/nezha/model"
|
||||
pb "github.com/naiba/nezha/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -16,30 +15,18 @@ const (
|
||||
ReportDelay = 2
|
||||
)
|
||||
|
||||
// Conf ..
|
||||
var Conf *model.Config
|
||||
|
||||
// Cache ..
|
||||
var Cache *cache.Cache
|
||||
|
||||
// DB ..
|
||||
var DB *gorm.DB
|
||||
|
||||
// ServerList ..
|
||||
var ServerList map[uint64]*model.Server
|
||||
var SortedServerList []*model.Server
|
||||
|
||||
// ServerLock ..
|
||||
var ServerLock sync.RWMutex
|
||||
|
||||
// Version ..
|
||||
var Version = "debug"
|
||||
|
||||
func init() {
|
||||
if len(Version) > 7 {
|
||||
Version = Version[:7]
|
||||
}
|
||||
}
|
||||
var Version = "v0.2.0"
|
||||
|
||||
func ReSortServer() {
|
||||
SortedServerList = []*model.Server{}
|
||||
@ -51,19 +38,3 @@ func ReSortServer() {
|
||||
return SortedServerList[i].DisplayIndex > SortedServerList[j].DisplayIndex
|
||||
})
|
||||
}
|
||||
|
||||
// SendCommand ..
|
||||
func SendCommand(cmd *pb.Command) {
|
||||
ServerLock.RLock()
|
||||
defer ServerLock.RUnlock()
|
||||
var err error
|
||||
for _, server := range ServerList {
|
||||
if server.Stream != nil {
|
||||
err = server.Stream.Send(cmd)
|
||||
if err != nil {
|
||||
close(server.StreamClose)
|
||||
server.Stream = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ type ipDotSbGeoIP struct {
|
||||
|
||||
var netInSpeed, netOutSpeed, netInTransfer, netOutTransfer, lastUpdate uint64
|
||||
|
||||
// GetHost ..
|
||||
func GetHost() *model.Host {
|
||||
hi, _ := host.Info()
|
||||
var cpus []string
|
||||
@ -60,8 +59,7 @@ func GetHost() *model.Host {
|
||||
}
|
||||
}
|
||||
|
||||
// GetState ..
|
||||
func GetState(delay int64) *model.State {
|
||||
func GetState(delay int64) *model.HostState {
|
||||
hi, _ := host.Info()
|
||||
// Memory
|
||||
mv, _ := mem.VirtualMemory()
|
||||
@ -75,7 +73,7 @@ func GetState(delay int64) *model.State {
|
||||
// Disk
|
||||
u, _ := disk.Usage("/")
|
||||
|
||||
return &model.State{
|
||||
return &model.HostState{
|
||||
CPU: cpuPercent,
|
||||
MemUsed: mv.Used,
|
||||
SwapUsed: ms.Used,
|
||||
@ -88,7 +86,6 @@ func GetState(delay int64) *model.State {
|
||||
}
|
||||
}
|
||||
|
||||
// TrackNetworkSpeed ..
|
||||
func TrackNetworkSpeed() {
|
||||
var innerNetInTransfer, innerNetOutTransfer uint64
|
||||
nc, err := net.IOCounters(false)
|
||||
|
@ -10,23 +10,19 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// AuthHandler ..
|
||||
type AuthHandler struct {
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
}
|
||||
|
||||
// GetRequestMetadata ..
|
||||
func (a *AuthHandler) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||||
return map[string]string{"client_id": a.ClientID, "client_secret": a.ClientSecret}, nil
|
||||
}
|
||||
|
||||
// RequireTransportSecurity ..
|
||||
func (a *AuthHandler) RequireTransportSecurity() bool {
|
||||
return !dao.Conf.Debug
|
||||
}
|
||||
|
||||
// Check ..
|
||||
func (a *AuthHandler) Check(ctx context.Context) (clientID uint64, err error) {
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
|
@ -3,7 +3,6 @@ package rpc
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/naiba/nezha/model"
|
||||
@ -12,13 +11,60 @@ import (
|
||||
"github.com/naiba/nezha/service/dao"
|
||||
)
|
||||
|
||||
// NezhaHandler ..
|
||||
type NezhaHandler struct {
|
||||
Auth *AuthHandler
|
||||
}
|
||||
|
||||
// ReportState ..
|
||||
func (s *NezhaHandler) ReportState(c context.Context, r *pb.State) (*pb.Receipt, error) {
|
||||
func (s *NezhaHandler) ReportTask(c context.Context, r *pb.TaskResult) (*pb.Receipt, error) {
|
||||
var err error
|
||||
if _, err = s.Auth.Check(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.GetType() == model.MonitorTypeHTTPGET {
|
||||
// SSL 证书变更报警
|
||||
var last model.MonitorHistory
|
||||
if err := dao.DB.Where("monitor_id = ?", r.GetId()).Order("id DESC").First(&last).Error; err == nil {
|
||||
if last.Data != "" && last.Data != r.GetData() {
|
||||
var monitor model.Monitor
|
||||
dao.DB.First(&monitor, "id = ?", last.MonitorID)
|
||||
alertmanager.SendNotification(fmt.Sprintf(
|
||||
"监控:%s SSL证书变更,旧:%s,新:%s。",
|
||||
monitor.Name, last.Data, r.GetData()))
|
||||
}
|
||||
}
|
||||
}
|
||||
// 存入历史记录
|
||||
mh := model.PB2MonitorHistory(r)
|
||||
if err := dao.DB.Create(&mh).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 更新最后检测时间
|
||||
var m model.Monitor
|
||||
m.ID = r.GetId()
|
||||
if err := dao.DB.Model(&m).Update("last_check", time.Now()).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.Lock()
|
||||
dao.ServerList[clientID].TaskStream = stream
|
||||
dao.ServerList[clientID].TaskClose = closeCh
|
||||
dao.ServerLock.Unlock()
|
||||
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 {
|
||||
@ -32,28 +78,7 @@ func (s *NezhaHandler) ReportState(c context.Context, r *pb.State) (*pb.Receipt,
|
||||
return &pb.Receipt{Proced: true}, nil
|
||||
}
|
||||
|
||||
// Heartbeat ..
|
||||
func (s *NezhaHandler) Heartbeat(r *pb.Beat, stream pb.NezhaService_HeartbeatServer) error {
|
||||
var clientID uint64
|
||||
var err error
|
||||
defer log.Printf("Heartbeat exit server:%v err:%v", clientID, err)
|
||||
if clientID, err = s.Auth.Check(stream.Context()); err != nil {
|
||||
return err
|
||||
}
|
||||
// 放入在线服务器列表
|
||||
dao.ServerLock.RLock()
|
||||
closeCh := make(chan error)
|
||||
dao.ServerList[clientID].StreamClose = closeCh
|
||||
dao.ServerList[clientID].Stream = stream
|
||||
dao.ServerLock.RUnlock()
|
||||
select {
|
||||
case err = <-closeCh:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Register ..
|
||||
func (s *NezhaHandler) Register(c context.Context, r *pb.Host) (*pb.Receipt, error) {
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user