From e062872c5386ba83f84d125dad120f10f2e7c948 Mon Sep 17 00:00:00 2001 From: Sydonian <794346190@qq.com> Date: Mon, 14 Jul 2025 10:24:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BE=93=E5=87=BA=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E7=8A=B6=E6=80=81=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/internal/http/v1/server.go | 2 + client/internal/http/v1/system.go | 32 +++++++++++ client/internal/speedstats/speedstats.go | 57 +++++++++++++++++--- client/internal/ticktock/speed_stats_step.go | 7 ++- client/sdk/api/v1/system.go | 37 +++++++++++++ client/types/status.go | 16 ++++++ jcsctl/cmd/admin/status.go | 46 ++++++++++++++++ 7 files changed, 188 insertions(+), 9 deletions(-) create mode 100644 client/internal/http/v1/system.go create mode 100644 client/sdk/api/v1/system.go create mode 100644 client/types/status.go create mode 100644 jcsctl/cmd/admin/status.go diff --git a/client/internal/http/v1/server.go b/client/internal/http/v1/server.go index f8736d5..7b9b8db 100644 --- a/client/internal/http/v1/server.go +++ b/client/internal/http/v1/server.go @@ -84,4 +84,6 @@ func (s *Server) InitRouters(rt gin.IRoutes, ah *auth.Auth) { rt.GET(cliapi.TickTockListJobsPath, certAuth, s.TickTock().ListJobs) rt.POST(cliapi.TickTockRunJobPath, certAuth, s.TickTock().RunJob) + + rt.GET(cliapi.SystemStatusPath, certAuth, s.System().Status) } diff --git a/client/internal/http/v1/system.go b/client/internal/http/v1/system.go new file mode 100644 index 0000000..bfc71f2 --- /dev/null +++ b/client/internal/http/v1/system.go @@ -0,0 +1,32 @@ +package http + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" + cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" + "gitlink.org.cn/cloudream/jcs-pub/common/ecode" +) + +type SystemService struct { + *Server +} + +func (s *Server) System() *SystemService { + return &SystemService{ + Server: s, + } +} + +func (s *SystemService) Status(ctx *gin.Context) { + var req cliapi.SystemStatus + if err := ctx.ShouldBindQuery(&req); err != nil { + ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "%v", err)) + return + } + + ctx.JSON(http.StatusOK, types.OK(cliapi.SystemStatusResp{ + SpeedStats: s.svc.SpeedStats.DumpStatus(), + })) +} diff --git a/client/internal/speedstats/speedstats.go b/client/internal/speedstats/speedstats.go index cf44df8..6fdec3b 100644 --- a/client/internal/speedstats/speedstats.go +++ b/client/internal/speedstats/speedstats.go @@ -1,10 +1,11 @@ package speedstats import ( - "fmt" "math/rand/v2" "sync" "time" + + clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" ) const ( @@ -91,13 +92,6 @@ func (p *SpeedStats) Step() { p.statsAbove1G[1].Step() } -func (p *SpeedStats) Dump() string { - p.lock.RLock() - defer p.lock.RUnlock() - - return fmt.Sprintf("100M: %v, %v\n1G: %v, %v\nAbove1G: %v, %v\n", p.stats100M[0].AvarageSpeed, p.stats100M[1].AvarageSpeed, p.stats1G[0].AvarageSpeed, p.stats1G[1].AvarageSpeed, p.statsAbove1G[0].AvarageSpeed, p.statsAbove1G[1].AvarageSpeed) -} - func (p *SpeedStats) ShouldAtClient(size int64) bool { p.lock.RLock() defer p.lock.RUnlock() @@ -126,3 +120,50 @@ func (p *SpeedStats) ShouldAtClient(size int64) bool { v := rand.Float64() return v < prob } + +func (p *SpeedStats) DumpStatus() clitypes.SpeedStatsStatus { + return clitypes.SpeedStatsStatus{ + Below100M: []clitypes.SpeedStatsStatusEntry{ + { + TotalSize: p.stats100M[0].TotalSize, + TotalTime: p.stats100M[0].TotalTime, + AvarageSpeed: p.stats100M[0].AvarageSpeed, + LastSpeed: p.stats100M[0].LastSpeed, + }, + { + TotalSize: p.stats100M[1].TotalSize, + TotalTime: p.stats100M[1].TotalTime, + AvarageSpeed: p.stats100M[1].AvarageSpeed, + LastSpeed: p.stats100M[1].LastSpeed, + }, + }, + Below1G: []clitypes.SpeedStatsStatusEntry{ + { + TotalSize: p.stats1G[0].TotalSize, + TotalTime: p.stats1G[0].TotalTime, + AvarageSpeed: p.stats1G[0].AvarageSpeed, + LastSpeed: p.stats1G[0].LastSpeed, + }, + { + TotalSize: p.stats1G[1].TotalSize, + TotalTime: p.stats1G[1].TotalTime, + AvarageSpeed: p.stats1G[1].AvarageSpeed, + LastSpeed: p.stats1G[1].LastSpeed, + }, + }, + Above1G: []clitypes.SpeedStatsStatusEntry{ + { + TotalSize: p.statsAbove1G[0].TotalSize, + TotalTime: p.statsAbove1G[0].TotalTime, + AvarageSpeed: p.statsAbove1G[0].AvarageSpeed, + LastSpeed: p.statsAbove1G[0].LastSpeed, + }, + { + TotalSize: p.statsAbove1G[1].TotalSize, + TotalTime: p.statsAbove1G[1].TotalTime, + AvarageSpeed: p.statsAbove1G[1].AvarageSpeed, + LastSpeed: p.statsAbove1G[1].LastSpeed, + }, + }, + } +} diff --git a/client/internal/ticktock/speed_stats_step.go b/client/internal/ticktock/speed_stats_step.go index 91f8fd2..0675e14 100644 --- a/client/internal/ticktock/speed_stats_step.go +++ b/client/internal/ticktock/speed_stats_step.go @@ -23,5 +23,10 @@ func (j *SpeedStatsStep) Execute(t *TickTock) { }() t.speedStats.Step() - log.Info(t.speedStats.Dump()) + status := t.speedStats.DumpStatus() + log.Infof("100M: %f, %f; 1G: %f, %f; Above1G: %f, %f\n", + status.Below100M[0].AvarageSpeed, status.Below100M[1].AvarageSpeed, + status.Below1G[0].AvarageSpeed, status.Below1G[1].AvarageSpeed, + status.Above1G[0].AvarageSpeed, status.Above1G[1].AvarageSpeed, + ) } diff --git a/client/sdk/api/v1/system.go b/client/sdk/api/v1/system.go new file mode 100644 index 0000000..e13333e --- /dev/null +++ b/client/sdk/api/v1/system.go @@ -0,0 +1,37 @@ +package api + +import ( + "net/http" + + "gitlink.org.cn/cloudream/common/sdks" + clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" +) + +type SystemService struct { + *Client +} + +func (c *Client) System() *SystemService { + return &SystemService{c} +} + +const SystemStatusPath = "/system/status" + +type SystemStatus struct { +} + +func (r *SystemStatus) MakeParam() *sdks.RequestParam { + return sdks.MakeQueryParam(http.MethodGet, SystemStatusPath, r) +} + +type SystemStatusResp struct { + SpeedStats clitypes.SpeedStatsStatus `json:"speedStats"` +} + +func (r *SystemStatusResp) ParseResponse(resp *http.Response) error { + return sdks.ParseCodeDataJSONResponse(resp, r) +} + +func (c *SystemService) Status(req SystemStatus) (*SystemStatusResp, error) { + return JSONAPI(&c.cfg, c.httpCli, &req, &SystemStatusResp{}) +} diff --git a/client/types/status.go b/client/types/status.go new file mode 100644 index 0000000..5b9e2a8 --- /dev/null +++ b/client/types/status.go @@ -0,0 +1,16 @@ +package types + +import "time" + +type SpeedStatsStatus struct { + Below100M []SpeedStatsStatusEntry `json:"below100M"` + Below1G []SpeedStatsStatusEntry `json:"below1G"` + Above1G []SpeedStatsStatusEntry `json:"above1G"` +} + +type SpeedStatsStatusEntry struct { + TotalSize int64 `json:"totalSize"` + TotalTime time.Duration `json:"totalTime"` + AvarageSpeed float64 `json:"avarageSpeed"` + LastSpeed float64 `json:"lastSpeed"` +} diff --git a/jcsctl/cmd/admin/status.go b/jcsctl/cmd/admin/status.go new file mode 100644 index 0000000..fdc054e --- /dev/null +++ b/jcsctl/cmd/admin/status.go @@ -0,0 +1,46 @@ +package admin + +import ( + "bytes" + "encoding/json" + "fmt" + + "github.com/spf13/cobra" + cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" + "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd" +) + +func init() { + var opt statusOpt + cmd := cobra.Command{ + Use: "status", + Args: cobra.ExactArgs(0), + RunE: func(c *cobra.Command, args []string) error { + ctx := cmd.GetCmdCtx(c) + return status(c, ctx, opt, args) + }, + } + AdminCmd.AddCommand(&cmd) +} + +type statusOpt struct { +} + +func status(c *cobra.Command, ctx *cmd.CommandContext, opt statusOpt, args []string) error { + resp, err := ctx.Client.System().Status(cliapi.SystemStatus{}) + if err != nil { + return fmt.Errorf("get system status: %v", err) + } + + bw := bytes.NewBuffer(nil) + enc := json.NewEncoder(bw) + enc.SetIndent("", " ") + + err = enc.Encode(resp) + if err != nil { + return fmt.Errorf("encode system status: %v", err) + } + + fmt.Println(bw.String()) + return nil +}