add plugins
All checks were successful
Build Multi-Platform Binaries / build (push) Successful in 11m9s
All checks were successful
Build Multi-Platform Binaries / build (push) Successful in 11m9s
This commit is contained in:
114
internal/client/plugin/cache.go
Normal file
114
internal/client/plugin/cache.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gotunnel/pkg/plugin"
|
||||
)
|
||||
|
||||
// CachedPlugin 缓存的 plugin 信息
|
||||
type CachedPlugin struct {
|
||||
Metadata plugin.PluginMetadata
|
||||
Path string
|
||||
LoadedAt time.Time
|
||||
}
|
||||
|
||||
// Cache 管理本地 plugin 存储
|
||||
type Cache struct {
|
||||
dir string
|
||||
plugins map[string]*CachedPlugin
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewCache 创建 plugin 缓存
|
||||
func NewCache(cacheDir string) (*Cache, error) {
|
||||
if err := os.MkdirAll(cacheDir, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Cache{
|
||||
dir: cacheDir,
|
||||
plugins: make(map[string]*CachedPlugin),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Get 返回缓存的 plugin(如果有效)
|
||||
func (c *Cache) Get(name, version, checksum string) (*CachedPlugin, error) {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
cached, ok := c.plugins[name]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 验证版本和 checksum
|
||||
if cached.Metadata.Version != version {
|
||||
return nil, nil
|
||||
}
|
||||
if checksum != "" && cached.Metadata.Checksum != checksum {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
// Store 保存 plugin 到缓存
|
||||
func (c *Cache) Store(meta plugin.PluginMetadata, wasmData []byte) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
// 验证 checksum
|
||||
hash := sha256.Sum256(wasmData)
|
||||
checksum := hex.EncodeToString(hash[:])
|
||||
if meta.Checksum != "" && meta.Checksum != checksum {
|
||||
return fmt.Errorf("checksum mismatch")
|
||||
}
|
||||
meta.Checksum = checksum
|
||||
|
||||
// 写入文件
|
||||
path := filepath.Join(c.dir, meta.Name+".wasm")
|
||||
if err := os.WriteFile(path, wasmData, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.plugins[meta.Name] = &CachedPlugin{
|
||||
Metadata: meta,
|
||||
Path: path,
|
||||
LoadedAt: time.Now(),
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove 删除缓存的 plugin
|
||||
func (c *Cache) Remove(name string) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
cached, ok := c.plugins[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
os.Remove(cached.Path)
|
||||
delete(c.plugins, name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// List 返回所有缓存的 plugins
|
||||
func (c *Cache) List() []plugin.PluginMetadata {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
var result []plugin.PluginMetadata
|
||||
for _, cached := range c.plugins {
|
||||
result = append(result, cached.Metadata)
|
||||
}
|
||||
return result
|
||||
}
|
||||
70
internal/client/plugin/manager.go
Normal file
70
internal/client/plugin/manager.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/gotunnel/pkg/plugin"
|
||||
"github.com/gotunnel/pkg/plugin/builtin"
|
||||
"github.com/gotunnel/pkg/plugin/wasm"
|
||||
)
|
||||
|
||||
// Manager 客户端 plugin 管理器
|
||||
type Manager struct {
|
||||
registry *plugin.Registry
|
||||
cache *Cache
|
||||
runtime *wasm.Runtime
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewManager 创建客户端 plugin 管理器
|
||||
func NewManager(cacheDir string) (*Manager, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
cache, err := NewCache(cacheDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
runtime, err := wasm.NewRuntime(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
registry := plugin.NewRegistry()
|
||||
|
||||
m := &Manager{
|
||||
registry: registry,
|
||||
cache: cache,
|
||||
runtime: runtime,
|
||||
}
|
||||
|
||||
// 注册内置 plugins
|
||||
if err := m.registerBuiltins(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// registerBuiltins 注册内置 plugins
|
||||
// 注意: tcp, udp, http, https 是内置类型,直接在 tunnel 中处理
|
||||
func (m *Manager) registerBuiltins() error {
|
||||
// 注册 SOCKS5 plugin
|
||||
if err := m.registry.RegisterBuiltin(builtin.NewSOCKS5Plugin()); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("[Plugin] Builtin plugins registered: socks5")
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetHandler 返回指定代理类型的 handler
|
||||
func (m *Manager) GetHandler(proxyType string) (plugin.ProxyHandler, error) {
|
||||
return m.registry.Get(proxyType)
|
||||
}
|
||||
|
||||
// Close 关闭管理器
|
||||
func (m *Manager) Close(ctx context.Context) error {
|
||||
return m.runtime.Close(ctx)
|
||||
}
|
||||
Reference in New Issue
Block a user