diff --git a/docs/api.yaml b/docs/api.yaml index f971b35..86703c8 100644 --- a/docs/api.yaml +++ b/docs/api.yaml @@ -47,6 +47,11 @@ components: - size - list + Edge: + type: object + properties: + + tags: - name: Auth description: 认证授权相关接口 @@ -410,4 +415,27 @@ paths: summary: 获取公告列表 description: 获取系统公告列表 + /api/edge/all: + post: + tags: + - Edge + summary: 获取所有边缘节点 + description: 获取所有可用的边缘节点列表 + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + prov: + type: string + description: 省份 + city: + type: string + description: 城市 + isp: + type: string + description: 运营商 + diff --git a/web/domains/edge/types.go b/web/domains/edge/types.go index de0d0a6..929fa70 100644 --- a/web/domains/edge/types.go +++ b/web/domains/edge/types.go @@ -23,6 +23,19 @@ func ISPFromStr(str string) ISP { return IspUnknown } +func ISPToStr(isp ISP) string { + switch isp { + case IspChinaTelecom: + return "电信" + case IspChinaUnicom: + return "联通" + case IspChinaMobile: + return "移动" + default: + return "未知" + } +} + type Type int32 const ( diff --git a/web/handlers/channel.go b/web/handlers/channel.go index c7f5b89..2407d62 100644 --- a/web/handlers/channel.go +++ b/web/handlers/channel.go @@ -159,7 +159,7 @@ func CreateChannel(c *fiber.Ctx) error { req.Protocol, req.AuthType, req.Count, - s.EdgeFilterConfig{ + s.EdgeFilter{ Isp: isp, Prov: req.Prov, City: req.City, diff --git a/web/handlers/edge.go b/web/handlers/edge.go index ee2aef7..eec336e 100644 --- a/web/handlers/edge.go +++ b/web/handlers/edge.go @@ -1,11 +1,13 @@ package handlers import ( + "platform/web/auth" edge2 "platform/web/domains/edge" proxy2 "platform/web/domains/proxy" g "platform/web/globals" m "platform/web/models" q "platform/web/queries" + s "platform/web/services" "github.com/gofiber/fiber/v2" "gorm.io/gen/field" @@ -96,3 +98,52 @@ func OfflineEdge(c *fiber.Ctx) (err error) { return c.SendStatus(fiber.StatusOK) } + +type AllEdgesAvailableReq struct { + s.EdgeFilter + Count int `json:"count"` +} + +type AllEdgesAvailableRespItem struct { + Ip string `json:"ip"` // 节点地址 + Port int32 `json:"port"` // 代理服务端口 + Isp string `json:"isp"` // 运营商 + Prov string `json:"prov"` // 省份 + City string `json:"city"` // 城市 + Status int32 `json:"status"` // 节点状态:0-离线,1-正常 +} + +func AllEdgesAvailable(c *fiber.Ctx) (err error) { + // 检查权限 + _, err = auth.NewProtect(c).Payload(auth.PayloadInternalServer).Do() + if err != nil { + return err + } + + // 验证请求参数 + var req = new(AllEdgesAvailableReq) + err = g.Validator.Validate(c, req) + if err != nil { + return err + } + + // 获取可用的转发服务 + infos, err := s.Edge.AllEdges(req.Count, req.EdgeFilter) + if err != nil { + return err + } + + // 返回结果 + var edges = make([]AllEdgesAvailableRespItem, len(infos)) + for i, info := range infos { + edges[i] = AllEdgesAvailableRespItem{ + Ip: info.Host, + Port: info.ProxyPort, + Isp: edge2.ISPToStr(edge2.ISP(info.Isp)), + Prov: info.Prov, + City: info.City, + Status: info.Status, + } + } + return c.JSON(edges) +} diff --git a/web/router.go b/web/router.go index e77be75..442c715 100644 --- a/web/router.go +++ b/web/router.go @@ -74,6 +74,7 @@ func ApplyRouters(app *fiber.App) { edge := api.Group("/edge") edge.Post("/online", handlers.OnlineEdge) edge.Post("/offline", handlers.OfflineEdge) + edge.Post("/all", handlers.AllEdgesAvailable) // 临时 app.Get("/test", func(c *fiber.Ctx) error { diff --git a/web/services/channel.go b/web/services/channel.go index d110dd0..caacbbe 100644 --- a/web/services/channel.go +++ b/web/services/channel.go @@ -218,10 +218,10 @@ func (s *channelService) CreateChannel( protocol channel2.Protocol, authType ChannelAuthType, count int, - edgeFilter ...EdgeFilterConfig, + edgeFilter ...EdgeFilter, ) (channels []*m.Channel, err error) { var now = time.Now() - var filter = EdgeFilterConfig{} + var filter = EdgeFilter{} if len(edgeFilter) > 0 { filter = edgeFilter[0] } @@ -245,7 +245,7 @@ func (s *channelService) CreateChannel( } // 分配节点 - var config = ChannelCreateConfig{ + var config = ChannelCreator{ Protocol: protocol, AuthIp: authType == ChannelAuthTypeIp, Whitelists: whitelist, @@ -397,7 +397,7 @@ func findWhitelist(q *q.Query, userId int32) ([]string, error) { return whitelist, nil } -func assignShortChannels(q *q.Query, userId int32, resourceId int32, count int, config ChannelCreateConfig, filter EdgeFilterConfig, now time.Time) ([]*m.Channel, error) { +func assignShortChannels(q *q.Query, userId int32, resourceId int32, count int, config ChannelCreator, filter EdgeFilter, now time.Time) ([]*m.Channel, error) { // 查找网关 proxies, err := q.Proxy. @@ -594,14 +594,14 @@ func assignShortChannels(q *q.Query, userId int32, resourceId int32, count int, return newChannels, nil } -func assignLongChannels(q *q.Query, userId int32, resourceId int32, count int, config ChannelCreateConfig, filter EdgeFilterConfig) ([]*m.Channel, error) { +func assignLongChannels(q *q.Query, userId int32, resourceId int32, count int, config ChannelCreator, filter EdgeFilter) ([]*m.Channel, error) { // 查询符合条件的节点,根据 channel 统计使用次数 var edges = make([]struct { m.Edge - Count int - Host string - Secret string + Count int + ProxyHost string + ProxySecret string }, 0) do := q.Edge.Where(q.Edge.Status.Eq(1)) @@ -621,8 +621,8 @@ func assignLongChannels(q *q.Query, userId int32, resourceId int32, count int, c Select( q.Edge.ALL, q.Channel.ALL.Count().As("count"), - q.Proxy.Host, - q.Proxy.Secret, + q.Proxy.Host.As("proxy_host"), + q.Proxy.Secret.As("proxy_secret"), ). Group(q.Edge.ID, q.Proxy.Host, q.Proxy.Secret). Where(do). @@ -630,7 +630,7 @@ func assignLongChannels(q *q.Query, userId int32, resourceId int32, count int, c Limit(count). Scan(&edges) if err != nil { - return nil, err + return nil, fmt.Errorf("查询符合条件的节点失败: %w", err) } if len(edges) == 0 { return nil, ErrEdgesNoAvailable @@ -650,8 +650,8 @@ func assignLongChannels(q *q.Query, userId int32, resourceId int32, count int, c if _, ok := proxies[edge.ProxyID]; !ok { proxies[edge.ProxyID] = &m.Proxy{ ID: edge.ProxyID, - Host: edge.Host, - Secret: edge.Secret, + Host: edge.ProxyHost, + Secret: edge.ProxySecret, } } @@ -674,7 +674,7 @@ func assignLongChannels(q *q.Query, userId int32, resourceId int32, count int, c AuthIP: config.AuthIp, AuthPass: config.AuthPass, Expiration: orm.LocalDateTime(config.Expiration), - ProxyHost: edge.Host, + ProxyHost: edge.ProxyHost, ProxyPort: edge.ProxyPort, } if config.AuthIp { @@ -819,7 +819,7 @@ const ( ChannelAuthTypePass ) -type ChannelCreateConfig struct { +type ChannelCreator struct { Protocol channel2.Protocol AuthIp bool Whitelists []string @@ -827,12 +827,6 @@ type ChannelCreateConfig struct { Expiration time.Time } -type EdgeFilterConfig struct { - Isp string `json:"isp"` - Prov string `json:"prov"` - City string `json:"city"` -} - type ResourceInfo struct { Id int32 Active bool diff --git a/web/services/edge.go b/web/services/edge.go new file mode 100644 index 0000000..819e0c5 --- /dev/null +++ b/web/services/edge.go @@ -0,0 +1,43 @@ +package services + +import ( + edge2 "platform/web/domains/edge" + m "platform/web/models" + q "platform/web/queries" +) + +var Edge = &edgeService{} + +type edgeService struct{} + +func (s *edgeService) AllEdges(count int, filter EdgeFilter) ([]*m.Edge, error) { + do := q.Edge.Where(q.Edge.Status.Eq(1)) + if filter.Prov != "" { + do = do.Where(q.Edge.Prov.Eq(filter.Prov)) + } + if filter.City != "" { + do = do.Where(q.Edge.City.Eq(filter.City)) + } + if filter.Isp != "" { + do = do.Where(q.Edge.Isp.Eq(int32(edge2.ISPFromStr(filter.Isp)))) + } + if count > 0 { + do = do.Limit(count) + } + + edges, err := q.Edge.Where(do).Find() + if err != nil { + return nil, err + } + + return edges, nil +} + +type EdgeInfo struct { +} + +type EdgeFilter struct { + Isp string `json:"isp"` + Prov string `json:"prov"` + City string `json:"city"` +}