优化白名单与通道提取功能
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
异常展示全部信息,只返回 bizerr 的内容,控制台打印全部 err 内容
|
|
||||||
|
|
||||||
|
错误提示增强,展示整链路信息
|
||||||
|
|
||||||
ip 提取频率限制,在 ensure 函数加逻辑,通过 redis 或者 pg 计算分钟内提取次数,只允许每分钟提取 30 次
|
ip 提取频率限制,在 ensure 函数加逻辑,通过 redis 或者 pg 计算分钟内提取次数,只允许每分钟提取 30 次
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"platform/pkg/env"
|
"platform/pkg/env"
|
||||||
"platform/pkg/u"
|
"platform/pkg/u"
|
||||||
"platform/web/auth"
|
"platform/web/auth"
|
||||||
@@ -97,13 +98,31 @@ func CreateWhitelist(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建白名单
|
// 创建白名单
|
||||||
err = q.Whitelist.Create(&m.Whitelist{
|
uid := authCtx.User.ID
|
||||||
UserID: authCtx.User.ID,
|
err = g.Redsync.WithLock(whitelistKey(uid), func() error {
|
||||||
IP: u.Z(ip),
|
count, err := q.Whitelist.Where(
|
||||||
Remark: &req.Remark,
|
q.Whitelist.UserID.Eq(uid),
|
||||||
|
).Count()
|
||||||
|
if err != nil {
|
||||||
|
return core.NewServErr("获取白名单数量失败", err)
|
||||||
|
}
|
||||||
|
if count >= 5 {
|
||||||
|
return core.NewBizErr("白名单数量已达上限")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = q.Whitelist.Create(&m.Whitelist{
|
||||||
|
UserID: authCtx.User.ID,
|
||||||
|
IP: u.Z(ip),
|
||||||
|
Remark: &req.Remark,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return core.NewServErr("添加白名单失败", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return core.NewServErr("添加白名单失败", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -206,3 +225,7 @@ func secureAddr(str string) (*orm.Inet, error) {
|
|||||||
}
|
}
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func whitelistKey(userID int32) string {
|
||||||
|
return fmt.Sprintf("platform:whitelist:add:%d", userID)
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
"gorm.io/gen"
|
|
||||||
"gorm.io/gen/field"
|
"gorm.io/gen/field"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -87,30 +86,20 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取可用节点
|
// 获取可用节点
|
||||||
edgesResp, err := g.Cloud.CloudEdges(&g.CloudEdgesReq{
|
secret := strings.Split(u.Z(proxy.Secret), ":")
|
||||||
Province: filter.Prov,
|
if len(secret) != 2 {
|
||||||
City: filter.City,
|
return nil, core.NewServErr(fmt.Sprintf("代理 %s 密钥格式错误", proxy.IP.String()), nil)
|
||||||
Isp: u.X(filter.Isp.String()),
|
}
|
||||||
Limit: &count,
|
gateway := g.NewGateway(proxy.IP.String(), secret[0], secret[1])
|
||||||
NoRepeat: u.P(true),
|
edges, err := getAvailableEdges(gateway, filter, count)
|
||||||
NoDayRepeat: u.P(true),
|
|
||||||
ActiveTime: u.P(3600),
|
|
||||||
IpUnchangedTime: u.P(3600),
|
|
||||||
Sort: u.P("ip_unchanged_time_asc"),
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("获取可用节点失败: %v\n", err)
|
return nil, err
|
||||||
return nil, core.NewBizErr("获取可用节点失败", err)
|
|
||||||
}
|
}
|
||||||
if edgesResp.Total != count && len(edgesResp.Edges) != count {
|
|
||||||
return nil, core.NewBizErr("地区可用节点数量不足")
|
|
||||||
}
|
|
||||||
edges := edgesResp.Edges
|
|
||||||
|
|
||||||
// 准备通道数据
|
// 准备通道数据
|
||||||
channels := make([]*m.Channel, count)
|
channels := make([]*m.Channel, count)
|
||||||
chanConfigs := make([]*g.PortConfigsReq, count)
|
chanConfigs := make([]*g.PortConfigsReq, count)
|
||||||
edgeConfigs := make([]string, count)
|
edgeConfigs := make([]string, 0, count)
|
||||||
for i := range count {
|
for i := range count {
|
||||||
ch := chans[i]
|
ch := chans[i]
|
||||||
edge := edges[i]
|
edge := edges[i]
|
||||||
@@ -152,7 +141,9 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 连接配置数据
|
// 连接配置数据
|
||||||
edgeConfigs[i] = edge.EdgeID
|
if edge.Type == EdgeInfoCloud {
|
||||||
|
edgeConfigs = append(edgeConfigs, edge.EdgeID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提交异步任务关闭通道
|
// 提交异步任务关闭通道
|
||||||
@@ -166,15 +157,13 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
|||||||
|
|
||||||
// 保存数据
|
// 保存数据
|
||||||
err = q.Q.Transaction(func(q *q.Query) error {
|
err = q.Q.Transaction(func(q *q.Query) error {
|
||||||
var rs gen.ResultInfo
|
|
||||||
|
|
||||||
// 根据套餐类型和模式更新使用记录
|
// 根据套餐类型和模式更新使用记录
|
||||||
isShortType := resource.Type == m.ResourceTypeShort
|
isShortType := resource.Type == m.ResourceTypeShort
|
||||||
isLongType := resource.Type == m.ResourceTypeLong
|
isLongType := resource.Type == m.ResourceTypeLong
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case isShortType:
|
case isShortType:
|
||||||
rs, err = q.ResourceShort.
|
_, err = q.ResourceShort.
|
||||||
Where(
|
Where(
|
||||||
q.ResourceShort.ID.Eq(*resource.ShortId),
|
q.ResourceShort.ID.Eq(*resource.ShortId),
|
||||||
q.ResourceShort.Used.Eq(resource.Used),
|
q.ResourceShort.Used.Eq(resource.Used),
|
||||||
@@ -187,7 +176,7 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
|||||||
)
|
)
|
||||||
|
|
||||||
case isLongType:
|
case isLongType:
|
||||||
rs, err = q.ResourceLong.
|
_, err = q.ResourceLong.
|
||||||
Where(
|
Where(
|
||||||
q.ResourceLong.ID.Eq(*resource.LongId),
|
q.ResourceLong.ID.Eq(*resource.LongId),
|
||||||
q.ResourceLong.Used.Eq(resource.Used),
|
q.ResourceLong.Used.Eq(resource.Used),
|
||||||
@@ -205,9 +194,6 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return core.NewServErr("更新套餐使用记录失败", err)
|
return core.NewServErr("更新套餐使用记录失败", err)
|
||||||
}
|
}
|
||||||
if rs.RowsAffected == 0 {
|
|
||||||
return core.NewServErr("套餐使用记录不存在")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存通道
|
// 保存通道
|
||||||
err = q.Channel.
|
err = q.Channel.
|
||||||
@@ -240,11 +226,6 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提交配置
|
// 提交配置
|
||||||
secret := strings.Split(u.Z(proxy.Secret), ":")
|
|
||||||
if len(secret) != 2 {
|
|
||||||
return nil, core.NewServErr(fmt.Sprintf("代理 %s 密钥格式错误", proxy.IP.String()), nil)
|
|
||||||
}
|
|
||||||
gateway := g.NewGateway(proxy.IP.String(), secret[0], secret[1])
|
|
||||||
if env.RunMode == env.RunModeProd {
|
if env.RunMode == env.RunModeProd {
|
||||||
|
|
||||||
// 连接节点到网关
|
// 连接节点到网关
|
||||||
@@ -259,6 +240,7 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
|||||||
// 启用网关代理通道
|
// 启用网关代理通道
|
||||||
err = gateway.GatewayPortConfigs(chanConfigs)
|
err = gateway.GatewayPortConfigs(chanConfigs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
slog.Warn("提交代理端口配置失败", "error", err.Error())
|
||||||
return nil, core.NewServErr(fmt.Sprintf("配置代理 %s 端口失败", proxy.IP.String()), err)
|
return nil, core.NewServErr(fmt.Sprintf("配置代理 %s 端口失败", proxy.IP.String()), err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -340,3 +322,70 @@ func (s *channelBaiyinProvider) RemoveChannels(batch string) error {
|
|||||||
slog.Debug("清除代理端口配置", "duration", time.Since(start).String())
|
slog.Debug("清除代理端口配置", "duration", time.Since(start).String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAvailableEdges(gateway g.GatewayClient, filter *EdgeFilter, count int) ([]EdgeInfo, error) {
|
||||||
|
edges := make([]EdgeInfo, 0, count)
|
||||||
|
|
||||||
|
// 先查本地
|
||||||
|
localEdgesResp, err := gateway.GatewayEdge(&g.GatewayEdgeReq{
|
||||||
|
Province: filter.Prov,
|
||||||
|
City: filter.City,
|
||||||
|
Isp: u.X(filter.Isp.String()),
|
||||||
|
Limit: &count,
|
||||||
|
Assigned: u.P(false),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, core.NewBizErr("获取可用节点失败", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, _ := range localEdgesResp {
|
||||||
|
edges = append(edges, EdgeInfo{
|
||||||
|
Type: EdgeInfoLocal,
|
||||||
|
EdgeID: id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(edges) >= count {
|
||||||
|
return edges, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再查云端无重复
|
||||||
|
remaining := count - len(edges)
|
||||||
|
cloudEdgesResp, err := g.Cloud.CloudEdges(&g.CloudEdgesReq{
|
||||||
|
Province: filter.Prov,
|
||||||
|
City: filter.City,
|
||||||
|
Isp: u.X(filter.Isp.String()),
|
||||||
|
Limit: &remaining,
|
||||||
|
NoRepeat: u.P(true),
|
||||||
|
ActiveTime: u.P(3600),
|
||||||
|
IpUnchangedTime: u.P(3600),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, core.NewBizErr("获取可用节点失败", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, edge := range cloudEdgesResp.Edges {
|
||||||
|
edges = append(edges, EdgeInfo{
|
||||||
|
Type: EdgeInfoCloud,
|
||||||
|
EdgeID: edge.EdgeID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(edges) >= count {
|
||||||
|
return edges, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不能和已有的重复,如果有重复则再次查询云端补足,二次提取还有重复则放弃
|
||||||
|
|
||||||
|
return nil, core.NewBizErr("地区可用节点数量不足")
|
||||||
|
}
|
||||||
|
|
||||||
|
type EdgeInfo struct {
|
||||||
|
Type EdgeInfoType
|
||||||
|
EdgeID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type EdgeInfoType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EdgeInfoLocal EdgeInfoType = "local"
|
||||||
|
EdgeInfoCloud EdgeInfoType = "cloud"
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user