mirror of
https://github.com/Gouryella/drip.git
synced 2026-02-23 21:00:44 +00:00
- Removed the manual performance optimization configuration in main.go and replaced it with a new tuning module. - Add patterned GC tuning in server.go and tunnel_runner.go - Updated yamux configuration to a unified optimized configuration to improve throughput. - Implement connection pool preheating function to eliminate cold start delay. - Optimize session selection using a min-heap, reducing the time complexity from O(n) to O(log n). - Add a bufio.Reader pool and a buffer pool to reduce memory allocation. - Implement a fragmented lock manager to improve performance under high concurrency. - Adjust heartbeat and timeout configurations to suit high-throughput scenarios BREAKING CHANGE: Manual GC tuning configuration has been removed; automatic tuning mode is now used.
179 lines
5.4 KiB
Go
179 lines
5.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
_ "net/http/pprof"
|
|
"os"
|
|
"os/signal"
|
|
"strconv"
|
|
"syscall"
|
|
|
|
"drip/internal/server/proxy"
|
|
"drip/internal/server/tcp"
|
|
"drip/internal/server/tunnel"
|
|
"drip/internal/shared/constants"
|
|
"drip/internal/shared/tuning"
|
|
"drip/internal/shared/utils"
|
|
"drip/pkg/config"
|
|
"github.com/spf13/cobra"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
var (
|
|
serverPort int
|
|
serverPublicPort int
|
|
serverDomain string
|
|
serverAuthToken string
|
|
serverDebug bool
|
|
serverTCPPortMin int
|
|
serverTCPPortMax int
|
|
serverTLSCert string
|
|
serverTLSKey string
|
|
serverPprofPort int
|
|
)
|
|
|
|
var serverCmd = &cobra.Command{
|
|
Use: "server",
|
|
Short: "Start Drip server",
|
|
Long: `Start the Drip tunnel server to accept client connections`,
|
|
RunE: runServer,
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(serverCmd)
|
|
|
|
// Command line flags with environment variable defaults
|
|
serverCmd.Flags().IntVarP(&serverPort, "port", "p", getEnvInt("DRIP_PORT", 8443), "Server port (env: DRIP_PORT)")
|
|
serverCmd.Flags().IntVar(&serverPublicPort, "public-port", getEnvInt("DRIP_PUBLIC_PORT", 0), "Public port to display in URLs (env: DRIP_PUBLIC_PORT)")
|
|
serverCmd.Flags().StringVarP(&serverDomain, "domain", "d", getEnvString("DRIP_DOMAIN", constants.DefaultDomain), "Server domain (env: DRIP_DOMAIN)")
|
|
serverCmd.Flags().StringVarP(&serverAuthToken, "token", "t", getEnvString("DRIP_TOKEN", ""), "Authentication token (env: DRIP_TOKEN)")
|
|
serverCmd.Flags().BoolVar(&serverDebug, "debug", false, "Enable debug logging")
|
|
serverCmd.Flags().IntVar(&serverTCPPortMin, "tcp-port-min", getEnvInt("DRIP_TCP_PORT_MIN", constants.DefaultTCPPortMin), "Minimum TCP tunnel port (env: DRIP_TCP_PORT_MIN)")
|
|
serverCmd.Flags().IntVar(&serverTCPPortMax, "tcp-port-max", getEnvInt("DRIP_TCP_PORT_MAX", constants.DefaultTCPPortMax), "Maximum TCP tunnel port (env: DRIP_TCP_PORT_MAX)")
|
|
|
|
// TLS options
|
|
serverCmd.Flags().StringVar(&serverTLSCert, "tls-cert", getEnvString("DRIP_TLS_CERT", ""), "Path to TLS certificate file (env: DRIP_TLS_CERT)")
|
|
serverCmd.Flags().StringVar(&serverTLSKey, "tls-key", getEnvString("DRIP_TLS_KEY", ""), "Path to TLS private key file (env: DRIP_TLS_KEY)")
|
|
|
|
// Performance profiling
|
|
serverCmd.Flags().IntVar(&serverPprofPort, "pprof", getEnvInt("DRIP_PPROF_PORT", 0), "Enable pprof on specified port (env: DRIP_PPROF_PORT)")
|
|
}
|
|
|
|
func runServer(_ *cobra.Command, _ []string) error {
|
|
// Apply server-mode GC tuning (high throughput, more memory)
|
|
tuning.ApplyMode(tuning.ModeServer)
|
|
|
|
if serverTLSCert == "" {
|
|
return fmt.Errorf("TLS certificate path is required (use --tls-cert flag or DRIP_TLS_CERT environment variable)")
|
|
}
|
|
if serverTLSKey == "" {
|
|
return fmt.Errorf("TLS private key path is required (use --tls-key flag or DRIP_TLS_KEY environment variable)")
|
|
}
|
|
|
|
if err := utils.InitServerLogger(serverDebug); err != nil {
|
|
return fmt.Errorf("failed to initialize logger: %w", err)
|
|
}
|
|
defer utils.Sync()
|
|
|
|
logger := utils.GetLogger()
|
|
|
|
logger.Info("Starting Drip Server",
|
|
zap.String("version", Version),
|
|
zap.String("commit", GitCommit),
|
|
)
|
|
|
|
if serverPprofPort > 0 {
|
|
go func() {
|
|
pprofAddr := fmt.Sprintf("localhost:%d", serverPprofPort)
|
|
logger.Info("Starting pprof server", zap.String("address", pprofAddr))
|
|
if err := http.ListenAndServe(pprofAddr, nil); err != nil {
|
|
logger.Error("pprof server failed", zap.Error(err))
|
|
}
|
|
}()
|
|
}
|
|
|
|
displayPort := serverPublicPort
|
|
if displayPort == 0 {
|
|
displayPort = serverPort
|
|
}
|
|
|
|
serverConfig := &config.ServerConfig{
|
|
Port: serverPort,
|
|
PublicPort: displayPort,
|
|
Domain: serverDomain,
|
|
TCPPortMin: serverTCPPortMin,
|
|
TCPPortMax: serverTCPPortMax,
|
|
TLSEnabled: true,
|
|
TLSCertFile: serverTLSCert,
|
|
TLSKeyFile: serverTLSKey,
|
|
AuthToken: serverAuthToken,
|
|
Debug: serverDebug,
|
|
}
|
|
|
|
tlsConfig, err := serverConfig.LoadTLSConfig()
|
|
if err != nil {
|
|
logger.Fatal("Failed to load TLS configuration", zap.Error(err))
|
|
}
|
|
|
|
logger.Info("TLS 1.3 configuration loaded",
|
|
zap.String("cert", serverTLSCert),
|
|
zap.String("key", serverTLSKey),
|
|
)
|
|
|
|
tunnelManager := tunnel.NewManager(logger)
|
|
|
|
portAllocator, err := tcp.NewPortAllocator(serverTCPPortMin, serverTCPPortMax)
|
|
if err != nil {
|
|
logger.Fatal("Invalid TCP port range", zap.Error(err))
|
|
}
|
|
|
|
listenAddr := fmt.Sprintf("0.0.0.0:%d", serverPort)
|
|
|
|
httpHandler := proxy.NewHandler(tunnelManager, logger, serverDomain, serverAuthToken)
|
|
|
|
listener := tcp.NewListener(listenAddr, tlsConfig, serverAuthToken, tunnelManager, logger, portAllocator, serverDomain, displayPort, httpHandler)
|
|
|
|
if err := listener.Start(); err != nil {
|
|
logger.Fatal("Failed to start TCP listener", zap.Error(err))
|
|
}
|
|
|
|
logger.Info("Drip Server started",
|
|
zap.String("address", listenAddr),
|
|
zap.String("domain", serverDomain),
|
|
zap.String("protocol", "TCP over TLS 1.3"),
|
|
)
|
|
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
<-quit
|
|
|
|
logger.Info("Shutting down server...")
|
|
|
|
if err := listener.Stop(); err != nil {
|
|
logger.Error("Error stopping listener", zap.Error(err))
|
|
}
|
|
|
|
logger.Info("Server stopped")
|
|
return nil
|
|
}
|
|
|
|
// getEnvInt returns the environment variable value as int, or defaultVal if not set
|
|
func getEnvInt(key string, defaultVal int) int {
|
|
if val := os.Getenv(key); val != "" {
|
|
if i, err := strconv.Atoi(val); err == nil {
|
|
return i
|
|
}
|
|
}
|
|
return defaultVal
|
|
}
|
|
|
|
// getEnvString returns the environment variable value, or defaultVal if not set
|
|
func getEnvString(key string, defaultVal string) string {
|
|
if val := os.Getenv(key); val != "" {
|
|
return val
|
|
}
|
|
return defaultVal
|
|
}
|