161 lines
4.4 KiB
Go
161 lines
4.4 KiB
Go
package services
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"platform/pkg/u"
|
|
"platform/web/core"
|
|
g "platform/web/globals"
|
|
m "platform/web/models"
|
|
q "platform/web/queries"
|
|
)
|
|
|
|
type channelBaiyinProvider struct{}
|
|
|
|
func (s *channelBaiyinProvider) selectProxy(count int) (*m.Proxy, error) {
|
|
return selectProxyByType(m.ProxyTypeBaiYin, count)
|
|
}
|
|
|
|
func (s *channelBaiyinProvider) prepareCreate(ctx *channelCreateContext) (*channelCreateResult, error) {
|
|
gateway, err := proxyGateway(ctx.Proxy)
|
|
if err != nil {
|
|
return nil, core.NewServErr("创建代理网关失败", err)
|
|
}
|
|
|
|
channels := make([]*m.Channel, len(ctx.Ports))
|
|
chanConfigs := make([]*g.PortConfigsReq, len(ctx.Ports))
|
|
for i, portRef := range ctx.Ports {
|
|
channel := newBaseChannel(ctx, portRef.Port())
|
|
cfg := &g.PortConfigsReq{
|
|
Port: int(portRef.Port()),
|
|
Status: true,
|
|
AutoEdgeConfig: &g.AutoEdgeConfig{
|
|
Province: u.Z(ctx.Filter.Prov),
|
|
City: u.Z(ctx.Filter.City),
|
|
Isp: ctx.Filter.Isp.String(),
|
|
Count: u.P(1),
|
|
},
|
|
}
|
|
|
|
if ctx.AuthWhitelist {
|
|
cfg.Whitelist = &ctx.Whitelists
|
|
}
|
|
if username, password, ok := applyChannelAuth(ctx, channel); ok {
|
|
cfg.Userpass = u.P(username + ":" + password)
|
|
}
|
|
|
|
channels[i] = channel
|
|
chanConfigs[i] = cfg
|
|
}
|
|
|
|
return &channelCreateResult{
|
|
Channels: channels,
|
|
applyRemote: func() error {
|
|
slog.Debug("提交代理端口配置", "proxy", ctx.Proxy.IP.String(), "total_count", len(chanConfigs))
|
|
if err := ensureEdges(ctx.Proxy, gateway, ctx.Filter, ctx.Count); err != nil {
|
|
slog.Warn("ensureEdges 失败", "err", err)
|
|
}
|
|
if len(chanConfigs) > 0 {
|
|
if err := gateway.GatewayPortConfigs(chanConfigs); err != nil {
|
|
slog.Warn("提交代理端口配置失败", "error", err.Error())
|
|
return core.NewServErr(fmt.Sprintf("配置代理 %s 端口失败", ctx.Proxy.IP.String()), err)
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (s *channelBaiyinProvider) removeRemote(_ string, batch *usedChanBatch) error {
|
|
configs := make([]*g.PortConfigsReq, len(batch.Chans))
|
|
for i, ch := range batch.Chans {
|
|
configs[i] = &g.PortConfigsReq{
|
|
Port: int(ch.Port()),
|
|
Edge: &[]string{},
|
|
AutoEdgeConfig: &g.AutoEdgeConfig{Count: u.P(0)},
|
|
Status: false,
|
|
}
|
|
}
|
|
|
|
proxy, err := q.Proxy.Where(q.Proxy.ID.Eq(batch.ProxyID)).Take()
|
|
if err != nil {
|
|
return core.NewServErr("获取代理数据失败", err)
|
|
}
|
|
|
|
gateway, err := proxyGateway(proxy)
|
|
if err != nil {
|
|
return core.NewServErr("创建代理网关失败", err)
|
|
}
|
|
|
|
if err = gateway.GatewayPortConfigs(configs); err != nil {
|
|
return core.NewServErr(fmt.Sprintf("清空代理 %s 端口配置失败", proxy.IP.String()), err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ensureEdges 检查本地节点是否足够,如果不足从云端连入
|
|
// 本地节点通过 Assigned = false 排除已分配节点
|
|
// 云端节点通过 NoRepeat = true 排除已分配节点
|
|
func ensureEdges(proxy *m.Proxy, gateway g.GatewayClient, filter *EdgeFilter, count int) error {
|
|
if filter.IsEmpty() {
|
|
return nil // 没有过滤条件,直接返回空,避免无意义的查询
|
|
}
|
|
|
|
// 先查本地
|
|
localEdges, 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 core.NewBizErr("检查可用节点失败[1]", err)
|
|
}
|
|
if len(localEdges) >= count {
|
|
return nil // 本地节点足够,直接返回空,后续逻辑会优先使用本地节点
|
|
}
|
|
|
|
// 再查云端
|
|
remaining := count - len(localEdges)
|
|
cloudEdges, 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 core.NewBizErr("检查可用节点失败[2]", err)
|
|
}
|
|
if len(cloudEdges.Edges) < remaining {
|
|
return core.NewBizErr("地区可用节点数量不足")
|
|
}
|
|
|
|
// 连入云端节点
|
|
edges := make([]string, remaining)
|
|
for i, edge := range cloudEdges.Edges {
|
|
edges[i] = edge.EdgeID
|
|
}
|
|
|
|
if err := g.Cloud.CloudConnect(&g.CloudConnectReq{Uuid: proxy.Mac, Edge: &edges}); err != nil {
|
|
return core.NewServErr("连接云平台失败", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type EdgeInfo struct {
|
|
Type EdgeInfoType
|
|
EdgeID string
|
|
}
|
|
|
|
type EdgeInfoType string
|
|
|
|
const (
|
|
EdgeInfoLocal EdgeInfoType = "local"
|
|
EdgeInfoCloud EdgeInfoType = "cloud"
|
|
)
|