package singleton import ( "sync" "time" "github.com/naiba/nezha/model" "github.com/naiba/nezha/pkg/utils" ) var ( ApiTokenList = make(map[string]*model.ApiToken) UserIDToApiTokenList = make(map[uint64][]string) ApiLock sync.RWMutex ServerAPI = &ServerAPIService{} MonitorAPI = &MonitorAPIService{} ) type ServerAPIService struct{} // 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"` LastActive int64 `json:"last_active"` IPV4 string `json:"ipv4"` IPV6 string `json:"ipv6"` ValidIP string `json:"valid_ip"` DisplayIndex int `json:"display_index"` } // 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"` } type MonitorAPIService struct { } type MonitorInfoResponse struct { CommonResponse Result []*MonitorInfo `json:"result"` } type MonitorInfo struct { MonitorID uint64 `json:"monitor_id"` ServerID uint64 `json:"server_id"` MonitorName string `json:"monitor_name"` ServerName string `json:"server_name"` CreatedAt []int64 `json:"created_at"` AvgDelay []float32 `json:"avg_delay"` } func InitAPI() { ApiTokenList = make(map[string]*model.ApiToken) UserIDToApiTokenList = make(map[uint64][]string) } func loadAPI() { InitAPI() var tokenList []*model.ApiToken DB.Find(&tokenList) for _, token := range tokenList { ApiTokenList[token.Token] = token UserIDToApiTokenList[token.UserID] = append(UserIDToApiTokenList[token.UserID], token.Token) } } // GetStatusByIDList 获取传入IDList的服务器状态信息 func (s *ServerAPIService) GetStatusByIDList(idList []uint64) *ServerStatusResponse { res := &ServerStatusResponse{} res.Result = make([]*StatusResponse, 0) ServerLock.RLock() defer ServerLock.RUnlock() for _, v := range idList { server := ServerList[v] if server == nil { continue } ipv4, ipv6, validIP := utils.SplitIPAddr(server.Host.IP) info := CommonServerInfo{ ID: server.ID, Name: server.Name, Tag: server.Tag, LastActive: server.LastActive.Unix(), IPV4: ipv4, IPV6: ipv6, ValidIP: validIP, } res.Result = append(res.Result, &StatusResponse{ CommonServerInfo: info, Host: server.Host, Status: server.State, }) } res.CommonResponse = CommonResponse{ Code: 0, Message: "success", } return res } // GetStatusByTag 获取传入分组的所有服务器状态信息 func (s *ServerAPIService) GetStatusByTag(tag string) *ServerStatusResponse { return s.GetStatusByIDList(ServerTagToIDList[tag]) } // GetAllStatus 获取所有服务器状态信息 func (s *ServerAPIService) GetAllStatus() *ServerStatusResponse { res := &ServerStatusResponse{} res.Result = make([]*StatusResponse, 0) ServerLock.RLock() defer ServerLock.RUnlock() for _, v := range ServerList { host := v.Host state := v.State if host == nil || state == nil { continue } ipv4, ipv6, validIP := utils.SplitIPAddr(host.IP) info := CommonServerInfo{ ID: v.ID, Name: v.Name, Tag: v.Tag, LastActive: v.LastActive.Unix(), IPV4: ipv4, IPV6: ipv6, ValidIP: validIP, DisplayIndex: v.DisplayIndex, } res.Result = append(res.Result, &StatusResponse{ CommonServerInfo: info, Host: v.Host, Status: v.State, }) } res.CommonResponse = CommonResponse{ Code: 0, Message: "success", } return res } // GetListByTag 获取传入分组的所有服务器信息 func (s *ServerAPIService) GetListByTag(tag string) *ServerInfoResponse { res := &ServerInfoResponse{} res.Result = make([]*CommonServerInfo, 0) ServerLock.RLock() defer ServerLock.RUnlock() for _, v := range ServerTagToIDList[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, LastActive: ServerList[v].LastActive.Unix(), IPV4: ipv4, IPV6: ipv6, ValidIP: validIP, } res.Result = append(res.Result, info) } res.CommonResponse = CommonResponse{ Code: 0, Message: "success", } return res } // GetAllList 获取所有服务器信息 func (s *ServerAPIService) 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, LastActive: v.LastActive.Unix(), IPV4: ipv4, IPV6: ipv6, ValidIP: validIP, } res.Result = append(res.Result, info) } res.CommonResponse = CommonResponse{ Code: 0, Message: "success", } return res } func (m *MonitorAPIService) GetMonitorHistories(query map[string]any) *MonitorInfoResponse { var ( resultMap = make(map[uint64]*MonitorInfo) monitorHistories []*model.MonitorHistory sortedMonitorIDs []uint64 ) res := &MonitorInfoResponse{ CommonResponse: CommonResponse{ Code: 0, Message: "success", }, } if err := DB.Model(&model.MonitorHistory{}).Select("monitor_id, created_at, server_id, avg_delay"). Where(query).Where("created_at >= ?", time.Now().Add(-24*time.Hour)).Order("monitor_id, created_at"). Scan(&monitorHistories).Error; err != nil { res.CommonResponse = CommonResponse{ Code: 500, Message: err.Error(), } } else { for _, history := range monitorHistories { infos, ok := resultMap[history.MonitorID] if !ok { infos = &MonitorInfo{ MonitorID: history.MonitorID, ServerID: history.ServerID, MonitorName: ServiceSentinelShared.monitors[history.MonitorID].Name, ServerName: ServerList[history.ServerID].Name, } resultMap[history.MonitorID] = infos sortedMonitorIDs = append(sortedMonitorIDs, history.MonitorID) } infos.CreatedAt = append(infos.CreatedAt, history.CreatedAt.Truncate(time.Minute).Unix()*1000) infos.AvgDelay = append(infos.AvgDelay, history.AvgDelay) } for _, monitorID := range sortedMonitorIDs { res.Result = append(res.Result, resultMap[monitorID]) } } return res }