| @@ -84,4 +84,6 @@ func (s *Server) InitRouters(rt gin.IRoutes, ah *auth.Auth) { | |||||
| rt.GET(cliapi.TickTockListJobsPath, certAuth, s.TickTock().ListJobs) | rt.GET(cliapi.TickTockListJobsPath, certAuth, s.TickTock().ListJobs) | ||||
| rt.POST(cliapi.TickTockRunJobPath, certAuth, s.TickTock().RunJob) | rt.POST(cliapi.TickTockRunJobPath, certAuth, s.TickTock().RunJob) | ||||
| rt.GET(cliapi.SystemStatusPath, certAuth, s.System().Status) | |||||
| } | } | ||||
| @@ -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(), | |||||
| })) | |||||
| } | |||||
| @@ -1,10 +1,11 @@ | |||||
| package speedstats | package speedstats | ||||
| import ( | import ( | ||||
| "fmt" | |||||
| "math/rand/v2" | "math/rand/v2" | ||||
| "sync" | "sync" | ||||
| "time" | "time" | ||||
| clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||||
| ) | ) | ||||
| const ( | const ( | ||||
| @@ -91,13 +92,6 @@ func (p *SpeedStats) Step() { | |||||
| p.statsAbove1G[1].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 { | func (p *SpeedStats) ShouldAtClient(size int64) bool { | ||||
| p.lock.RLock() | p.lock.RLock() | ||||
| defer p.lock.RUnlock() | defer p.lock.RUnlock() | ||||
| @@ -126,3 +120,50 @@ func (p *SpeedStats) ShouldAtClient(size int64) bool { | |||||
| v := rand.Float64() | v := rand.Float64() | ||||
| return v < prob | 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, | |||||
| }, | |||||
| }, | |||||
| } | |||||
| } | |||||
| @@ -23,5 +23,10 @@ func (j *SpeedStatsStep) Execute(t *TickTock) { | |||||
| }() | }() | ||||
| t.speedStats.Step() | 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, | |||||
| ) | |||||
| } | } | ||||
| @@ -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{}) | |||||
| } | |||||
| @@ -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"` | |||||
| } | |||||
| @@ -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 | |||||
| } | |||||