feat: add support for starting plugin rules with remote port configuration
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 28s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 1m7s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 50s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 2m33s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 1m2s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 2m26s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 58s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 2m32s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 2m9s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 1m30s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 3m6s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 2m30s

This commit is contained in:
2026-01-04 19:28:00 +08:00
parent d6bde71c94
commit 458bb35005
3 changed files with 58 additions and 1 deletions

View File

@@ -47,6 +47,8 @@ type ServerInterface interface {
StopClientLogStream(sessionID string)
// 插件状态查询
GetClientPluginStatus(clientID string) ([]protocol.PluginStatusEntry, error)
// 插件规则管理
StartPluginRule(clientID string, rule protocol.ProxyRule) error
}
// ConfigField 配置字段

View File

@@ -7,8 +7,8 @@ import (
"github.com/gin-gonic/gin"
"github.com/gotunnel/internal/server/db"
// removed router import
"github.com/gotunnel/internal/server/router/dto"
"github.com/gotunnel/pkg/protocol"
)
// StoreHandler 插件商店处理器
@@ -192,9 +192,26 @@ func (h *StoreHandler) Install(c *gin.Context) {
h.app.GetClientStore().UpdateClient(dbClient)
}
// 启动服务端监听器(让外部用户可以通过 RemotePort 访问插件)
if req.RemotePort > 0 {
pluginRule := protocol.ProxyRule{
Name: req.PluginName,
Type: req.PluginName, // 使用插件名作为类型,让 isClientPlugin 识别
RemotePort: req.RemotePort,
Enabled: boolPtr(true),
}
// 启动监听器(忽略错误,可能端口已被占用)
h.app.GetServer().StartPluginRule(req.ClientID, pluginRule)
}
Success(c, gin.H{
"status": "ok",
"plugin": req.PluginName,
"client": req.ClientID,
})
}
// boolPtr 返回 bool 值的指针
func boolPtr(b bool) *bool {
return &b
}

View File

@@ -1227,6 +1227,15 @@ func (s *Server) pushClientInstalledPlugins(cs *ClientSession, alreadyPushed map
if err := s.InstallJSPluginToClient(cs.ID, req); err != nil {
log.Printf("[Server] Failed to restore plugin %s: %v", cp.Name, err)
} else if cp.RemotePort > 0 {
// 安装成功后启动服务端监听器
pluginRule := protocol.ProxyRule{
Name: cp.Name,
Type: cp.Name,
RemotePort: cp.RemotePort,
Enabled: boolPtr(true),
}
s.startClientPluginListener(cs, pluginRule)
}
}
}
@@ -1342,6 +1351,30 @@ func (s *Server) sendClientPluginStop(session *yamux.Session, pluginName, ruleNa
return nil
}
// StartPluginRule 为客户端插件启动服务端监听器
func (s *Server) StartPluginRule(clientID string, rule protocol.ProxyRule) error {
s.mu.RLock()
cs, ok := s.clients[clientID]
s.mu.RUnlock()
if !ok {
return fmt.Errorf("client %s not found or not online", clientID)
}
// 检查端口是否已被占用
cs.mu.Lock()
_, exists := cs.Listeners[rule.RemotePort]
cs.mu.Unlock()
if exists {
// 端口已在监听,无需重复启动
return nil
}
// 启动插件监听器
s.startClientPluginListener(cs, rule)
return nil
}
// RestartClientPlugin 重启客户端 JS 插件
func (s *Server) RestartClientPlugin(clientID, pluginName, ruleName string) error {
s.mu.RLock()
@@ -1612,3 +1645,8 @@ func (s *Server) StopClientLogStream(sessionID string) {
s.logSessions.RemoveSession(sessionID)
}
// boolPtr 返回 bool 值的指针
func boolPtr(b bool) *bool {
return &b
}