2025-05-13 09:29:13 +08:00
|
|
|
|
package handlers
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-05-27 15:08:18 +08:00
|
|
|
|
"errors"
|
|
|
|
|
|
"gorm.io/gen/field"
|
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
"log/slog"
|
2025-05-26 10:57:39 +08:00
|
|
|
|
"platform/pkg/u"
|
2025-05-23 18:58:03 +08:00
|
|
|
|
"platform/web/auth"
|
2025-05-13 18:47:30 +08:00
|
|
|
|
edge2 "platform/web/domains/edge"
|
2025-05-13 09:29:13 +08:00
|
|
|
|
proxy2 "platform/web/domains/proxy"
|
|
|
|
|
|
g "platform/web/globals"
|
|
|
|
|
|
m "platform/web/models"
|
|
|
|
|
|
q "platform/web/queries"
|
2025-05-23 18:58:03 +08:00
|
|
|
|
s "platform/web/services"
|
2025-05-13 18:47:30 +08:00
|
|
|
|
|
|
|
|
|
|
"github.com/gofiber/fiber/v2"
|
2025-05-13 09:29:13 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
type RegisterEdgeReq struct {
|
2025-05-27 15:08:18 +08:00
|
|
|
|
Name string `json:"name" validate:"required"`
|
|
|
|
|
|
Version int `json:"version" validate:"required"`
|
2025-05-13 09:29:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type RegisterEdgeResp struct {
|
2025-05-14 17:45:14 +08:00
|
|
|
|
Id int32 `json:"id"`
|
2025-05-13 09:29:13 +08:00
|
|
|
|
Host string `json:"host"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-27 15:08:18 +08:00
|
|
|
|
func AssignEdge(c *fiber.Ctx) (err error) {
|
2025-05-13 09:29:13 +08:00
|
|
|
|
|
|
|
|
|
|
// 验证请求参数
|
|
|
|
|
|
var req = new(RegisterEdgeReq)
|
|
|
|
|
|
err = g.Validator.Validate(c, req)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-27 15:08:18 +08:00
|
|
|
|
// 全局锁,防止并发注册
|
|
|
|
|
|
var mutex = g.Redsync.NewMutex("edge:discovery")
|
|
|
|
|
|
if err := mutex.Lock(); err != nil {
|
|
|
|
|
|
return errors.New("服务繁忙,请稍后重试")
|
2025-05-13 09:29:13 +08:00
|
|
|
|
}
|
2025-05-27 15:08:18 +08:00
|
|
|
|
defer func() {
|
|
|
|
|
|
if ok, err := mutex.Unlock(); err != nil {
|
|
|
|
|
|
slog.Error("解锁失败", slog.Bool("ok", ok), slog.Any("err", err))
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
2025-05-13 09:29:13 +08:00
|
|
|
|
|
2025-05-27 15:08:18 +08:00
|
|
|
|
// 检查节点
|
|
|
|
|
|
var fwd *m.Proxy
|
|
|
|
|
|
var edge *m.Edge
|
|
|
|
|
|
edge, err = q.Edge.
|
|
|
|
|
|
Where(q.Edge.Name.Eq(req.Name)).
|
|
|
|
|
|
Take()
|
|
|
|
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
|
|
|
|
// 挑选合适的转发服务
|
|
|
|
|
|
fwd, err = q.Proxy.
|
|
|
|
|
|
LeftJoin(q.Edge, q.Edge.ProxyID.EqCol(q.Proxy.ID), q.Edge.Status.Eq(1)).
|
|
|
|
|
|
Select(q.Proxy.ALL, q.Edge.ALL.Count().As("count")).
|
|
|
|
|
|
Where(q.Proxy.Type.Eq(int32(proxy2.TypeSelfHosted))).
|
|
|
|
|
|
Group(q.Proxy.ID).
|
|
|
|
|
|
Order(field.NewField("", "count").Desc()).
|
|
|
|
|
|
First()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
// 保存节点信息
|
|
|
|
|
|
edge = &m.Edge{
|
|
|
|
|
|
Name: req.Name,
|
|
|
|
|
|
Version: int32(req.Version),
|
|
|
|
|
|
Type: int32(edge2.TypeSelfHosted),
|
|
|
|
|
|
ProxyID: &fwd.ID,
|
|
|
|
|
|
}
|
|
|
|
|
|
err = q.Edge.Create(edge)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if err == nil {
|
|
|
|
|
|
// 获取已配置的转发服务
|
|
|
|
|
|
fwd, err = q.Proxy.
|
|
|
|
|
|
Where(q.Proxy.ID.Eq(*edge.ProxyID)).
|
|
|
|
|
|
Take()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
// 节点已存在,更新版本号
|
|
|
|
|
|
if edge.Version < int32(req.Version) {
|
|
|
|
|
|
_, err = q.Edge.
|
|
|
|
|
|
Where(q.Edge.ID.Eq(edge.ID)).
|
|
|
|
|
|
UpdateSimple(q.Edge.Version.Value(int32(req.Version)))
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2025-05-13 09:29:13 +08:00
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 返回服务地址
|
|
|
|
|
|
return c.JSON(RegisterEdgeResp{
|
2025-05-14 17:45:14 +08:00
|
|
|
|
Id: edge.ID,
|
2025-05-13 09:29:13 +08:00
|
|
|
|
Host: fwd.Host,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-05-14 17:45:14 +08:00
|
|
|
|
|
2025-05-23 18:58:03 +08:00
|
|
|
|
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,
|
2025-05-26 10:57:39 +08:00
|
|
|
|
Port: u.Z(info.ProxyPort),
|
2025-05-27 15:08:18 +08:00
|
|
|
|
Isp: edge2.ISP(info.Isp).String(),
|
2025-05-23 18:58:03 +08:00
|
|
|
|
Prov: info.Prov,
|
|
|
|
|
|
City: info.City,
|
|
|
|
|
|
Status: info.Status,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return c.JSON(edges)
|
|
|
|
|
|
}
|