实现手动 proxy 同步接口
This commit is contained in:
@@ -2,6 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"platform/pkg/u"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gen/field"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var Proxy = &proxyService{}
|
||||
@@ -23,11 +25,20 @@ type proxyService struct{}
|
||||
func hasUsedChans(proxyID int32) (bool, error) {
|
||||
ctx := context.Background()
|
||||
pattern := usedChansKey(proxyID, "*")
|
||||
keys, _, err := g.Redis.Scan(ctx, 0, pattern, 1).Result()
|
||||
if err != nil {
|
||||
return false, err
|
||||
var cursor uint64
|
||||
for {
|
||||
keys, next, err := g.Redis.Scan(ctx, cursor, pattern, 100).Result()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(keys) > 0 {
|
||||
return true, nil
|
||||
}
|
||||
if next == 0 {
|
||||
return false, nil
|
||||
}
|
||||
cursor = next
|
||||
}
|
||||
return len(keys) > 0, nil
|
||||
}
|
||||
|
||||
func rebuildFreeChans(proxyID int32, addr netip.Addr) error {
|
||||
@@ -161,17 +172,117 @@ func (s *proxyService) Update(update *UpdateProxy) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *proxyService) SyncPool(id int32) error {
|
||||
proxy, err := q.Proxy.Where(q.Proxy.ID.Eq(id)).Select(q.Proxy.ID, q.Proxy.IP).First()
|
||||
func (s *proxyService) SyncPorts(id int32) error {
|
||||
proxy, err := findOfflineProxy(id)
|
||||
if err != nil {
|
||||
return core.NewServErr("获取代理数据失败", err)
|
||||
return err
|
||||
}
|
||||
if proxy == nil {
|
||||
return core.NewBizErr("代理不存在")
|
||||
|
||||
used, err := hasUsedChans(id)
|
||||
if err != nil {
|
||||
return core.NewServErr("检查代理通道状态失败", err)
|
||||
}
|
||||
if used {
|
||||
return core.NewBizErr("代理存在未关闭通道,禁止重建端口池")
|
||||
}
|
||||
|
||||
return rebuildFreeChans(id, proxy.IP.Addr)
|
||||
}
|
||||
|
||||
func (s *proxyService) SyncChains(id int32) error {
|
||||
proxy, err := findOfflineProxy(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if proxy.Type != m.ProxyTypeGost {
|
||||
return core.NewBizErr("仅 GOST 代理支持重建代理链")
|
||||
}
|
||||
|
||||
chains, err := buildGostChainsFromEdges()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := proxyGost(proxy)
|
||||
if err != nil {
|
||||
return core.NewServErr("创建 GOST 客户端失败", err)
|
||||
}
|
||||
|
||||
oldChains, err := client.ListChains()
|
||||
if err != nil {
|
||||
return core.NewServErr("查询 GOST chains 失败", err)
|
||||
}
|
||||
for _, chain := range oldChains {
|
||||
if err := client.DeleteChain(chain.Name); err != nil {
|
||||
return core.NewServErr(fmt.Sprintf("删除 GOST chain 失败: %s", chain.Name), err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, chain := range chains {
|
||||
if err := client.CreateChain(chain); err != nil {
|
||||
return core.NewServErr(fmt.Sprintf("创建 GOST chain 失败: %s", chain.Name), err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := client.SaveConfig(); err != nil {
|
||||
return core.NewServErr("保存 GOST 配置失败", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func findOfflineProxy(id int32) (*m.Proxy, error) {
|
||||
proxy, err := q.Proxy.Where(q.Proxy.ID.Eq(id)).Take()
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, core.NewBizErr("代理不存在")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, core.NewServErr("获取代理数据失败", err)
|
||||
}
|
||||
if proxy.Status != m.ProxyStatusOffline {
|
||||
return nil, core.NewBizErr("代理未下线,禁止同步")
|
||||
}
|
||||
return proxy, nil
|
||||
}
|
||||
|
||||
func buildGostChainsFromEdges() ([]*g.GostChainConfig, error) {
|
||||
edges, err := q.Edge.
|
||||
Where(q.Edge.Type.Eq(int(m.EdgeTypeGostChain))).
|
||||
Order(q.Edge.ID).
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, core.NewServErr("查询 GOST edge 数据失败", err)
|
||||
}
|
||||
|
||||
chains := make([]*g.GostChainConfig, len(edges))
|
||||
for i, edge := range edges {
|
||||
if strings.TrimSpace(edge.Mac) == "" {
|
||||
return nil, core.NewBizErr(fmt.Sprintf("GOST edge %d chain 名称为空", edge.ID))
|
||||
}
|
||||
if !edge.IP.Addr.IsValid() {
|
||||
return nil, core.NewBizErr(fmt.Sprintf("GOST edge %s IP 无效", edge.Mac))
|
||||
}
|
||||
if edge.Port == nil || *edge.Port == 0 {
|
||||
return nil, core.NewBizErr(fmt.Sprintf("GOST edge %s 端口为空", edge.Mac))
|
||||
}
|
||||
|
||||
chains[i] = &g.GostChainConfig{
|
||||
Name: edge.Mac,
|
||||
Hops: []g.GostHopConfig{{
|
||||
Nodes: []g.GostNodeConfig{{
|
||||
Addr: netip.AddrPortFrom(edge.IP.Addr, *edge.Port).String(),
|
||||
Connector: g.GostConnectorConfig{
|
||||
Type: "socks5",
|
||||
},
|
||||
Dialer: g.GostDialerConfig{
|
||||
Type: "tcp",
|
||||
},
|
||||
}},
|
||||
}},
|
||||
}
|
||||
}
|
||||
return chains, nil
|
||||
}
|
||||
|
||||
func (s *proxyService) Remove(id int32) error {
|
||||
used, err := hasUsedChans(id)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user