新增提取函数,实现通过套餐编号提取
This commit is contained in:
@@ -102,13 +102,17 @@ func CreateChannel(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// 创建通道
|
||||
no, err := s.FindResourceNoById(req.ResourceId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var isp *m.EdgeISP
|
||||
if req.Isp != nil {
|
||||
isp = u.X(m.ToEdgeISP(*req.Isp))
|
||||
}
|
||||
result, err := s.Channel.CreateChannels(
|
||||
ip,
|
||||
req.ResourceId,
|
||||
ip, no,
|
||||
req.AuthType == s.ChannelAuthTypeIp,
|
||||
req.AuthType == s.ChannelAuthTypePass,
|
||||
req.Count,
|
||||
@@ -149,6 +153,69 @@ type CreateChannelReq struct {
|
||||
Isp *int `json:"isp"`
|
||||
}
|
||||
|
||||
// CreateChannelV2 创建新通道 v2,使用 resource_no 替代 resource_id
|
||||
func CreateChannelV2(c *fiber.Ctx) error {
|
||||
// 不检查权限,允许 api 调用
|
||||
|
||||
// 解析参数
|
||||
req := new(CreateChannelReqV2)
|
||||
if err := g.Validator.ParseBody(c, req); err != nil {
|
||||
return core.NewBizErr("解析参数失败", err)
|
||||
}
|
||||
|
||||
ip, err := netip.ParseAddr(c.IP())
|
||||
if err != nil {
|
||||
return core.NewBizErr("获取客户端地址失败", err)
|
||||
}
|
||||
|
||||
// 创建通道
|
||||
var isp *m.EdgeISP
|
||||
if req.Isp != nil {
|
||||
isp = u.X(m.ToEdgeISP(*req.Isp))
|
||||
}
|
||||
result, err := s.Channel.CreateChannels(
|
||||
ip,
|
||||
req.ResourceNo,
|
||||
req.AuthType == s.ChannelAuthTypeIp,
|
||||
req.AuthType == s.ChannelAuthTypePass,
|
||||
req.Count,
|
||||
&s.EdgeFilter{
|
||||
Isp: isp,
|
||||
Prov: req.Prov,
|
||||
City: req.City,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 返回结果
|
||||
var resp = make([]*CreateChannelRespItem, len(result))
|
||||
for i, channel := range result {
|
||||
resp[i] = &CreateChannelRespItem{
|
||||
Proto: req.Protocol,
|
||||
Host: channel.Host,
|
||||
IP: channel.Proxy.IP.String(),
|
||||
Port: channel.Port,
|
||||
}
|
||||
if req.AuthType == s.ChannelAuthTypePass {
|
||||
resp[i].Username = channel.Username
|
||||
resp[i].Password = channel.Password
|
||||
}
|
||||
}
|
||||
return c.JSON(resp)
|
||||
}
|
||||
|
||||
type CreateChannelReqV2 struct {
|
||||
ResourceNo string `json:"resource_no" validate:"required"`
|
||||
AuthType s.ChannelAuthType `json:"auth_type" validate:"required"`
|
||||
Protocol int `json:"protocol" validate:"required"`
|
||||
Count int `json:"count" validate:"required"`
|
||||
Prov *string `json:"prov"`
|
||||
City *string `json:"city"`
|
||||
Isp *int `json:"isp"`
|
||||
}
|
||||
|
||||
type CreateChannelRespItem struct {
|
||||
Proto int `json:"-"`
|
||||
Host string `json:"host"`
|
||||
|
||||
@@ -95,6 +95,7 @@ func userRouter(api fiber.Router) {
|
||||
channel := api.Group("/channel")
|
||||
channel.Post("/list", handlers.ListChannel)
|
||||
channel.Post("/create", handlers.CreateChannel)
|
||||
channel.Post("/create/v2", handlers.CreateChannelV2)
|
||||
|
||||
// 交易
|
||||
trade := api.Group("/trade")
|
||||
|
||||
@@ -25,7 +25,7 @@ var Channel = &channelServer{
|
||||
}
|
||||
|
||||
type ChannelServiceProvider interface {
|
||||
CreateChannels(source netip.Addr, resourceId int32, authWhitelist bool, authPassword bool, count int, edgeFilter *EdgeFilter) ([]*m.Channel, error)
|
||||
CreateChannels(source netip.Addr, resourceNo string, authWhitelist bool, authPassword bool, count int, edgeFilter *EdgeFilter) ([]*m.Channel, error)
|
||||
RemoveChannels(batch string) error
|
||||
ClearExpiredChannels(proxyId int32) (int, error)
|
||||
}
|
||||
@@ -34,8 +34,8 @@ type channelServer struct {
|
||||
provider ChannelServiceProvider
|
||||
}
|
||||
|
||||
func (s *channelServer) CreateChannels(source netip.Addr, resourceId int32, authWhitelist bool, authPassword bool, count int, edgeFilter *EdgeFilter) ([]*m.Channel, error) {
|
||||
return s.provider.CreateChannels(source, resourceId, authWhitelist, authPassword, count, edgeFilter)
|
||||
func (s *channelServer) CreateChannels(source netip.Addr, resourceNo string, authWhitelist bool, authPassword bool, count int, edgeFilter *EdgeFilter) ([]*m.Channel, error) {
|
||||
return s.provider.CreateChannels(source, resourceNo, authWhitelist, authPassword, count, edgeFilter)
|
||||
}
|
||||
|
||||
func (s *channelServer) RemoveChannels(batch string) error {
|
||||
@@ -115,12 +115,23 @@ func genPassPair() (string, string) {
|
||||
return string(username), string(password)
|
||||
}
|
||||
|
||||
func FindResourceNoById(resourceId int32) (string, error) {
|
||||
resource, err := q.Resource.
|
||||
Select(q.Resource.ResourceNo).
|
||||
Where(q.Resource.ID.Eq(resourceId)).
|
||||
Take()
|
||||
if err != nil {
|
||||
return "", ErrResourceNotExist
|
||||
}
|
||||
return u.Z(resource.ResourceNo), nil
|
||||
}
|
||||
|
||||
// 查找资源
|
||||
func findResource(resourceId int32, now time.Time) (*ResourceView, error) {
|
||||
func findResourceViewByNo(resourceNo string, now time.Time) (*ResourceView, error) {
|
||||
resource, err := q.Resource.
|
||||
Preload(field.Associations).
|
||||
Where(
|
||||
q.Resource.ID.Eq(resourceId),
|
||||
q.Resource.ResourceNo.Eq(resourceNo),
|
||||
q.Resource.Active.Is(true),
|
||||
).
|
||||
Take()
|
||||
@@ -131,7 +142,7 @@ func findResource(resourceId int32, now time.Time) (*ResourceView, error) {
|
||||
return nil, ErrResourceNotExist
|
||||
}
|
||||
var info = &ResourceView{
|
||||
Id: resource.ID,
|
||||
ID: resource.ID,
|
||||
User: *resource.User,
|
||||
Active: resource.Active,
|
||||
Type: resource.Type,
|
||||
@@ -177,7 +188,7 @@ func findResource(resourceId int32, now time.Time) (*ResourceView, error) {
|
||||
|
||||
// ResourceView 套餐数据的简化视图,便于直接获取主要数据
|
||||
type ResourceView struct {
|
||||
Id int32
|
||||
ID int32
|
||||
User m.User
|
||||
Active bool
|
||||
Type m.ResourceType
|
||||
@@ -195,13 +206,13 @@ type ResourceView struct {
|
||||
}
|
||||
|
||||
// 检查用户是否可提取
|
||||
func ensure(now time.Time, source netip.Addr, resourceId int32, authWhitelist bool, count int) (*ResourceView, []string, error) {
|
||||
func ensure(now time.Time, source netip.Addr, resourceNo string, authWhitelist bool, count int) (*ResourceView, []string, error) {
|
||||
if count > 400 {
|
||||
return nil, nil, core.NewBizErr("单次最多提取 400 个")
|
||||
}
|
||||
|
||||
// 获取用户套餐
|
||||
resource, err := findResource(resourceId, now)
|
||||
resource, err := findResourceViewByNo(resourceNo, now)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
type channelBaiyinProvider struct{}
|
||||
|
||||
func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int32, authWhitelist bool, authPassword bool, count int, filter *EdgeFilter) ([]*m.Channel, error) {
|
||||
func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceNo string, authWhitelist bool, authPassword bool, count int, filter *EdgeFilter) ([]*m.Channel, error) {
|
||||
if filter == nil {
|
||||
return nil, core.NewBizErr("缺少节点过滤条件")
|
||||
}
|
||||
@@ -34,9 +34,9 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
||||
channels := make([]*m.Channel, count)
|
||||
|
||||
// 资源锁,防止并发扣减失败导致的端口悬空问题
|
||||
err := g.Redsync.WithLock(lockChannelCreateKey(resourceId), func() error {
|
||||
err := g.Redsync.WithLock(lockChannelCreateKey(resourceNo), func() error {
|
||||
// 检查并获取套餐与白名单
|
||||
resource, whitelists, err := ensure(now, source, resourceId, authWhitelist, count)
|
||||
resource, whitelists, err := ensure(now, source, resourceNo, authWhitelist, count)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
||||
// 通道数据
|
||||
channels[i] = &m.Channel{
|
||||
UserID: user.ID,
|
||||
ResourceID: resourceId,
|
||||
ResourceID: resource.ID,
|
||||
BatchNo: batchNo,
|
||||
ProxyID: proxy.ID,
|
||||
Host: u.Else(proxy.Host, proxy.IP.String()),
|
||||
@@ -181,7 +181,7 @@ func (s *channelBaiyinProvider) CreateChannels(source netip.Addr, resourceId int
|
||||
// 保存提取记录
|
||||
err = q.LogsUserUsage.Create(&m.LogsUserUsage{
|
||||
UserID: user.ID,
|
||||
ResourceID: resourceId,
|
||||
ResourceID: resource.ID,
|
||||
BatchNo: batchNo,
|
||||
Count: int32(count),
|
||||
ISP: u.X(filter.Isp.String()),
|
||||
@@ -335,8 +335,8 @@ func (s *channelBaiyinProvider) ClearExpiredChannels(proxyId int32) (int, error)
|
||||
return len(batchSet), nil
|
||||
}
|
||||
|
||||
func lockChannelCreateKey(resourceId int32) string {
|
||||
return fmt.Sprintf("platform:channel:create:%d", resourceId)
|
||||
func lockChannelCreateKey(resourceNo string) string {
|
||||
return fmt.Sprintf("platform:channel:create:%s", resourceNo)
|
||||
}
|
||||
|
||||
func lockChannelRemoveKey(bid string) string {
|
||||
|
||||
Reference in New Issue
Block a user