11111
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 29s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 1m3s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 49s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 1m30s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 46s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 1m29s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 51s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m44s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 1m5s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 1m15s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 1m35s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 1m3s

This commit is contained in:
2026-01-03 01:55:41 +08:00
parent 5c2727e342
commit 0dfd14ab5c
9 changed files with 66 additions and 233 deletions

View File

@@ -7,7 +7,6 @@ import (
"github.com/gotunnel/internal/client/tunnel"
"github.com/gotunnel/pkg/crypto"
"github.com/gotunnel/pkg/plugin"
"github.com/gotunnel/pkg/plugin/builtin"
)
func main() {
@@ -30,15 +29,9 @@ func main() {
log.Printf("[Client] TLS enabled")
}
// 初始化插件系统
// 初始化插件注册表(用于 JS 插件)
registry := plugin.NewRegistry()
for _, h := range builtin.GetClientPlugins() {
if err := registry.RegisterClient(h); err != nil {
log.Fatalf("[Plugin] Register error: %v", err)
}
}
client.SetPluginRegistry(registry)
log.Printf("[Plugin] Registered %d plugins", len(builtin.GetClientPlugins()))
client.Run()
}

View File

@@ -27,7 +27,6 @@ import (
"github.com/gotunnel/internal/server/tunnel"
"github.com/gotunnel/pkg/crypto"
"github.com/gotunnel/pkg/plugin"
"github.com/gotunnel/pkg/plugin/builtin"
"github.com/gotunnel/pkg/plugin/sign"
)
@@ -71,14 +70,10 @@ func main() {
log.Printf("[Server] TLS enabled")
}
// 初始化插件系统
// 初始化插件系统(用于客户端 JS 插件管理)
registry := plugin.NewRegistry()
if err := registry.RegisterAllServer(builtin.GetServerPlugins()); err != nil {
log.Fatalf("[Plugin] Register error: %v", err)
}
server.SetPluginRegistry(registry)
server.SetJSPluginStore(clientStore) // 设置 JS 插件存储,用于客户端重连时恢复插件
log.Printf("[Plugin] Registered %d plugins", len(builtin.GetServerPlugins()))
// 加载 JS 插件配置
if len(cfg.JSPlugins) > 0 {

View File

@@ -1,51 +0,0 @@
package plugin
import (
"log"
"sync"
"github.com/gotunnel/pkg/plugin"
"github.com/gotunnel/pkg/plugin/builtin"
)
// Manager 客户端 plugin 管理器
type Manager struct {
registry *plugin.Registry
mu sync.RWMutex
}
// NewManager 创建客户端 plugin 管理器
func NewManager() (*Manager, error) {
registry := plugin.NewRegistry()
m := &Manager{
registry: registry,
}
if err := m.registerBuiltins(); err != nil {
return nil, err
}
return m, nil
}
// registerBuiltins 注册内置 plugins
func (m *Manager) registerBuiltins() error {
for _, h := range builtin.GetClientPlugins() {
if err := m.registry.RegisterClient(h); err != nil {
return err
}
}
log.Printf("[Plugin] Registered %d client plugins", len(builtin.GetClientPlugins()))
return nil
}
// GetClient 返回客户端插件
func (m *Manager) GetClient(name string) (plugin.ClientPlugin, error) {
return m.registry.GetClient(name)
}
// GetRegistry 返回插件注册表
func (m *Manager) GetRegistry() *plugin.Registry {
return m.registry
}

View File

@@ -509,6 +509,18 @@ func (c *Client) handleJSPluginInstall(stream net.Conn, msg *protocol.Message) {
log.Printf("[Client] Installing JS plugin: %s", req.PluginName)
// 如果插件已经在运行,先停止它
key := req.PluginName + ":" + req.RuleName
c.pluginMu.Lock()
if existingHandler, ok := c.runningPlugins[key]; ok {
log.Printf("[Client] Stopping existing plugin %s before reinstall", key)
if err := existingHandler.Stop(); err != nil {
log.Printf("[Client] Stop existing plugin error: %v", err)
}
delete(c.runningPlugins, key)
}
c.pluginMu.Unlock()
// 验证官方签名
if err := c.verifyJSPluginSignature(req.PluginName, req.Source, req.Signature); err != nil {
log.Printf("[Client] JS plugin %s signature verification failed: %v", req.PluginName, err)

View File

@@ -1,11 +1,9 @@
package plugin
import (
"log"
"sync"
"github.com/gotunnel/pkg/plugin"
"github.com/gotunnel/pkg/plugin/builtin"
)
// Manager 服务端 plugin 管理器
@@ -22,33 +20,9 @@ func NewManager() (*Manager, error) {
registry: registry,
}
if err := m.registerBuiltins(); err != nil {
return nil, err
}
return m, nil
}
// registerBuiltins 注册内置 plugins
func (m *Manager) registerBuiltins() error {
if err := m.registry.RegisterAllServer(builtin.GetServerPlugins()); err != nil {
return err
}
for _, h := range builtin.GetClientPlugins() {
if err := m.registry.RegisterClient(h); err != nil {
return err
}
}
log.Printf("[Plugin] Registered %d server, %d client plugins",
len(builtin.GetServerPlugins()), len(builtin.GetClientPlugins()))
return nil
}
// GetServer 返回服务端插件
func (m *Manager) GetServer(name string) (plugin.ServerPlugin, error) {
return m.registry.GetServer(name)
}
// ListPlugins 返回所有插件
func (m *Manager) ListPlugins() []plugin.Info {
return m.registry.List()

View File

@@ -471,21 +471,7 @@ func (s *Server) acceptProxyConns(cs *ClientSession, ln net.Listener, rule proto
func (s *Server) acceptProxyServerConns(cs *ClientSession, ln net.Listener, rule protocol.ProxyRule) {
dialer := proxy.NewTunnelDialer(cs.Session)
// 优先使用插件系统
if s.pluginRegistry != nil {
if handler, err := s.pluginRegistry.GetServer(rule.Type); err == nil {
handler.Init(rule.PluginConfig)
for {
conn, err := ln.Accept()
if err != nil {
return
}
go handler.HandleConn(conn, dialer)
}
}
}
// 回退到内置 proxy 实现
// 使用内置 proxy 实现
proxyServer := proxy.NewServer(rule.Type, dialer)
for {
conn, err := ln.Accept()
@@ -771,14 +757,9 @@ func (s *Server) InstallPluginsToClient(clientID string, plugins []string) error
}
}
if !found {
// 获取插件信息
version := "1.0.0"
if handler, err := s.pluginRegistry.GetServer(pluginName); err == nil && handler != nil {
version = handler.Metadata().Version
}
client.Plugins = append(client.Plugins, db.ClientPlugin{
Name: pluginName,
Version: version,
Version: "1.0.0",
Enabled: true,
})
}
@@ -893,7 +874,7 @@ func (s *Server) GetPluginConfigSchema(name string) ([]router.ConfigField, error
return nil, fmt.Errorf("plugin registry not initialized")
}
handler, err := s.pluginRegistry.GetServer(name)
handler, err := s.pluginRegistry.GetClient(name)
if err != nil {
return nil, fmt.Errorf("plugin %s not found", name)
}
@@ -1302,37 +1283,64 @@ func (s *Server) sendClientPluginStop(session *yamux.Session, pluginName, ruleNa
return nil
}
// RestartClientPlugin 重启客户端插件
// RestartClientPlugin 重启客户端 JS 插件
func (s *Server) RestartClientPlugin(clientID, pluginName, ruleName string) error {
s.mu.RLock()
cs, ok := s.clients[clientID]
_, ok := s.clients[clientID]
s.mu.RUnlock()
if !ok {
return fmt.Errorf("client %s not found or not online", clientID)
}
// 查找规则(用于内置插件
var rule *protocol.ProxyRule
for _, r := range cs.Rules {
if r.Name == ruleName && r.Type == pluginName {
rule = &r
// 重新发送完整的安装请求来重启 JS 插件
return s.reinstallJSPlugin(clientID, pluginName, ruleName)
}
// reinstallJSPlugin 重新安装 JS 插件(用于重启)
func (s *Server) reinstallJSPlugin(clientID, pluginName, ruleName string) error {
// 从数据库获取插件信息
if s.jsPluginStore == nil {
return fmt.Errorf("JS plugin store not configured")
}
jsPlugin, err := s.jsPluginStore.GetJSPlugin(pluginName)
if err != nil {
return fmt.Errorf("plugin %s not found: %w", pluginName, err)
}
// 获取客户端的插件配置
client, err := s.clientStore.GetClient(clientID)
if err != nil {
return fmt.Errorf("client not found: %w", err)
}
// 合并配置
config := jsPlugin.Config
if config == nil {
config = make(map[string]string)
}
for _, cp := range client.Plugins {
if cp.Name == pluginName {
for k, v := range cp.Config {
config[k] = v
}
break
}
}
// 先停止
if err := s.sendClientPluginStop(cs.Session, pluginName, ruleName); err != nil {
log.Printf("[Server] Stop plugin warning: %v", err)
log.Printf("[Server] Reinstalling JS plugin %s to client %s", pluginName, clientID)
req := router.JSPluginInstallRequest{
PluginName: pluginName,
Source: jsPlugin.Source,
Signature: jsPlugin.Signature,
RuleName: ruleName,
Config: config,
AutoStart: true, // 重启时总是自动启动
}
// 如果找到规则,使用规则重启(内置插件)
if rule != nil {
return s.sendClientPluginStart(cs.Session, *rule)
}
// 否则发送 JS 插件重启命令
return s.sendJSPluginRestart(cs.Session, pluginName, ruleName)
return s.InstallJSPluginToClient(clientID, req)
}
// sendJSPluginRestart 发送 JS 插件重启命令

View File

@@ -1,28 +0,0 @@
package builtin
import "github.com/gotunnel/pkg/plugin"
var (
serverPlugins []plugin.ServerPlugin
clientPlugins []plugin.ClientPlugin
)
// RegisterServer 注册服务端插件
func RegisterServer(handler plugin.ServerPlugin) {
serverPlugins = append(serverPlugins, handler)
}
// RegisterClient 注册客户端插件
func RegisterClient(handler plugin.ClientPlugin) {
clientPlugins = append(clientPlugins, handler)
}
// GetServerPlugins 返回所有服务端插件
func GetServerPlugins() []plugin.ServerPlugin {
return serverPlugins
}
// GetClientPlugins 返回所有客户端插件
func GetClientPlugins() []plugin.ClientPlugin {
return clientPlugins
}

View File

@@ -6,9 +6,8 @@ import (
"sync"
)
// Registry 管理可用的 plugins
// Registry 管理可用的 plugins (仅客户端插件)
type Registry struct {
serverPlugins map[string]ServerPlugin // 服务端插件
clientPlugins map[string]ClientPlugin // 客户端插件
enabled map[string]bool // 启用状态
mu sync.RWMutex
@@ -17,31 +16,11 @@ type Registry struct {
// NewRegistry 创建 plugin 注册表
func NewRegistry() *Registry {
return &Registry{
serverPlugins: make(map[string]ServerPlugin),
clientPlugins: make(map[string]ClientPlugin),
enabled: make(map[string]bool),
}
}
// RegisterServer 注册服务端插件
func (r *Registry) RegisterServer(handler ServerPlugin) error {
r.mu.Lock()
defer r.mu.Unlock()
meta := handler.Metadata()
if meta.Name == "" {
return fmt.Errorf("plugin name cannot be empty")
}
if _, exists := r.serverPlugins[meta.Name]; exists {
return fmt.Errorf("plugin %s already registered", meta.Name)
}
r.serverPlugins[meta.Name] = handler
r.enabled[meta.Name] = true
return nil
}
// RegisterClient 注册客户端插件
func (r *Registry) RegisterClient(handler ClientPlugin) error {
r.mu.Lock()
@@ -61,20 +40,6 @@ func (r *Registry) RegisterClient(handler ClientPlugin) error {
return nil
}
// GetServer 返回服务端插件
func (r *Registry) GetServer(name string) (ServerPlugin, error) {
r.mu.RLock()
defer r.mu.RUnlock()
if handler, ok := r.serverPlugins[name]; ok {
if !r.enabled[name] {
return nil, fmt.Errorf("plugin %s is disabled", name)
}
return handler, nil
}
return nil, fmt.Errorf("plugin %s not found", name)
}
// GetClient 返回客户端插件
func (r *Registry) GetClient(name string) (ClientPlugin, error) {
r.mu.RLock()
@@ -96,14 +61,6 @@ func (r *Registry) List() []Info {
var plugins []Info
for name, handler := range r.serverPlugins {
plugins = append(plugins, Info{
Metadata: handler.Metadata(),
Loaded: true,
Enabled: r.enabled[name],
})
}
for name, handler := range r.clientPlugins {
plugins = append(plugins, Info{
Metadata: handler.Metadata(),
@@ -120,9 +77,8 @@ func (r *Registry) Has(name string) bool {
r.mu.RLock()
defer r.mu.RUnlock()
_, ok1 := r.serverPlugins[name]
_, ok2 := r.clientPlugins[name]
return ok1 || ok2
_, ok := r.clientPlugins[name]
return ok
}
// Close 关闭所有 plugins
@@ -131,11 +87,6 @@ func (r *Registry) Close(ctx context.Context) error {
defer r.mu.Unlock()
var lastErr error
for name, handler := range r.serverPlugins {
if err := handler.Close(); err != nil {
lastErr = fmt.Errorf("failed to close plugin %s: %w", name, err)
}
}
for name, handler := range r.clientPlugins {
if err := handler.Stop(); err != nil {
lastErr = fmt.Errorf("failed to stop client plugin %s: %w", name, err)
@@ -171,9 +122,8 @@ func (r *Registry) Disable(name string) error {
// has 内部检查(无锁)
func (r *Registry) has(name string) bool {
_, ok1 := r.serverPlugins[name]
_, ok2 := r.clientPlugins[name]
return ok1 || ok2
_, ok := r.clientPlugins[name]
return ok
}
// IsEnabled 检查插件是否启用
@@ -182,13 +132,3 @@ func (r *Registry) IsEnabled(name string) bool {
defer r.mu.RUnlock()
return r.enabled[name]
}
// RegisterAllServer 批量注册服务端插件
func (r *Registry) RegisterAllServer(handlers []ServerPlugin) error {
for _, handler := range handlers {
if err := r.RegisterServer(handler); err != nil {
return err
}
}
return nil
}

View File

@@ -13,7 +13,6 @@ import (
type Side string
const (
SideServer Side = "server"
SideClient Side = "client"
)
@@ -100,15 +99,6 @@ type Dialer interface {
Dial(network, address string) (net.Conn, error)
}
// ServerPlugin 服务端插件接口
// 运行在服务端,处理外部连接并通过隧道转发到客户端
type ServerPlugin interface {
Metadata() Metadata
Init(config map[string]string) error
HandleConn(conn net.Conn, dialer Dialer) error
Close() error
}
// ClientPlugin 客户端插件接口
// 运行在客户端,提供本地服务
type ClientPlugin interface {