diff --git a/cmd/agent/main.go b/cmd/agent/main.go index 4ab9b35..5a38d70 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "io" "log" "os" "time" @@ -10,7 +11,9 @@ import ( "github.com/spf13/cobra" "google.golang.org/grpc" + "github.com/p14yground/nezha/model" pb "github.com/p14yground/nezha/proto" + "github.com/p14yground/nezha/service/dao" "github.com/p14yground/nezha/service/monitor" "github.com/p14yground/nezha/service/rpc" ) @@ -25,51 +28,89 @@ var ( 啦啦啦,啦啦啦,我是 mjj 小行家`, Run: run, } - appKey string - appSecret string + clientID string + clientSecret string + debug bool ) func main() { - rootCmd.PersistentFlags().StringVarP(&appKey, "id", "i", "", "客户端ID") - rootCmd.PersistentFlags().StringVarP(&appSecret, "secret", "p", "", "客户端Secret") + rootCmd.PersistentFlags().StringVarP(&clientID, "id", "i", "", "客户端ID") + rootCmd.PersistentFlags().StringVarP(&clientSecret, "secret", "p", "", "客户端Secret") + rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "开启Debug") if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } } +var endReport time.Time +var reporting bool +var client pb.NezhaServiceClient +var ctx = context.Background() + func run(cmd *cobra.Command, args []string) { + dao.Conf = &model.Config{ + Debug: debug, + } auth := rpc.AuthHandler{ - AppKey: appKey, - AppSecret: appSecret, + ClientID: clientID, + ClientSecret: clientSecret, } - conn, err := grpc.Dial(":5555", grpc.WithInsecure(), grpc.WithPerRPCCredentials(&auth)) - if err != nil { - panic(err) - } - defer conn.Close() - client := pb.NewNezhaServiceClient(conn) - ctx := context.Background() - - resp, err := client.Register(ctx, monitor.GetHost().PB()) - if err != nil { - log.Printf("client.Register err: %v", err) - } - log.Printf("Register resp: %s", resp) - - hc, err := client.Heartbeat(ctx, &pb.Beat{ - Timestamp: fmt.Sprintf("%v", time.Now()), - }) - if err != nil { - log.Printf("client.Register err: %v", err) - } - log.Printf("Register resp: %s", hc) - - for i := 0; i < 3; i++ { - resp, err := client.ReportState(ctx, monitor.GetState(3).PB()) + go reportState() + var err error + var conn *grpc.ClientConn + var hc pb.NezhaService_HeartbeatClient + for { + log.Println("Try to reconnect ...") + time.Sleep(time.Second * 5) + conn, err = grpc.Dial(":5555", grpc.WithInsecure(), grpc.WithPerRPCCredentials(&auth)) if err != nil { - log.Printf("client.ReportState err: %v", err) + log.Printf("grpc.Dial err: %v", err) + continue } - log.Printf("ReportState resp: %s", resp) + client = pb.NewNezhaServiceClient(conn) + // 第一步注册 + client.Register(ctx, monitor.GetHost().PB()) + hc, err = client.Heartbeat(ctx, &pb.Beat{ + Timestamp: fmt.Sprintf("%v", time.Now()), + }) + if err != nil { + log.Printf("client.Register err: %v", err) + continue + } + err = receiveCommand(hc) + log.Printf("receiveCommand exit to main: %v", err) + } +} + +func receiveCommand(hc pb.NezhaService_HeartbeatClient) error { + var err error + var action *pb.Command + defer log.Printf("receiveCommand exit %v %v => %v", time.Now(), action, err) + for { + action, err = hc.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + switch action.GetType() { + case model.MTReportState: + endReport = time.Now().Add(time.Second * 10) + default: + log.Printf("Unknown action: %v", action) + } + } +} + +func reportState() { + var err error + defer log.Printf("reportState exit %v %v => %v", endReport, time.Now(), err) + for { + if endReport.After(time.Now()) { + _, err = client.ReportState(ctx, monitor.GetState(0).PB()) + } + time.Sleep(time.Second) } } diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index c1ecd43..ecce8ed 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -7,6 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/naiba/com" + "github.com/patrickmn/go-cache" "github.com/p14yground/nezha/model" "github.com/p14yground/nezha/pkg/mygin" @@ -37,9 +38,9 @@ type serverForm struct { func (ma *memberAPI) addServer(c *gin.Context) { var sf serverForm + var s model.Server err := c.ShouldBindJSON(&sf) if err == nil { - var s model.Server s.Name = sf.Name s.Secret = com.MD5(fmt.Sprintf("%s%s%d", time.Now(), sf.Name, dao.Admin.ID)) s.Secret = s.Secret[:10] @@ -52,6 +53,7 @@ func (ma *memberAPI) addServer(c *gin.Context) { }) return } + dao.Cache.Set(fmt.Sprintf("%s%d%s", model.CtxKeyServer, s.ID, s.Secret), s, cache.NoExpiration) c.JSON(http.StatusOK, model.Response{ Code: http.StatusOK, }) diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go index 4b276de..6060d58 100644 --- a/cmd/dashboard/main.go +++ b/cmd/dashboard/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "time" "github.com/jinzhu/gorm" @@ -36,6 +37,12 @@ func init() { func initDB() { dao.DB.AutoMigrate(model.Server{}) + // load cache + var servers []model.Server + dao.DB.Find(&servers) + for _, s := range servers { + dao.Cache.Set(fmt.Sprintf("%s%d%s", model.CtxKeyServer, s.ID, s.Secret), s, cache.NoExpiration) + } } func main() { diff --git a/cmd/dashboard/rpc/rpc.go b/cmd/dashboard/rpc/rpc.go index 9e27c53..778b4ab 100644 --- a/cmd/dashboard/rpc/rpc.go +++ b/cmd/dashboard/rpc/rpc.go @@ -14,8 +14,8 @@ func ServeRPC() { server := grpc.NewServer() pb.RegisterNezhaServiceServer(server, &rpcService.NezhaHandler{ Auth: &rpcService.AuthHandler{ - AppKey: "naiba", - AppSecret: "123456", + ClientID: "naiba", + ClientSecret: "123456", }, }) listen, err := net.Listen("tcp", ":5555") diff --git a/model/common.go b/model/common.go index 4602bfb..c683d8f 100644 --- a/model/common.go +++ b/model/common.go @@ -7,6 +7,8 @@ const CtxKeyIsUserLogin = "ckiul" // CtxKeyOauth2State .. const CtxKeyOauth2State = "cko2s" +// CtxKeyServer .. +const CtxKeyServer = "cks" // Common .. type Common struct { diff --git a/model/monitor.go b/model/monitor.go index 32dfb53..d71a250 100644 --- a/model/monitor.go +++ b/model/monitor.go @@ -2,6 +2,12 @@ package model import pb "github.com/p14yground/nezha/proto" +const ( + _ = iota + // MTReportState .. + MTReportState +) + // State .. type State struct { CPU float64 @@ -39,6 +45,8 @@ type Host struct { Virtualization string Uptime string BootTime string + IP string + CountryCode string Version string } @@ -52,6 +60,8 @@ func (h *Host) PB() *pb.Host { Virtualization: h.Virtualization, Uptime: h.Uptime, BootTime: h.BootTime, + Ip: h.IP, + CountryCode: h.CountryCode, Version: h.Version, } } diff --git a/proto/nezha.proto b/proto/nezha.proto index 36892a2..9ccc509 100644 --- a/proto/nezha.proto +++ b/proto/nezha.proto @@ -16,7 +16,9 @@ message Host { string virtualization = 5; string uptime = 6; string boot_time = 7; - string version = 8; + string ip = 8; + string country_code = 9; + string version = 10; } message State { diff --git a/resource/static/main.css b/resource/static/main.css index 3b430ee..9332e56 100644 --- a/resource/static/main.css +++ b/resource/static/main.css @@ -4,8 +4,19 @@ } } +.nb-container { + padding-top: 75px; + min-height: 80%; +} + +.footer.segment { + margin-top: 40px !important; + padding-top: 40px; + padding-bottom: 40px; +} + .login-form { - height: 100%; + height: 82%; } .login-form .column { @@ -16,12 +27,29 @@ height: 100%; } -.nb-container { - margin-top: 75px; +.status.cards .header>.icon { + float: right; + margin-right: 0; } -.footer.segment { - margin-top: 40px !important; - padding-top: 40px; - padding-bottom: 40px; +.status.cards .wide.column { + padding-top: 0 !important; + padding-bottom: 0 !important; + height: 2rem !important; +} + +.status.cards .three.wide.column { + padding-right: 0 !important; +} + +.status.cards .wide.column:nth-child(1) { + margin-top: 1rem !important; +} + +.status.cards .wide.column:nth-child(2) { + margin-top: 1rem !important; +} + +.status.cards .description { + padding-bottom: 1rem !important; } \ No newline at end of file diff --git a/resource/static/main.js b/resource/static/main.js index b330e3b..599f36e 100644 --- a/resource/static/main.js +++ b/resource/static/main.js @@ -1,11 +1,12 @@ $('.ui.checkbox').checkbox(); +$('.yellow.info.circle.icon').popup(); const confirmBtn = $('.mini.confirm.modal .positive.button') function showConfirm(title, content, callFn, extData) { const modal = $('.mini.confirm.modal') modal.children('.header').text(title) modal.children('.content').text(content) - if (confirmBtn.hasClass('loading')) { + if (confirmBtn.hasCslass('loading')) { return false } modal.modal({ diff --git a/resource/template/page/home.html b/resource/template/page/home.html index f2d5d02..ee171f9 100644 --- a/resource/template/page/home.html +++ b/resource/template/page/home.html @@ -3,17 +3,40 @@ {{template "common/menu" .}}