Files
x/config/parsing/recorder/parse.go
T
ginuerzh 618cc7fd9c fix(plugin): CloseIdleConnections silent no-op when tokenTransport wraps HTTP transport
tokenTransport now delegates CloseIdleConnections to the underlying
*http.Transport so http.Client.CloseIdleConnections() works through
the wrapper. Three plugin Close() methods updated to unwrap via
HTTPClientTransport before calling CloseIdleConnections.

RoundTrip now short-circuits when caller already set Authorization,
avoiding an unnecessary req.Clone allocation on the pass-through path.
2026-05-27 20:37:14 +08:00

140 lines
4.1 KiB
Go

package recorder
import (
"crypto/tls"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/go-gost/core/logger"
"github.com/go-gost/core/recorder"
"github.com/go-gost/x/config"
"github.com/go-gost/x/internal/plugin"
xrecorder "github.com/go-gost/x/recorder"
recorder_plugin "github.com/go-gost/x/recorder/plugin"
"gopkg.in/natefinch/lumberjack.v2"
)
type discardCloser struct{}
func (discardCloser) Write(p []byte) (n int, err error) { return len(p), nil }
func (discardCloser) Close() error { return nil }
// ParseRecorder converts a RecorderConfig into a recorder.Recorder. It
// supports plugin backends (HTTP or gRPC), file output (with optional
// rotation), TCP syslog-style delivery, HTTP POST delivery, and Redis storage
// (set, list, or sorted set). Returns nil when cfg is nil or no backend is
// configured.
func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) {
if cfg == nil {
return nil
}
if cfg.Plugin != nil {
var tlsCfg *tls.Config
if cfg.Plugin.TLS != nil {
tlsCfg = &tls.Config{
ServerName: cfg.Plugin.TLS.ServerName,
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
}
}
switch strings.ToLower(cfg.Plugin.Type) {
case "http":
return recorder_plugin.NewHTTPPlugin(
cfg.Name, cfg.Plugin.Addr,
plugin.TokenOption(cfg.Plugin.Token),
plugin.TLSConfigOption(tlsCfg),
plugin.TimeoutOption(cfg.Plugin.Timeout),
)
default:
return recorder_plugin.NewGRPCPlugin(
cfg.Name, cfg.Plugin.Addr,
plugin.TokenOption(cfg.Plugin.Token),
plugin.TLSConfigOption(tlsCfg),
)
}
}
if cfg.File != nil && cfg.File.Path != "" {
var out io.WriteCloser = discardCloser{}
if cfg.File.Rotation != nil {
out = &lumberjack.Logger{
Filename: cfg.File.Path,
MaxSize: cfg.File.Rotation.MaxSize,
MaxAge: cfg.File.Rotation.MaxAge,
MaxBackups: cfg.File.Rotation.MaxBackups,
LocalTime: cfg.File.Rotation.LocalTime,
Compress: cfg.File.Rotation.Compress,
}
} else {
os.MkdirAll(filepath.Dir(cfg.File.Path), 0755)
f, err := os.OpenFile(cfg.File.Path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
logger.Default().Warn(err)
} else {
out = f
}
}
return xrecorder.FileRecorder(out,
xrecorder.RecorderFileRecorderOption(cfg.Name),
xrecorder.SepFileRecorderOption(cfg.File.Sep),
)
}
if cfg.TCP != nil && cfg.TCP.Addr != "" {
return xrecorder.TCPRecorder(cfg.TCP.Addr,
xrecorder.RecorderTCPRecorderOption(cfg.Name),
xrecorder.TimeoutTCPRecorderOption(cfg.TCP.Timeout),
)
}
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
h := http.Header{}
for k, v := range cfg.HTTP.Header {
h.Add(k, v)
}
return xrecorder.HTTPRecorder(cfg.HTTP.URL,
xrecorder.RecorderHTTPRecorderOption(cfg.Name),
xrecorder.TimeoutHTTPRecorderOption(cfg.HTTP.Timeout),
xrecorder.HeaderHTTPRecorderOption(h),
)
}
if cfg.Redis != nil &&
cfg.Redis.Addr != "" &&
cfg.Redis.Key != "" {
switch cfg.Redis.Type {
case "list": // redis list
return xrecorder.RedisListRecorder(cfg.Redis.Addr,
xrecorder.RecorderRedisRecorderOption(cfg.Name),
xrecorder.DBRedisRecorderOption(cfg.Redis.DB),
xrecorder.KeyRedisRecorderOption(cfg.Redis.Key),
xrecorder.UsernameRedisRecorderOption(cfg.Redis.Username),
xrecorder.PasswordRedisRecorderOption(cfg.Redis.Password),
)
case "sset": // sorted set
return xrecorder.RedisSortedSetRecorder(cfg.Redis.Addr,
xrecorder.RecorderRedisRecorderOption(cfg.Name),
xrecorder.DBRedisRecorderOption(cfg.Redis.DB),
xrecorder.KeyRedisRecorderOption(cfg.Redis.Key),
xrecorder.UsernameRedisRecorderOption(cfg.Redis.Username),
xrecorder.PasswordRedisRecorderOption(cfg.Redis.Password),
)
default: // redis set
return xrecorder.RedisSetRecorder(cfg.Redis.Addr,
xrecorder.RecorderRedisRecorderOption(cfg.Name),
xrecorder.DBRedisRecorderOption(cfg.Redis.DB),
xrecorder.KeyRedisRecorderOption(cfg.Redis.Key),
xrecorder.UsernameRedisRecorderOption(cfg.Redis.Username),
xrecorder.PasswordRedisRecorderOption(cfg.Redis.Password),
)
}
}
return
}