From 8fc1d3057869e38f020e74d1b460152e435c32f5 Mon Sep 17 00:00:00 2001 From: luorijun Date: Thu, 7 May 2026 12:43:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=99=BD=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E4=B8=8E=E9=80=9A=E9=81=93=E6=8F=90=E5=8F=96=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- web/handlers/whitelist.go | 33 ++++++++-- web/services/channel_baiyin.go | 113 +++++++++++++++++++++++---------- 3 files changed, 112 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 9f01532..fb8e974 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ ## TODO -异常展示全部信息,只返回 bizerr 的内容,控制台打印全部 err 内容 + + +错误提示增强,展示整链路信息 ip 提取频率限制,在 ensure 函数加逻辑,通过 redis 或者 pg 计算分钟内提取次数,只允许每分钟提取 30 次 diff --git a/web/handlers/whitelist.go b/web/handlers/whitelist.go index 63c391a..0893d96 100644 --- a/web/handlers/whitelist.go +++ b/web/handlers/whitelist.go @@ -2,6 +2,7 @@ package handlers import ( "errors" + "fmt" "platform/pkg/env" "platform/pkg/u" "platform/web/auth" @@ -97,13 +98,31 @@ func CreateWhitelist(c *fiber.Ctx) error { } // 创建白名单 - err = q.Whitelist.Create(&m.Whitelist{ - UserID: authCtx.User.ID, - IP: u.Z(ip), - Remark: &req.Remark, + uid := authCtx.User.ID + err = g.Redsync.WithLock(whitelistKey(uid), func() error { + count, err := q.Whitelist.Where( + 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 { - return core.NewServErr("添加白名单失败", err) + return err } return nil @@ -206,3 +225,7 @@ func secureAddr(str string) (*orm.Inet, error) { } return ip, nil } + +func whitelistKey(userID int32) string { + return fmt.Sprintf("platform:whitelist:add:%d", userID) +} diff --git a/web/services/channel_baiyin.go b/web/services/channel_baiyin.go index 3bdec4c..b80789f 100644 --- a/web/services/channel_baiyin.go +++ b/web/services/channel_baiyin.go @@ -17,7 +17,6 @@ import ( "time" "github.com/hibiken/asynq" - "gorm.io/gen" "gorm.io/gen/field" ) @@ -87,30 +86,20 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int } // 获取可用节点 - edgesResp, err := g.Cloud.CloudEdges(&g.CloudEdgesReq{ - Province: filter.Prov, - City: filter.City, - Isp: u.X(filter.Isp.String()), - Limit: &count, - NoRepeat: u.P(true), - NoDayRepeat: u.P(true), - ActiveTime: u.P(3600), - IpUnchangedTime: u.P(3600), - Sort: u.P("ip_unchanged_time_asc"), - }) + 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]) + edges, err := getAvailableEdges(gateway, filter, count) if err != nil { - fmt.Printf("获取可用节点失败: %v\n", err) - return nil, core.NewBizErr("获取可用节点失败", err) + return nil, err } - if edgesResp.Total != count && len(edgesResp.Edges) != count { - return nil, core.NewBizErr("地区可用节点数量不足") - } - edges := edgesResp.Edges // 准备通道数据 channels := make([]*m.Channel, count) chanConfigs := make([]*g.PortConfigsReq, count) - edgeConfigs := make([]string, count) + edgeConfigs := make([]string, 0, count) for i := range count { ch := chans[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 { - var rs gen.ResultInfo - // 根据套餐类型和模式更新使用记录 isShortType := resource.Type == m.ResourceTypeShort isLongType := resource.Type == m.ResourceTypeLong switch { case isShortType: - rs, err = q.ResourceShort. + _, err = q.ResourceShort. Where( q.ResourceShort.ID.Eq(*resource.ShortId), q.ResourceShort.Used.Eq(resource.Used), @@ -187,7 +176,7 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int ) case isLongType: - rs, err = q.ResourceLong. + _, err = q.ResourceLong. Where( q.ResourceLong.ID.Eq(*resource.LongId), q.ResourceLong.Used.Eq(resource.Used), @@ -205,9 +194,6 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int if err != nil { return core.NewServErr("更新套餐使用记录失败", err) } - if rs.RowsAffected == 0 { - return core.NewServErr("套餐使用记录不存在") - } // 保存通道 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 { // 连接节点到网关 @@ -259,6 +240,7 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int // 启用网关代理通道 err = gateway.GatewayPortConfigs(chanConfigs) if err != nil { + slog.Warn("提交代理端口配置失败", "error", err.Error()) return nil, core.NewServErr(fmt.Sprintf("配置代理 %s 端口失败", proxy.IP.String()), err) } } else { @@ -340,3 +322,70 @@ func (s *channelBaiyinProvider) RemoveChannels(batch string) error { slog.Debug("清除代理端口配置", "duration", time.Since(start).String()) 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" +)