refactor(server): enhance server start options and support for proxy protocol

This commit is contained in:
yusing
2025-09-18 17:34:02 +08:00
parent 3aba5a1911
commit 83a69322fa
6 changed files with 80 additions and 16 deletions

View File

@@ -71,6 +71,7 @@ require (
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pires/go-proxyproto v0.8.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect

View File

@@ -128,6 +128,8 @@ github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

View File

@@ -39,5 +39,5 @@ func StartAgentServer(parent task.Parent, opt Options) {
TLSConfig: tlsConfig,
}
server.Start(parent, agentServer, nil, &log.Logger)
server.Start(parent, agentServer, server.WithLogger(&log.Logger))
}

1
go.mod
View File

@@ -213,6 +213,7 @@ require (
require (
github.com/gin-gonic/gin v1.10.1
github.com/pires/go-proxyproto v0.8.1
github.com/yusing/ds v0.1.0
)

2
go.sum
View File

@@ -1424,6 +1424,8 @@ github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
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/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=

View File

@@ -9,6 +9,7 @@ import (
"net/http"
"time"
"github.com/pires/go-proxyproto"
"github.com/quic-go/quic-go/http3"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
@@ -28,6 +29,7 @@ type Server struct {
https *http.Server
startTime time.Time
acl *acl.Config
proxyProto bool
l zerolog.Logger
}
@@ -39,6 +41,8 @@ type Options struct {
CertProvider CertProvider
Handler http.Handler
ACL *acl.Config
SupportProxyProtocol bool
}
type httpServer interface {
@@ -86,6 +90,7 @@ func NewServer(opt Options) (s *Server) {
https: httpsSer,
l: logger,
acl: opt.ACL,
proxyProto: opt.SupportProxyProtocol,
}
}
@@ -105,7 +110,8 @@ func (s *Server) Start(parent task.Parent) {
Handler: s.https.Handler,
TLSConfig: http3.ConfigureTLSConfig(s.https.TLSConfig),
}
Start(subtask, h3, s.acl, &s.l)
// TODO: support proxy protocol for HTTP/3
Start(subtask, h3, WithACL(s.acl), WithLogger(&s.l))
if s.http != nil {
s.http.Handler = advertiseHTTP3(s.http.Handler, h3)
}
@@ -113,16 +119,68 @@ func (s *Server) Start(parent task.Parent) {
s.https.Handler = advertiseHTTP3(s.https.Handler, h3)
}
Start(subtask, s.http, s.acl, &s.l)
Start(subtask, s.https, s.acl, &s.l)
Start(subtask, s.http, WithProxyProtocolSupport(s.proxyProto), WithACL(s.acl), WithLogger(&s.l))
Start(subtask, s.https, WithProxyProtocolSupport(s.proxyProto), WithACL(s.acl), WithLogger(&s.l))
}
func Start[Server httpServer](parent task.Parent, srv Server, acl *acl.Config, logger *zerolog.Logger) (port int) {
type ServerStartOptions struct {
tcpWrappers []func(l net.Listener) net.Listener
udpWrappers []func(l net.PacketConn) net.PacketConn
logger *zerolog.Logger
}
type ServerStartOption func(opts *ServerStartOptions)
func WithTCPWrappers(wrappers ...func(l net.Listener) net.Listener) ServerStartOption {
return func(opts *ServerStartOptions) {
opts.tcpWrappers = wrappers
}
}
func WithUDPWrappers(wrappers ...func(l net.PacketConn) net.PacketConn) ServerStartOption {
return func(opts *ServerStartOptions) {
opts.udpWrappers = wrappers
}
}
func WithLogger(logger *zerolog.Logger) ServerStartOption {
return func(opts *ServerStartOptions) {
opts.logger = logger
}
}
func WithACL(acl *acl.Config) ServerStartOption {
return func(opts *ServerStartOptions) {
if acl == nil {
return
}
opts.tcpWrappers = append(opts.tcpWrappers, acl.WrapTCP)
opts.udpWrappers = append(opts.udpWrappers, acl.WrapUDP)
}
}
func WithProxyProtocolSupport(value bool) ServerStartOption {
// TODO: HTTP/3 (UDP) support
return func(opts *ServerStartOptions) {
if value {
opts.tcpWrappers = append(opts.tcpWrappers, func(l net.Listener) net.Listener {
return &proxyproto.Listener{Listener: l}
})
}
}
}
func Start[Server httpServer](parent task.Parent, srv Server, optFns ...ServerStartOption) (port int) {
if srv == nil {
return
}
setDebugLogger(srv, logger)
var opts ServerStartOptions
for _, optFn := range optFns {
optFn(&opts)
}
setDebugLogger(srv, opts.logger)
proto := proto(srv)
task := parent.Subtask(proto, true)
@@ -137,40 +195,40 @@ func Start[Server httpServer](parent task.Parent, srv Server, acl *acl.Config, l
}
l, err := lc.Listen(task.Context(), "tcp", srv.Addr)
if err != nil {
HandleError(logger, err, "failed to listen on port")
HandleError(opts.logger, err, "failed to listen on port")
return
}
port = l.Addr().(*net.TCPAddr).Port
if srv.TLSConfig != nil {
l = tls.NewListener(l, srv.TLSConfig)
}
if acl != nil {
l = acl.WrapTCP(l)
for _, wrapper := range opts.tcpWrappers {
l = wrapper(l)
}
serveFunc = getServeFunc(l, srv.Serve)
task.OnCancel("stop", func() {
stop(srv, l, logger)
stop(srv, l, opts.logger)
})
case *http3.Server:
l, err := lc.ListenPacket(task.Context(), "udp", srv.Addr)
if err != nil {
HandleError(logger, err, "failed to listen on port")
HandleError(opts.logger, err, "failed to listen on port")
return
}
port = l.LocalAddr().(*net.UDPAddr).Port
if acl != nil {
l = acl.WrapUDP(l)
for _, wrapper := range opts.udpWrappers {
l = wrapper(l)
}
serveFunc = getServeFunc(l, srv.Serve)
task.OnCancel("stop", func() {
stop(srv, l, logger)
stop(srv, l, opts.logger)
})
}
logStarted(srv, logger)
logStarted(srv, opts.logger)
go func() {
err := convertError(serveFunc())
if err != nil {
HandleError(logger, err, "failed to serve "+proto+" server")
HandleError(opts.logger, err, "failed to serve "+proto+" server")
}
task.Finish(err)
}()