添加 haproxy 协议支持
Some checks failed
Go / build (.exe, 386, windows, windows-386) (push) Has been cancelled
Go / build (.exe, amd64, windows, windows-amd64) (push) Has been cancelled
Go / build (.exe, arm64, windows, windows-arm64) (push) Has been cancelled
Go / build (386, freebsd, freebsd-386) (push) Has been cancelled
Go / build (386, linux, linux-386) (push) Has been cancelled
Go / build (386, netbsd, netbsd-386) (push) Has been cancelled
Go / build (386, openbsd, openbsd-386) (push) Has been cancelled
Go / build (386, plan9, plan9-386) (push) Has been cancelled
Go / build (amd64, darwin, darwin-amd64) (push) Has been cancelled
Go / build (amd64, dragonfly, dragonfly-amd64) (push) Has been cancelled
Go / build (amd64, freebsd, freebsd-amd64) (push) Has been cancelled
Go / build (amd64, illumos, illumos-amd64) (push) Has been cancelled
Go / build (amd64, linux, linux-amd64) (push) Has been cancelled
Go / build (amd64, netbsd, netbsd-amd64) (push) Has been cancelled
Go / build (amd64, openbsd, openbsd-amd64) (push) Has been cancelled
Go / build (amd64, plan9, plan9-amd64) (push) Has been cancelled
Go / build (amd64, solaris, solaris-amd64) (push) Has been cancelled
Go / build (arm, 6, linux, linux-armv6) (push) Has been cancelled
Go / build (arm, 7, linux, linux-armv7) (push) Has been cancelled
Go / build (arm, freebsd, freebsd-arm) (push) Has been cancelled
Go / build (arm, netbsd, netbsd-arm) (push) Has been cancelled
Go / build (arm, openbsd, openbsd-arm) (push) Has been cancelled
Go / build (arm, plan9, plan9-arm) (push) Has been cancelled
Go / build (arm64, darwin, darwin-arm64) (push) Has been cancelled
Go / build (arm64, freebsd, freebsd-arm64) (push) Has been cancelled
Go / build (arm64, linux, linux-arm64) (push) Has been cancelled
Go / build (arm64, netbsd, netbsd-arm64) (push) Has been cancelled
Go / build (arm64, openbsd, openbsd-arm64) (push) Has been cancelled
Go / build (loong64, linux, linux-loong64) (push) Has been cancelled
Go / build (mips, linux, linux-mips) (push) Has been cancelled
Go / build (mips64, linux, linux-mips64) (push) Has been cancelled
Go / build (mips64le, linux, linux-mips64le) (push) Has been cancelled
Go / build (mipsle, linux, linux-mipsle) (push) Has been cancelled
Go / build (ppc64, aix, aix-ppc64) (push) Has been cancelled
Go / build (ppc64, linux, linux-ppc64) (push) Has been cancelled
Go / build (ppc64, openbsd, openbsd-ppc64) (push) Has been cancelled
Go / build (ppc64le, linux, linux-ppc64le) (push) Has been cancelled
Go / build (riscv64, freebsd, freebsd-riscv64) (push) Has been cancelled
Go / build (riscv64, linux, linux-riscv64) (push) Has been cancelled
Go / build (riscv64, openbsd, openbsd-riscv64) (push) Has been cancelled
Go / build (s390x, linux, linux-s390x) (push) Has been cancelled
Go / build (wasm, js, js-wasm) (push) Has been cancelled
Go / build (wasm, wasip1, wasip1-wasm) (push) Has been cancelled
Go / merge-artifacts (push) Has been cancelled
Some checks failed
Go / build (.exe, 386, windows, windows-386) (push) Has been cancelled
Go / build (.exe, amd64, windows, windows-amd64) (push) Has been cancelled
Go / build (.exe, arm64, windows, windows-arm64) (push) Has been cancelled
Go / build (386, freebsd, freebsd-386) (push) Has been cancelled
Go / build (386, linux, linux-386) (push) Has been cancelled
Go / build (386, netbsd, netbsd-386) (push) Has been cancelled
Go / build (386, openbsd, openbsd-386) (push) Has been cancelled
Go / build (386, plan9, plan9-386) (push) Has been cancelled
Go / build (amd64, darwin, darwin-amd64) (push) Has been cancelled
Go / build (amd64, dragonfly, dragonfly-amd64) (push) Has been cancelled
Go / build (amd64, freebsd, freebsd-amd64) (push) Has been cancelled
Go / build (amd64, illumos, illumos-amd64) (push) Has been cancelled
Go / build (amd64, linux, linux-amd64) (push) Has been cancelled
Go / build (amd64, netbsd, netbsd-amd64) (push) Has been cancelled
Go / build (amd64, openbsd, openbsd-amd64) (push) Has been cancelled
Go / build (amd64, plan9, plan9-amd64) (push) Has been cancelled
Go / build (amd64, solaris, solaris-amd64) (push) Has been cancelled
Go / build (arm, 6, linux, linux-armv6) (push) Has been cancelled
Go / build (arm, 7, linux, linux-armv7) (push) Has been cancelled
Go / build (arm, freebsd, freebsd-arm) (push) Has been cancelled
Go / build (arm, netbsd, netbsd-arm) (push) Has been cancelled
Go / build (arm, openbsd, openbsd-arm) (push) Has been cancelled
Go / build (arm, plan9, plan9-arm) (push) Has been cancelled
Go / build (arm64, darwin, darwin-arm64) (push) Has been cancelled
Go / build (arm64, freebsd, freebsd-arm64) (push) Has been cancelled
Go / build (arm64, linux, linux-arm64) (push) Has been cancelled
Go / build (arm64, netbsd, netbsd-arm64) (push) Has been cancelled
Go / build (arm64, openbsd, openbsd-arm64) (push) Has been cancelled
Go / build (loong64, linux, linux-loong64) (push) Has been cancelled
Go / build (mips, linux, linux-mips) (push) Has been cancelled
Go / build (mips64, linux, linux-mips64) (push) Has been cancelled
Go / build (mips64le, linux, linux-mips64le) (push) Has been cancelled
Go / build (mipsle, linux, linux-mipsle) (push) Has been cancelled
Go / build (ppc64, aix, aix-ppc64) (push) Has been cancelled
Go / build (ppc64, linux, linux-ppc64) (push) Has been cancelled
Go / build (ppc64, openbsd, openbsd-ppc64) (push) Has been cancelled
Go / build (ppc64le, linux, linux-ppc64le) (push) Has been cancelled
Go / build (riscv64, freebsd, freebsd-riscv64) (push) Has been cancelled
Go / build (riscv64, linux, linux-riscv64) (push) Has been cancelled
Go / build (riscv64, openbsd, openbsd-riscv64) (push) Has been cancelled
Go / build (s390x, linux, linux-s390x) (push) Has been cancelled
Go / build (wasm, js, js-wasm) (push) Has been cancelled
Go / build (wasm, wasip1, wasip1-wasm) (push) Has been cancelled
Go / merge-artifacts (push) Has been cancelled
添加插件功能支持
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
@@ -22,13 +23,14 @@ var (
|
||||
|
||||
type (
|
||||
Config struct {
|
||||
Tcp ProtocolConfig `toml:"tcp"`
|
||||
Quic QuicConfig `toml:"quic"`
|
||||
Kcp KcpConfig `toml:"kcp"`
|
||||
WebSocket WebSocketConfig `toml:"websocket"`
|
||||
Hosts map[string]string `toml:"hosts"`
|
||||
Log LogConfig `toml:"log"`
|
||||
PidFile string `toml:"pid_file"`
|
||||
Tcp ProtocolConfig `toml:"tcp"`
|
||||
Quic QuicConfig `toml:"quic"`
|
||||
Kcp KcpConfig `toml:"kcp"`
|
||||
WebSocket WebSocketConfig `toml:"websocket"`
|
||||
Hosts map[string]string `toml:"hosts"`
|
||||
Log LogConfig `toml:"log"`
|
||||
PidFile string `toml:"pid_file"`
|
||||
Plugin map[string]map[string]any `toml:"plugin"`
|
||||
}
|
||||
|
||||
ProtocolConfig struct {
|
||||
@@ -115,7 +117,13 @@ func loadConfig() error {
|
||||
|
||||
writePIDFile()
|
||||
|
||||
return loadLogger()
|
||||
if err := loadLogger(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
loadPlugins()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func watchConfig() *fsnotify.Watcher {
|
||||
@@ -164,3 +172,23 @@ func watchConfig() *fsnotify.Watcher {
|
||||
|
||||
return watcher
|
||||
}
|
||||
|
||||
func loadPluginConfig(cfg map[string]any, pluginCfg any) error {
|
||||
log.Info().
|
||||
Any("config", cfg).
|
||||
Msg("Loading plugin config")
|
||||
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
Result: pluginCfg,
|
||||
TagName: "toml",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := decoder.Decode(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
52
cmd/gateway/haproxy.go
Normal file
52
cmd/gateway/haproxy.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
proxyproto "github.com/pires/go-proxyproto"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func haProxyUpstream(source net.Conn, host string) net.Conn {
|
||||
target, err := net.ResolveTCPAddr("tcp", host)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to resolve TCP address")
|
||||
return nil
|
||||
}
|
||||
|
||||
conn, err := net.DialTCP("tcp", nil, target)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to dial TCP")
|
||||
return nil
|
||||
}
|
||||
|
||||
sourceAddr, err := net.ResolveTCPAddr(
|
||||
source.RemoteAddr().Network(),
|
||||
source.RemoteAddr().String(),
|
||||
)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to resolve TCP address")
|
||||
return nil
|
||||
}
|
||||
|
||||
TransportProtocol := proxyproto.TCPv4
|
||||
if sourceAddr.IP.To4() == nil {
|
||||
TransportProtocol = proxyproto.TCPv6
|
||||
}
|
||||
|
||||
header := &proxyproto.Header{
|
||||
Version: 1,
|
||||
Command: proxyproto.PROXY,
|
||||
TransportProtocol: TransportProtocol,
|
||||
SourceAddr: sourceAddr,
|
||||
DestinationAddr: target,
|
||||
}
|
||||
// After the connection was created write the proxy headers first
|
||||
_, err = header.WriteTo(conn)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to write proxy header")
|
||||
return nil
|
||||
}
|
||||
|
||||
return conn
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/tursom/mc-gateway/plugin/api"
|
||||
"github.com/tursom/mc-gateway/protocol"
|
||||
)
|
||||
|
||||
@@ -26,16 +27,15 @@ func main() {
|
||||
|
||||
go handleLogRotate()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
defer exitWaitGroup.Wait()
|
||||
|
||||
for _, service := range services {
|
||||
if !*service.enable {
|
||||
continue
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go service.run(&wg)
|
||||
exitWaitGroup.Add(1)
|
||||
go service.run(&exitWaitGroup)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,12 +121,26 @@ func mapToHost(conn net.Conn) net.Conn {
|
||||
|
||||
var client net.Conn
|
||||
|
||||
if host, ok := strings.CutPrefix(host, "quic://"); ok {
|
||||
client = upstreamQuic(host)
|
||||
} else if host, ok := strings.CutPrefix(host, "kcp://"); ok {
|
||||
client = upstreamKcp(host)
|
||||
} else {
|
||||
client = upstreamTcp(host)
|
||||
ok, err = invokeFirstHookHandler(api.HookUpstream, Handler2[net.Conn, string, bool](conn, host), func(handler func(net.Conn, string) (net.Conn, error)) error {
|
||||
var err error
|
||||
client, err = handler(conn, host)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to invoke upstream hook")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !ok {
|
||||
if host, ok := strings.CutPrefix(host, "quic://"); ok {
|
||||
client = upstreamQuic(host)
|
||||
} else if host, ok := strings.CutPrefix(host, "kcp://"); ok {
|
||||
client = upstreamKcp(host)
|
||||
} else if host, ok := strings.CutPrefix(host, "haproxy://"); ok {
|
||||
client = haProxyUpstream(conn, host)
|
||||
} else {
|
||||
client = upstreamTcp(host)
|
||||
}
|
||||
}
|
||||
if client == nil {
|
||||
return nil
|
||||
|
||||
175
cmd/gateway/plugin.go
Normal file
175
cmd/gateway/plugin.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"plugin"
|
||||
"sync"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/tursom/mc-gateway/plugin/api"
|
||||
)
|
||||
|
||||
var (
|
||||
exitWaitGroup sync.WaitGroup
|
||||
|
||||
pluginLock sync.RWMutex
|
||||
plugins = make(map[string]api.Plugin)
|
||||
|
||||
hooks = make(map[string]map[string]any)
|
||||
)
|
||||
|
||||
type (
|
||||
Gateway struct {
|
||||
pluginId string
|
||||
}
|
||||
)
|
||||
|
||||
func loadPlugins() {
|
||||
pluginLock.Lock()
|
||||
defer pluginLock.Unlock()
|
||||
|
||||
for pluginKey, pluginConfig := range config.Plugin {
|
||||
if enable, ok := pluginConfig["enable"].(bool); ok && enable {
|
||||
pluginFile := pluginKey
|
||||
if file, ok := pluginConfig["file"].(string); ok {
|
||||
pluginFile = file
|
||||
}
|
||||
|
||||
if _, ok := plugins[pluginKey]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
gateway := &Gateway{
|
||||
pluginId: pluginKey,
|
||||
}
|
||||
|
||||
log.Info().Str("plugin", pluginKey).Msg("Loading plugin")
|
||||
p, err := plugin.Open(pluginFile + ".so")
|
||||
if err != nil {
|
||||
log.Err(err).Str("plugin", pluginKey).Msg("Failed to open plugin")
|
||||
continue
|
||||
}
|
||||
|
||||
pluginSymbol, err := p.Lookup("Plugin")
|
||||
if err != nil {
|
||||
log.Err(err).Str("plugin", pluginKey).Msg("Failed to lookup plugin")
|
||||
continue
|
||||
}
|
||||
pluginFactory, ok := pluginSymbol.(func() api.Plugin)
|
||||
if !ok {
|
||||
log.Err(err).Str("plugin", pluginKey).Msg("Invalid plugin factory signature")
|
||||
continue
|
||||
}
|
||||
pluginInstance := pluginFactory()
|
||||
cfgObj := pluginInstance.NewConfigObj()
|
||||
if err := loadPluginConfig(pluginConfig, cfgObj); err != nil {
|
||||
log.Err(err).Str("plugin", pluginKey).Msg("Failed to load plugin config")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := pluginInstance.ReloadConfig(cfgObj); err != nil {
|
||||
log.Err(err).Str("plugin", pluginKey).Msg("Failed to reload plugin config")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := pluginInstance.Init(gateway); err != nil {
|
||||
log.Err(err).Str("plugin", pluginKey).Msg("Failed to initialize plugin")
|
||||
continue
|
||||
}
|
||||
|
||||
plugins[pluginKey] = pluginInstance
|
||||
hooks[pluginKey] = make(map[string]any)
|
||||
log.Info().Str("plugin", pluginKey).Msg("Plugin loaded successfully")
|
||||
} else {
|
||||
if plugin, ok := plugins[pluginKey]; ok {
|
||||
if err := plugin.Destroy(); err != nil {
|
||||
log.Err(err).Str("plugin", pluginKey).Msg("Failed to destroy plugin")
|
||||
}
|
||||
log.Info().Str("plugin", pluginKey).Msg("Plugin disabled")
|
||||
}
|
||||
delete(plugins, pluginKey)
|
||||
delete(hooks, pluginKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HandleConn implements api.Gateway.
|
||||
func (g *Gateway) HandleConn(conn net.Conn) {
|
||||
go handleRequest(conn)
|
||||
}
|
||||
|
||||
// Hook implements api.Gateway.
|
||||
func (g *Gateway) Hook(hook string, handler any) error {
|
||||
pluginLock.Lock()
|
||||
defer pluginLock.Unlock()
|
||||
|
||||
hooks[g.pluginId][hook] = handler
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExitWaitGroup implements api.Gateway.
|
||||
func (g *Gateway) ExitWaitGroup() *sync.WaitGroup {
|
||||
return &exitWaitGroup
|
||||
}
|
||||
|
||||
// TestOp implements api.Gateway.
|
||||
func (g *Gateway) TestOp() {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func Handler1[T1, R any](t1 T1) func(func(T1) R) R {
|
||||
return func(acceptor func(T1) R) R {
|
||||
return acceptor(t1)
|
||||
}
|
||||
}
|
||||
|
||||
func Handler2[T1, T2, R any](t1 T1, t2 T2) func(func(T1, T2) R) R {
|
||||
return func(acceptor func(T1, T2) R) R {
|
||||
return acceptor(t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
func Handler1R2[T1, R1, R2 any](t1 T1) func(func(T1) (R1, R2)) (R1, R2) {
|
||||
return func(acceptor func(T1) (R1, R2)) (R1, R2) {
|
||||
return acceptor(t1)
|
||||
}
|
||||
}
|
||||
|
||||
func invokeFirstHookHandler[Acceptor, Handler any](
|
||||
hook api.HookType[Acceptor, Handler],
|
||||
acceptor func(Acceptor) bool,
|
||||
handelr func(Handler) error,
|
||||
) (bool, error) {
|
||||
pluginLock.RLock()
|
||||
defer pluginLock.RUnlock()
|
||||
|
||||
for _, handlers := range hooks {
|
||||
if handler, ok := handlers[hook.Key()].(api.HookHandler[Acceptor, Handler]); ok && acceptor(handler.Acceptor()) {
|
||||
if err := handelr(handler.Handler()); err != nil {
|
||||
return true, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func invokeAllHookHandler[Acceptor, Handler any](
|
||||
hook api.HookType[Acceptor, Handler],
|
||||
acceptor func(Acceptor) bool,
|
||||
handelr func(Handler) error,
|
||||
) error {
|
||||
pluginLock.RLock()
|
||||
defer pluginLock.RUnlock()
|
||||
|
||||
for _, handlers := range hooks {
|
||||
if handler, ok := handlers[hook.Key()].(api.HookHandler[Acceptor, Handler]); ok && acceptor(handler.Acceptor()) {
|
||||
if err := handelr(handler.Handler()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
20
go.mod
20
go.mod
@@ -1,11 +1,15 @@
|
||||
module github.com/tursom/mc-gateway
|
||||
|
||||
go 1.23.1
|
||||
go 1.24
|
||||
|
||||
toolchain go1.24.4
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.5.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/pires/go-proxyproto v0.8.1
|
||||
github.com/quic-go/quic-go v0.52.0
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible
|
||||
@@ -13,6 +17,7 @@ require (
|
||||
|
||||
require (
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/klauspost/reedsolomon v1.12.4 // indirect
|
||||
@@ -20,15 +25,16 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/stretchr/testify v1.10.0 // indirect
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.38.0 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
)
|
||||
|
||||
40
go.sum
40
go.sum
@@ -39,8 +39,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
@@ -55,10 +55,14 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
@@ -71,8 +75,8 @@ github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
|
||||
@@ -88,28 +92,28 @@ go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -119,19 +123,19 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
||||
69
plugin/api/api.go
Normal file
69
plugin/api/api.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
Plugin interface {
|
||||
// Init 初始化插件
|
||||
// 返回错误表示初始化失败,插件将不会被启用
|
||||
Init(gateway Gateway) error
|
||||
// Destroy 销毁插件
|
||||
// 返回错误表示销毁失败,通常是资源释放失败
|
||||
// 但插件仍然会被标记为已销毁,后续调用 Init() 会重新初始化
|
||||
Destroy() error
|
||||
|
||||
// NewConfigObj 创建插件配置对象
|
||||
NewConfigObj() any
|
||||
// ReloadConfig 重新加载插件配置
|
||||
// config 是 NewConfigObj() 返回的对象
|
||||
// 如果返回错误,则表示配置加载失败,插件将不会被启用
|
||||
ReloadConfig(config any) error
|
||||
}
|
||||
|
||||
Gateway interface {
|
||||
HandleConn(conn net.Conn)
|
||||
|
||||
ExitWaitGroup() *sync.WaitGroup
|
||||
|
||||
Hook(hook string, handler any) error
|
||||
}
|
||||
|
||||
AbstractPlugin struct{}
|
||||
)
|
||||
|
||||
// Init 初始化插件
|
||||
// 返回错误表示初始化失败,插件将不会被启用
|
||||
func (p AbstractPlugin) Init(gateway Gateway) error {
|
||||
return nil // 默认实现,返回 nil 表示初始化成功
|
||||
}
|
||||
|
||||
// Destroy 销毁插件
|
||||
// 返回错误表示销毁失败,通常是资源释放失败
|
||||
// 但插件仍然会被标记为已销毁,后续调用 Init() 会重新初始化
|
||||
func (p AbstractPlugin) Destroy() error {
|
||||
return nil // 默认实现,返回 nil 表示销毁成功
|
||||
}
|
||||
|
||||
// NewConfigObj 创建插件配置对象
|
||||
func (p AbstractPlugin) NewConfigObj() any {
|
||||
return struct{}{} // 默认实现,返回一个空结构体
|
||||
}
|
||||
|
||||
// ReloadConfig 重新加载插件配置
|
||||
// config 是 NewConfigObj() 返回的对象
|
||||
// 如果返回错误,则表示配置加载失败,插件将不会被启用
|
||||
func (p AbstractPlugin) ReloadConfig(config any) error {
|
||||
return nil // 默认实现,返回 nil 表示配置加载成功
|
||||
}
|
||||
|
||||
func RegisterHookHandler[Accept, Handle any](
|
||||
gateway Gateway,
|
||||
hook HookType[Accept, Handle],
|
||||
accept Accept,
|
||||
handler Handle,
|
||||
) error {
|
||||
return gateway.Hook(hook.key, HookHandler[Accept, Handle]{accept, handler})
|
||||
}
|
||||
47
plugin/api/hook.go
Normal file
47
plugin/api/hook.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
UnsupportedHookType = errors.New("unsupported hook type")
|
||||
)
|
||||
|
||||
type (
|
||||
HookType[Accept, Handler any] struct {
|
||||
key string
|
||||
}
|
||||
|
||||
HookHandler[Accept, Handler any] struct {
|
||||
acceptor Accept
|
||||
handler Handler
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
HookUpstream = HookType[
|
||||
func(source net.Conn, host string) bool,
|
||||
func(source net.Conn, host string) (net.Conn, error),
|
||||
]{
|
||||
key: "upstream",
|
||||
}
|
||||
)
|
||||
|
||||
func (h HookType[Accept, Handler]) Key() string {
|
||||
return h.key
|
||||
}
|
||||
|
||||
func (h HookType[Accept, Handler]) AsAny() HookType[any, any] {
|
||||
return *(*HookType[any, any])(unsafe.Pointer(&h))
|
||||
}
|
||||
|
||||
func (h HookHandler[Acceptor, Handler]) Acceptor() Acceptor {
|
||||
return h.acceptor
|
||||
}
|
||||
|
||||
func (h HookHandler[Acceptor, Handler]) Handler() Handler {
|
||||
return h.handler
|
||||
}
|
||||
Reference in New Issue
Block a user