diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index 904ef33..334160f 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -49,12 +49,24 @@ func (ma *memberAPI) serve() { mr.GET("/server/details", ma.serverDetails) } -// serverList 获取服务器列表 +// serverList 获取服务器列表 不传入Query参数则获取全部 +// header: Authorization: Token +// query: tag (服务器分组) func (ma *memberAPI) serverList(c *gin.Context) { - + token, _ := c.Cookie("Authorization") + tag := c.Query("tag") + serverAPI := &singleton.ServerAPI{ + Token: token, + Tag: tag, + } + if tag != "" { + c.JSON(200, serverAPI.GetListByTag()) + return + } + c.JSON(200, serverAPI.GetAllList()) } -// serverDetails 获取服务器信息 +// serverDetails 获取服务器信息 不传入Query参数则获取全部 // header: Authorization: Token // query: idList (服务器ID,逗号分隔,优先级高于tag查询) // query: tag (服务器分组) diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 5989423..64adc44 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -6,6 +6,7 @@ import ( "math/rand" "os" "regexp" + "strings" "time" "unsafe" @@ -68,3 +69,27 @@ func IPDesensitize(ipAddr string) string { ipAddr = ipv6Desensitize(ipAddr) return ipAddr } + +// SplitIPAddr 传入/分割的v4v6混合地址,返回v4和v6地址与有效地址 +func SplitIPAddr(v4v6Bundle string) (string, string, string) { + ipList := strings.Split(v4v6Bundle, "/") + ipv4 := "" + ipv6 := "" + validIP := "" + if len(ipList) > 1 { + // 双栈 + ipv4 = ipList[0] + ipv6 = ipList[1] + validIP = ipv4 + } else if len(ipList) == 1 { + // 仅ipv4|ipv6 + if strings.Contains(ipList[0], ":") { + ipv6 = ipList[0] + validIP = ipv6 + } else { + ipv4 = ipList[0] + validIP = ipv4 + } + } + return ipv4, ipv6, validIP +} diff --git a/service/singleton/api.go b/service/singleton/api.go index b7fa1a6..6d02c94 100644 --- a/service/singleton/api.go +++ b/service/singleton/api.go @@ -1,6 +1,9 @@ package singleton -import "github.com/naiba/nezha/model" +import ( + "github.com/naiba/nezha/model" + "github.com/naiba/nezha/pkg/utils" +) type ServerAPI struct { Token string // 传入Token 后期可能会需要用于scope判定 @@ -8,24 +11,44 @@ type ServerAPI struct { Tag string } +// CommonResponse 常规返回结构 包含状态码 和 状态信息 type CommonResponse struct { Code int `json:"code"` Message string `json:"message"` } +type CommonServerInfo struct { + ID uint64 `json:"id"` + Name string `json:"name"` + Tag string `json:"tag"` + IPV4 string `json:"ipv4"` + IPV6 string `json:"ipv6"` + ValidIP string `json:"valid_ip"` +} + +// StatusResponse 服务器状态子结构 包含服务器信息与状态信息 type StatusResponse struct { + CommonServerInfo Host *model.Host `json:"host"` Status *model.HostState `json:"status"` } +// ServerStatusResponse 服务器状态返回结构 包含常规返回结构 和 服务器状态子结构 type ServerStatusResponse struct { CommonResponse Result []*StatusResponse `json:"result"` } +// ServerInfoResponse 服务器信息返回结构 包含常规返回结构 和 服务器信息子结构 +type ServerInfoResponse struct { + CommonResponse + Result []*CommonServerInfo `json:"result"` +} + // GetStatusByIDList 获取传入IDList的服务器状态信息 func (s *ServerAPI) GetStatusByIDList() *ServerStatusResponse { - var res []*StatusResponse + res := &ServerStatusResponse{} + res.Result = make([]*StatusResponse, 0) ServerLock.RLock() defer ServerLock.RUnlock() @@ -35,19 +58,26 @@ func (s *ServerAPI) GetStatusByIDList() *ServerStatusResponse { if server == nil { continue } - res = append(res, &StatusResponse{ - Host: server.Host, - Status: server.State, + ipv4, ipv6, validIP := utils.SplitIPAddr(server.Host.IP) + info := CommonServerInfo{ + ID: server.ID, + Name: server.Name, + Tag: server.Tag, + IPV4: ipv4, + IPV6: ipv6, + ValidIP: validIP, + } + res.Result = append(res.Result, &StatusResponse{ + CommonServerInfo: info, + Host: server.Host, + Status: server.State, }) } - - return &ServerStatusResponse{ - CommonResponse: CommonResponse{ - Code: 0, - Message: "success", - }, - Result: res, + res.CommonResponse = CommonResponse{ + Code: 0, + Message: "success", } + return res } // GetStatusByTag 获取传入分组的所有服务器状态信息 @@ -58,26 +88,94 @@ func (s *ServerAPI) GetStatusByTag() *ServerStatusResponse { // GetAllStatus 获取所有服务器状态信息 func (s *ServerAPI) GetAllStatus() *ServerStatusResponse { + res := &ServerStatusResponse{} + res.Result = make([]*StatusResponse, 0) ServerLock.RLock() defer ServerLock.RUnlock() - var res []*StatusResponse for _, v := range ServerList { host := v.Host state := v.State if host == nil || state == nil { continue } - res = append(res, &StatusResponse{ - Host: v.Host, - Status: v.State, + ipv4, ipv6, validIP := utils.SplitIPAddr(host.IP) + info := CommonServerInfo{ + ID: v.ID, + Name: v.Name, + Tag: v.Tag, + IPV4: ipv4, + IPV6: ipv6, + ValidIP: validIP, + } + res.Result = append(res.Result, &StatusResponse{ + CommonServerInfo: info, + Host: v.Host, + Status: v.State, }) } - - return &ServerStatusResponse{ - CommonResponse: CommonResponse{ - Code: 0, - Message: "success", - }, - Result: res, + res.CommonResponse = CommonResponse{ + Code: 0, + Message: "success", } + return res +} + +// GetListByTag 获取传入分组的所有服务器信息 +func (s *ServerAPI) GetListByTag() *ServerInfoResponse { + res := &ServerInfoResponse{} + res.Result = make([]*CommonServerInfo, 0) + + ServerLock.RLock() + defer ServerLock.RUnlock() + for _, v := range ServerTagToIDList[s.Tag] { + host := ServerList[v].Host + if host == nil { + continue + } + ipv4, ipv6, validIP := utils.SplitIPAddr(host.IP) + info := &CommonServerInfo{ + ID: v, + Name: ServerList[v].Name, + Tag: ServerList[v].Tag, + IPV4: ipv4, + IPV6: ipv6, + ValidIP: validIP, + } + res.Result = append(res.Result, info) + } + res.CommonResponse = CommonResponse{ + Code: 0, + Message: "success", + } + return res +} + +// GetAllList 获取所有服务器信息 +func (s *ServerAPI) GetAllList() *ServerInfoResponse { + res := &ServerInfoResponse{} + res.Result = make([]*CommonServerInfo, 0) + + ServerLock.RLock() + defer ServerLock.RUnlock() + for _, v := range ServerList { + host := v.Host + if host == nil { + continue + } + ipv4, ipv6, validIP := utils.SplitIPAddr(host.IP) + info := &CommonServerInfo{ + ID: v.ID, + Name: v.Name, + Tag: v.Tag, + IPV4: ipv4, + IPV6: ipv6, + ValidIP: validIP, + } + res.Result = append(res.Result, info) + } + res.CommonResponse = CommonResponse{ + Code: 0, + Message: "success", + } + return res }