This commit is contained in:
@@ -1,11 +1,6 @@
|
||||
package plugin
|
||||
|
||||
// RegisterBuiltins 注册所有内置 plugins
|
||||
// 注意:此函数需要在调用方导入 builtin 包并手动注册
|
||||
// 示例:
|
||||
// registry := plugin.NewRegistry()
|
||||
// registry.RegisterBuiltin(builtin.NewSOCKS5Plugin())
|
||||
// registry.RegisterBuiltin(builtin.NewHTTPPlugin())
|
||||
func RegisterBuiltins(registry *Registry, handlers ...ProxyHandler) error {
|
||||
for _, handler := range handlers {
|
||||
if err := registry.RegisterBuiltin(handler); err != nil {
|
||||
|
||||
16
pkg/plugin/builtin/register.go
Normal file
16
pkg/plugin/builtin/register.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package builtin
|
||||
|
||||
import "github.com/gotunnel/pkg/plugin"
|
||||
|
||||
// 全局插件注册表
|
||||
var registry []plugin.ProxyHandler
|
||||
|
||||
// Register 插件自注册函数,由各插件的 init() 调用
|
||||
func Register(handler plugin.ProxyHandler) {
|
||||
registry = append(registry, handler)
|
||||
}
|
||||
|
||||
// GetAll 返回所有已注册的内置插件
|
||||
func GetAll() []plugin.ProxyHandler {
|
||||
return registry
|
||||
}
|
||||
@@ -10,6 +10,10 @@ import (
|
||||
"github.com/gotunnel/pkg/plugin"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register(NewSOCKS5Plugin())
|
||||
}
|
||||
|
||||
const (
|
||||
socks5Version = 0x05
|
||||
noAuth = 0x00
|
||||
|
||||
86
pkg/plugin/builtin/vnc.go
Normal file
86
pkg/plugin/builtin/vnc.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"github.com/gotunnel/pkg/plugin"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register(NewVNCPlugin())
|
||||
}
|
||||
|
||||
// VNCPlugin VNC 远程桌面插件
|
||||
type VNCPlugin struct {
|
||||
config map[string]string
|
||||
}
|
||||
|
||||
// NewVNCPlugin 创建 VNC plugin
|
||||
func NewVNCPlugin() *VNCPlugin {
|
||||
return &VNCPlugin{}
|
||||
}
|
||||
|
||||
// Metadata 返回 plugin 信息
|
||||
func (p *VNCPlugin) Metadata() plugin.PluginMetadata {
|
||||
return plugin.PluginMetadata{
|
||||
Name: "vnc",
|
||||
Version: "1.0.0",
|
||||
Type: plugin.PluginTypeApp,
|
||||
Source: plugin.PluginSourceBuiltin,
|
||||
Description: "VNC remote desktop relay (connects to client's local VNC server)",
|
||||
Author: "GoTunnel",
|
||||
Capabilities: []string{
|
||||
"dial", "read", "write", "close",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Init 初始化 plugin
|
||||
func (p *VNCPlugin) Init(config map[string]string) error {
|
||||
p.config = config
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandleConn 处理 VNC 连接
|
||||
// 将外部 VNC 客户端连接转发到客户端本地的 VNC 服务
|
||||
func (p *VNCPlugin) HandleConn(conn net.Conn, dialer plugin.Dialer) error {
|
||||
defer conn.Close()
|
||||
|
||||
// 默认连接客户端本地的 VNC 服务 (5900)
|
||||
vncAddr := "127.0.0.1:5900"
|
||||
if addr, ok := p.config["vnc_addr"]; ok && addr != "" {
|
||||
vncAddr = addr
|
||||
}
|
||||
|
||||
log.Printf("[VNC] New connection from %s, forwarding to %s", conn.RemoteAddr(), vncAddr)
|
||||
|
||||
// 通过隧道连接到客户端本地的 VNC 服务
|
||||
remote, err := dialer.Dial("tcp", vncAddr)
|
||||
if err != nil {
|
||||
log.Printf("[VNC] Failed to connect to %s: %v", vncAddr, err)
|
||||
return err
|
||||
}
|
||||
defer remote.Close()
|
||||
|
||||
// 双向转发 VNC 流量
|
||||
errCh := make(chan error, 2)
|
||||
go func() {
|
||||
_, err := io.Copy(remote, conn)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, err := io.Copy(conn, remote)
|
||||
errCh <- err
|
||||
}()
|
||||
|
||||
// 等待任一方向完成
|
||||
<-errCh
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 释放资源
|
||||
func (p *VNCPlugin) Close() error {
|
||||
return nil
|
||||
}
|
||||
@@ -8,14 +8,16 @@ import (
|
||||
|
||||
// Registry 管理可用的 plugins
|
||||
type Registry struct {
|
||||
builtin map[string]ProxyHandler // 内置 Go 实现
|
||||
mu sync.RWMutex
|
||||
builtin map[string]ProxyHandler // 内置 Go 实现
|
||||
enabled map[string]bool // 启用状态
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewRegistry 创建 plugin 注册表
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{
|
||||
builtin: make(map[string]ProxyHandler),
|
||||
enabled: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@ func (r *Registry) RegisterBuiltin(handler ProxyHandler) error {
|
||||
}
|
||||
|
||||
r.builtin[meta.Name] = handler
|
||||
r.enabled[meta.Name] = true // 默认启用
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -44,6 +47,9 @@ func (r *Registry) Get(proxyType string) (ProxyHandler, error) {
|
||||
|
||||
// 先查找内置 plugin
|
||||
if handler, ok := r.builtin[proxyType]; ok {
|
||||
if !r.enabled[proxyType] {
|
||||
return nil, fmt.Errorf("plugin %s is disabled", proxyType)
|
||||
}
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
@@ -58,10 +64,11 @@ func (r *Registry) List() []PluginInfo {
|
||||
var plugins []PluginInfo
|
||||
|
||||
// 内置 plugins
|
||||
for _, handler := range r.builtin {
|
||||
for name, handler := range r.builtin {
|
||||
plugins = append(plugins, PluginInfo{
|
||||
Metadata: handler.Metadata(),
|
||||
Loaded: true,
|
||||
Enabled: r.enabled[name],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -91,3 +98,44 @@ func (r *Registry) Close(ctx context.Context) error {
|
||||
|
||||
return lastErr
|
||||
}
|
||||
|
||||
// Enable 启用插件
|
||||
func (r *Registry) Enable(name string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if _, ok := r.builtin[name]; !ok {
|
||||
return fmt.Errorf("plugin %s not found", name)
|
||||
}
|
||||
r.enabled[name] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Disable 禁用插件
|
||||
func (r *Registry) Disable(name string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if _, ok := r.builtin[name]; !ok {
|
||||
return fmt.Errorf("plugin %s not found", name)
|
||||
}
|
||||
r.enabled[name] = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsEnabled 检查插件是否启用
|
||||
func (r *Registry) IsEnabled(name string) bool {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
return r.enabled[name]
|
||||
}
|
||||
|
||||
// RegisterAll 批量注册插件
|
||||
func (r *Registry) RegisterAll(handlers []ProxyHandler) error {
|
||||
for _, handler := range handlers {
|
||||
if err := r.RegisterBuiltin(handler); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/gotunnel/pkg/plugin"
|
||||
)
|
||||
|
||||
// PluginStore 管理 plugin 持久化
|
||||
type PluginStore interface {
|
||||
// GetAllPlugins 返回所有存储的 plugins
|
||||
GetAllPlugins() ([]plugin.PluginMetadata, error)
|
||||
|
||||
// GetPlugin 返回指定 plugin 的元数据
|
||||
GetPlugin(name string) (*plugin.PluginMetadata, error)
|
||||
|
||||
// GetPluginData 返回 WASM 二进制
|
||||
GetPluginData(name string) ([]byte, error)
|
||||
|
||||
// SavePlugin 存储 plugin
|
||||
SavePlugin(metadata plugin.PluginMetadata, wasmData []byte) error
|
||||
|
||||
// DeletePlugin 删除 plugin
|
||||
DeletePlugin(name string) error
|
||||
|
||||
// PluginExists 检查 plugin 是否存在
|
||||
PluginExists(name string) (bool, error)
|
||||
|
||||
// Close 关闭存储
|
||||
Close() error
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gotunnel/pkg/plugin"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
// SQLiteStore SQLite 实现的 PluginStore
|
||||
type SQLiteStore struct {
|
||||
db *sql.DB
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewSQLiteStore 创建 SQLite plugin 存储
|
||||
func NewSQLiteStore(dbPath string) (*SQLiteStore, error) {
|
||||
db, err := sql.Open("sqlite", dbPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store := &SQLiteStore{db: db}
|
||||
if err := store.init(); err != nil {
|
||||
db.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return store, nil
|
||||
}
|
||||
|
||||
// init 初始化数据库表
|
||||
func (s *SQLiteStore) init() error {
|
||||
query := `
|
||||
CREATE TABLE IF NOT EXISTS plugins (
|
||||
name TEXT PRIMARY KEY,
|
||||
version TEXT NOT NULL,
|
||||
type TEXT NOT NULL DEFAULT 'proxy',
|
||||
source TEXT NOT NULL DEFAULT 'wasm',
|
||||
description TEXT,
|
||||
author TEXT,
|
||||
checksum TEXT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
capabilities TEXT NOT NULL DEFAULT '[]',
|
||||
config_schema TEXT NOT NULL DEFAULT '{}',
|
||||
wasm_data BLOB NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)`
|
||||
_, err := s.db.Exec(query)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetAllPlugins 返回所有存储的 plugins
|
||||
func (s *SQLiteStore) GetAllPlugins() ([]plugin.PluginMetadata, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
rows, err := s.db.Query(`
|
||||
SELECT name, version, type, source, description, author,
|
||||
checksum, size, capabilities, config_schema
|
||||
FROM plugins`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var plugins []plugin.PluginMetadata
|
||||
for rows.Next() {
|
||||
var m plugin.PluginMetadata
|
||||
var capJSON, configJSON string
|
||||
err := rows.Scan(&m.Name, &m.Version, &m.Type, &m.Source,
|
||||
&m.Description, &m.Author, &m.Checksum, &m.Size,
|
||||
&capJSON, &configJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json.Unmarshal([]byte(capJSON), &m.Capabilities)
|
||||
json.Unmarshal([]byte(configJSON), &m.ConfigSchema)
|
||||
plugins = append(plugins, m)
|
||||
}
|
||||
return plugins, rows.Err()
|
||||
}
|
||||
|
||||
// GetPlugin 返回指定 plugin 的元数据
|
||||
func (s *SQLiteStore) GetPlugin(name string) (*plugin.PluginMetadata, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
var m plugin.PluginMetadata
|
||||
var capJSON, configJSON string
|
||||
err := s.db.QueryRow(`
|
||||
SELECT name, version, type, source, description, author,
|
||||
checksum, size, capabilities, config_schema
|
||||
FROM plugins WHERE name = ?`, name).Scan(
|
||||
&m.Name, &m.Version, &m.Type, &m.Source,
|
||||
&m.Description, &m.Author, &m.Checksum, &m.Size,
|
||||
&capJSON, &configJSON)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json.Unmarshal([]byte(capJSON), &m.Capabilities)
|
||||
json.Unmarshal([]byte(configJSON), &m.ConfigSchema)
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// GetPluginData 返回 WASM 二进制
|
||||
func (s *SQLiteStore) GetPluginData(name string) ([]byte, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
var data []byte
|
||||
err := s.db.QueryRow(`SELECT wasm_data FROM plugins WHERE name = ?`, name).Scan(&data)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, fmt.Errorf("plugin %s not found", name)
|
||||
}
|
||||
return data, err
|
||||
}
|
||||
|
||||
// SavePlugin 存储 plugin
|
||||
func (s *SQLiteStore) SavePlugin(metadata plugin.PluginMetadata, wasmData []byte) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
capJSON, _ := json.Marshal(metadata.Capabilities)
|
||||
configJSON, _ := json.Marshal(metadata.ConfigSchema)
|
||||
|
||||
_, err := s.db.Exec(`
|
||||
INSERT OR REPLACE INTO plugins
|
||||
(name, version, type, source, description, author, checksum, size,
|
||||
capabilities, config_schema, wasm_data, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
metadata.Name, metadata.Version, metadata.Type, metadata.Source,
|
||||
metadata.Description, metadata.Author, metadata.Checksum, metadata.Size,
|
||||
string(capJSON), string(configJSON), wasmData, time.Now())
|
||||
return err
|
||||
}
|
||||
|
||||
// DeletePlugin 删除 plugin
|
||||
func (s *SQLiteStore) DeletePlugin(name string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
_, err := s.db.Exec(`DELETE FROM plugins WHERE name = ?`, name)
|
||||
return err
|
||||
}
|
||||
|
||||
// PluginExists 检查 plugin 是否存在
|
||||
func (s *SQLiteStore) PluginExists(name string) (bool, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
var count int
|
||||
err := s.db.QueryRow(`SELECT COUNT(*) FROM plugins WHERE name = ?`, name).Scan(&count)
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// Close 关闭存储
|
||||
func (s *SQLiteStore) Close() error {
|
||||
return s.db.Close()
|
||||
}
|
||||
@@ -9,7 +9,10 @@ import (
|
||||
type PluginType string
|
||||
|
||||
const (
|
||||
PluginTypeProxy PluginType = "proxy" // 代理处理器 (SOCKS5, HTTP 等)
|
||||
PluginTypeProxy PluginType = "proxy" // 代理协议插件 (SOCKS5 等)
|
||||
PluginTypeApp PluginType = "app" // 应用插件 (VNC, 文件管理等)
|
||||
PluginTypeService PluginType = "service" // 服务插件 (Web服务等)
|
||||
PluginTypeTool PluginType = "tool" // 工具插件 (监控、日志等)
|
||||
)
|
||||
|
||||
// PluginSource 表示 plugin 来源
|
||||
@@ -38,6 +41,7 @@ type PluginMetadata struct {
|
||||
type PluginInfo struct {
|
||||
Metadata PluginMetadata `json:"metadata"`
|
||||
Loaded bool `json:"loaded"`
|
||||
Enabled bool `json:"enabled"`
|
||||
LoadedAt time.Time `json:"loaded_at,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user