diff --git a/README.md b/README.md index 60d73a1..086b4e7 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # Moonshark +```bash +git submodule update --init --recursive +git submodule update --remote --recursive +``` diff --git a/core/http/server.go b/core/http/server.go index b06a687..48d9f88 100644 --- a/core/http/server.go +++ b/core/http/server.go @@ -3,6 +3,7 @@ package http import ( "context" "encoding/json" + "net" "net/http" "time" @@ -20,16 +21,40 @@ type Server struct { httpServer *http.Server } -// New creates a new HTTP server +// New creates a new HTTP server with optimized connection settings func New(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter, pool *workers.Pool, log *logger.Logger) *Server { server := &Server{ luaRouter: luaRouter, staticRouter: staticRouter, workerPool: pool, logger: log, - httpServer: &http.Server{}, + httpServer: &http.Server{ + // Connection timeouts + ReadTimeout: 30 * time.Second, + WriteTimeout: 30 * time.Second, + IdleTimeout: 120 * time.Second, + ReadHeaderTimeout: 10 * time.Second, + + // Improved connection handling + MaxHeaderBytes: 1 << 16, // 64KB + }, } server.httpServer.Handler = server + + // Set TCP keep-alive settings for the underlying TCP connections + server.httpServer.ConnState = func(conn net.Conn, state http.ConnState) { + if state == http.StateNew { + if tcpConn, ok := conn.(*net.TCPConn); ok { + // Enable TCP keep-alive + tcpConn.SetKeepAlive(true) + tcpConn.SetKeepAlivePeriod(30 * time.Second) + + // Set TCP_NODELAY (disable Nagle's algorithm) + tcpConn.SetNoDelay(true) + } + } + } + return server } diff --git a/core/logger/logger.go b/core/logger/logger.go index 0e75088..cb6fd0c 100644 --- a/core/logger/logger.go +++ b/core/logger/logger.go @@ -34,56 +34,39 @@ var levelProps = map[int]struct { tag string color string }{ - LevelDebug: {" DBG", colorCyan}, - LevelInfo: {"INFO", colorBlue}, - LevelWarning: {"WARN", colorYellow}, - LevelError: {" ERR", colorRed}, - LevelFatal: {"FATL", colorPurple}, + LevelDebug: {"DBG", colorCyan}, + LevelInfo: {"INF", colorBlue}, + LevelWarning: {"WRN", colorYellow}, + LevelError: {"ERR", colorRed}, + LevelFatal: {"FTL", colorPurple}, } // Time format for log messages const timeFormat = "15:04:05" -// logMessage represents a message to be logged -type logMessage struct { - level int - message string - rawMode bool // Indicates if raw formatting should be used -} - // Logger handles logging operations type Logger struct { writer io.Writer - messages chan logMessage - wg sync.WaitGroup level int useColors bool - done chan struct{} timeFormat string mu sync.Mutex // Mutex for thread-safe writing } // New creates a new logger func New(minLevel int, useColors bool) *Logger { - l := &Logger{ + return &Logger{ writer: os.Stdout, - messages: make(chan logMessage, 100), // Buffer 100 messages level: minLevel, useColors: useColors, - done: make(chan struct{}), timeFormat: timeFormat, } - - l.wg.Add(1) - go l.processLogs() - return l } // SetOutput changes the output destination func (l *Logger) SetOutput(w io.Writer) { l.mu.Lock() defer l.mu.Unlock() - l.writer = w } @@ -112,67 +95,45 @@ func (l *Logger) DisableColors() { l.useColors = false } -// processLogs processes incoming log messages -func (l *Logger) processLogs() { - defer l.wg.Done() - - for { - select { - case msg := <-l.messages: - if msg.level >= l.level { - l.writeMessage(msg) - } - case <-l.done: - // Process remaining messages - for { - select { - case msg := <-l.messages: - if msg.level >= l.level { - l.writeMessage(msg) - } - default: - return - } - } - } - } -} - -// writeMessage writes a formatted log message -func (l *Logger) writeMessage(msg logMessage) { +// writeMessage writes a formatted log message directly to the writer +func (l *Logger) writeMessage(level int, message string, rawMode bool) { var logLine string - if msg.rawMode { + if rawMode { // Raw mode - message is already formatted, just append newline - logLine = msg.message + "\n" + logLine = message + "\n" } else { // Standard format with timestamp, level tag, and message now := time.Now().Format(l.timeFormat) - props := levelProps[msg.level] + props := levelProps[level] if l.useColors { logLine = fmt.Sprintf("%s %s[%s]%s %s\n", - now, props.color, props.tag, colorReset, msg.message) + now, props.color, props.tag, colorReset, message) } else { logLine = fmt.Sprintf("%s [%s] %s\n", - now, props.tag, msg.message) + now, props.tag, message) } } - // Synchronize writing - l.mu.Lock() - _, _ = fmt.Fprint(l.writer, logLine) - l.mu.Unlock() + // Asynchronously write the log message + go func(w io.Writer, data string) { + l.mu.Lock() + _, _ = fmt.Fprint(w, data) + l.mu.Unlock() + }(l.writer, logLine) - // Auto-flush for fatal errors - if msg.level == LevelFatal { + // For fatal errors, ensure we sync immediately in the current goroutine + if level == LevelFatal { + l.mu.Lock() if f, ok := l.writer.(*os.File); ok { _ = f.Sync() } + l.mu.Unlock() } } -// log sends a message to the logger goroutine +// log handles the core logging logic with level filtering func (l *Logger) log(level int, format string, args ...any) { if level < l.level { return @@ -185,18 +146,10 @@ func (l *Logger) log(level int, format string, args ...any) { message = format } - // Don't block if channel is full - select { - case l.messages <- logMessage{level: level, message: message, rawMode: false}: - // Message sent - default: - // Channel full, write directly - l.writeMessage(logMessage{level: level, message: message, rawMode: false}) - } + l.writeMessage(level, message, false) // Exit on fatal errors if level == LevelFatal { - l.Close() os.Exit(1) } } @@ -218,18 +171,10 @@ func (l *Logger) LogRaw(format string, args ...any) { // Don't apply colors if disabled if !l.useColors { // Strip ANSI color codes if colors are disabled - // Simple approach to strip common ANSI codes message = removeAnsiColors(message) } - // Don't block if channel is full - select { - case l.messages <- logMessage{level: LevelInfo, message: message, rawMode: true}: - // Message sent - default: - // Channel full, write directly - l.writeMessage(logMessage{level: LevelInfo, message: message, rawMode: true}) - } + l.writeMessage(LevelInfo, message, true) } // Simple helper to remove ANSI color codes @@ -282,13 +227,6 @@ func (l *Logger) Fatal(format string, args ...any) { // No need for os.Exit here as it's handled in log() } -// Close shuts down the logger goroutine -func (l *Logger) Close() { - close(l.done) - l.wg.Wait() - close(l.messages) -} - // Default global logger var defaultLogger = New(LevelInfo, true) @@ -331,8 +269,3 @@ func SetLevel(level int) { func SetOutput(w io.Writer) { defaultLogger.SetOutput(w) } - -// Close shuts down the default logger -func Close() { - defaultLogger.Close() -} diff --git a/core/logger/logger_test.go b/core/logger/logger_test.go index 72db4f9..4b944f3 100644 --- a/core/logger/logger_test.go +++ b/core/logger/logger_test.go @@ -64,8 +64,6 @@ func TestLoggerLevels(t *testing.T) { if !strings.Contains(buf.String(), "[ERR]") { t.Errorf("Error message not logged after level change, got: %q", buf.String()) } - - logger.Close() } func TestLoggerConcurrency(t *testing.T) { @@ -96,8 +94,6 @@ func TestLoggerConcurrency(t *testing.T) { break } } - - logger.Close() } func TestLoggerColors(t *testing.T) { @@ -124,8 +120,6 @@ func TestLoggerColors(t *testing.T) { if strings.Contains(content, "\033[") { t.Errorf("Color codes present when disabled, got: %q", content) } - - logger.Close() } func TestDefaultLogger(t *testing.T) { @@ -139,8 +133,6 @@ func TestDefaultLogger(t *testing.T) { if !strings.Contains(content, "[INF]") { t.Errorf("Default logger not working, got: %q", content) } - - Close() } func BenchmarkLogger(b *testing.B) { @@ -152,7 +144,6 @@ func BenchmarkLogger(b *testing.B) { for i := 0; i < b.N; i++ { logger.Info("Benchmark message %d", i) } - logger.Close() } func BenchmarkLoggerParallel(b *testing.B) { @@ -168,5 +159,4 @@ func BenchmarkLoggerParallel(b *testing.B) { i++ } }) - logger.Close() } diff --git a/luajit b/luajit index 98ca857..13686b3 160000 --- a/luajit +++ b/luajit @@ -1 +1 @@ -Subproject commit 98ca857d73956bf69a07641710b678c11681319f +Subproject commit 13686b3e66b388a31d459fe95d1aa3bfa05aeb27 diff --git a/moonshark.go b/moonshark.go index c14ee51..4969ae8 100644 --- a/moonshark.go +++ b/moonshark.go @@ -47,7 +47,6 @@ func initRouters(routesDir, staticDir string, log *logger.Logger) (*routers.LuaR func main() { // Initialize logger log := logger.New(logger.LevelDebug, true) - defer log.Close() log.Info("Starting Moonshark server")