From 522a5770edd371b15ad60ccd5aa77d5cab5b3f0c Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Sat, 22 Mar 2025 14:16:45 -0500 Subject: [PATCH] optional http logging, updated module watcher --- core/http/server.go | 28 ++++++++++-------- core/runner/require.go | 33 ++++++++++----------- core/watchers/modulewatcher.go | 26 ++++++++-------- core/watchers/watcher.go | 54 +++++++++++++--------------------- moonshark.go | 9 +++++- 5 files changed, 74 insertions(+), 76 deletions(-) diff --git a/core/http/server.go b/core/http/server.go index a89cfe5..2f43919 100644 --- a/core/http/server.go +++ b/core/http/server.go @@ -14,21 +14,23 @@ import ( // Server handles HTTP requests using Lua and static file routers type Server struct { - luaRouter *routers.LuaRouter - staticRouter *routers.StaticRouter - luaRunner *runner.LuaRunner - logger *logger.Logger - httpServer *http.Server + luaRouter *routers.LuaRouter + staticRouter *routers.StaticRouter + luaRunner *runner.LuaRunner + logger *logger.Logger + httpServer *http.Server + loggingEnabled bool } // New creates a new HTTP server with optimized connection settings -func New(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter, runner *runner.LuaRunner, log *logger.Logger) *Server { +func New(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter, runner *runner.LuaRunner, log *logger.Logger, loggingEnabled bool) *Server { server := &Server{ - luaRouter: luaRouter, - staticRouter: staticRouter, - luaRunner: runner, - logger: log, - httpServer: &http.Server{}, + luaRouter: luaRouter, + staticRouter: staticRouter, + luaRunner: runner, + logger: log, + httpServer: &http.Server{}, + loggingEnabled: loggingEnabled, } server.httpServer.Handler = server @@ -74,7 +76,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { statusCode := wrappedWriter.StatusCode() // Log the request with our custom format - LogRequest(s.logger, statusCode, r, duration) + if s.loggingEnabled { + LogRequest(s.logger, statusCode, r, duration) + } } // handleRequest processes the actual request diff --git a/core/runner/require.go b/core/runner/require.go index 041873d..821e2fe 100644 --- a/core/runner/require.go +++ b/core/runner/require.go @@ -212,21 +212,8 @@ func (c *RequireCache) RefreshAll() int { return 0 } - // Collect paths to check - var paths []string - c.modules.Range(func(key, _ any) bool { - if path, ok := key.(string); ok { - paths = append(paths, path) - } - return true - }) - - // Check each path - for _, path := range paths { - if c.RefreshModule(path) { - refreshed++ - } - } + // For maximum performance, just clear everything + c.Clear() // Reset the needsRefresh flag c.needsRefresh.Store(false) @@ -267,6 +254,13 @@ func findAndCompileModule( } } + // If the cache needs refresh, handle it immediately + if cache.needsRefresh.Load() { + cache.Clear() // Complete reset for max performance + cache.needsRefresh.Store(false) + cache.lastRefresh = time.Now() + } + // Try each path for _, path := range paths { // Clean the path to handle .. and such (security) @@ -295,7 +289,7 @@ func findAndCompileModule( return value.([]byte), nil } - // Only do refresh check if marked as needed (by watcher) + // Check file modification time if cache is marked for refresh if cache.needsRefresh.Load() { fileInfo, err := os.Stat(cleanPath) // Remove from cache if file changed or doesn't exist @@ -303,10 +297,15 @@ func findAndCompileModule( cache.modules.Delete(cleanPath) // Continue to recompile } else { + // Update last used time and return cached bytecode + entry.LastUsed = time.Now() + cache.modules.Store(cleanPath, entry) return entry.Bytecode, nil } } else { - // No refresh needed, use cached bytecode + // Update last used time and return cached bytecode + entry.LastUsed = time.Now() + cache.modules.Store(cleanPath, entry) return entry.Bytecode, nil } } diff --git a/core/watchers/modulewatcher.go b/core/watchers/modulewatcher.go index 9ca17b9..e0eee54 100644 --- a/core/watchers/modulewatcher.go +++ b/core/watchers/modulewatcher.go @@ -10,30 +10,32 @@ func WatchLuaModules(luaRunner *runner.LuaRunner, libDirs []string, log *logger. watchers := make([]*Watcher, 0, len(libDirs)) for _, dir := range libDirs { - // Create a directory-specific callback that only signals changes - // without doing heavy processing in the callback itself + // Create a directory-specific callback that only does minimal work dirCopy := dir // Capture for closure callback := func() error { log.Debug("Detected changes in Lua module directory: %s", dirCopy) - // Only mark that refresh is needed instead of doing refresh now - luaRunner.RequireCache().MarkNeedsRefresh() + + // Completely reset the cache to match fresh-start performance + luaRunner.RequireCache().Clear() + + // Force reset of Lua's module registry + luaRunner.ResetPackageLoaded() + return nil } config := WatcherConfig{ - Dir: dir, - Callback: callback, - Log: log, - Recursive: true, - Adaptive: true, - // Use a longer debounce time to avoid too frequent updates - DebounceTime: defaultDebounceTime * 4, + Dir: dir, + Callback: callback, + Log: log, + Recursive: true, + Adaptive: true, + DebounceTime: defaultDebounceTime, } watcher, err := WatchDirectory(config) if err != nil { - // Close any watchers we've already created for _, w := range watchers { w.Close() } diff --git a/core/watchers/watcher.go b/core/watchers/watcher.go index 5033f8b..e4d77df 100644 --- a/core/watchers/watcher.go +++ b/core/watchers/watcher.go @@ -12,11 +12,9 @@ import ( // Default polling intervals const ( - defaultPollInterval = 1 * time.Second // Initial polling interval - extendedPollInterval = 5 * time.Second // Extended polling interval after inactivity - maxPollInterval = 10 * time.Second // Maximum polling interval after long inactivity - inactivityThreshold = 5 * time.Minute // Time before extending polling interval - secondExtendThreshold = 30 * time.Minute // Time before second extension + defaultPollInterval = 1 * time.Second // Initial polling interval + extendedPollInterval = 5 * time.Second // Extended polling interval after inactivity + inactivityThreshold = 10 * time.Minute // Time before extending polling interval ) // Default debounce time between detected change and callback @@ -121,7 +119,7 @@ func WatchDirectory(config WatcherConfig) (*Watcher, error) { go w.debounceLoop() if config.Adaptive { - w.logDebug("Started watching with adaptive polling") + w.logDebug("Started watching with adaptive polling (1s default, 5s after 10m inactivity)") } else { w.logDebug("Started watching with fixed polling interval: %v", pollInterval) } @@ -173,17 +171,11 @@ func (w *Watcher) watchLoop() { inactiveDuration := time.Since(w.lastChangeTime) if w.pollInterval == w.basePollInterval && inactiveDuration > inactivityThreshold { - // First extension + // Extend polling interval w.pollInterval = extendedPollInterval ticker.Reset(w.pollInterval) w.logDebug("Extended polling interval to: %v after %v of inactivity", - w.pollInterval, inactiveDuration.Round(time.Second)) - } else if w.pollInterval == extendedPollInterval && inactiveDuration > secondExtendThreshold { - // Second extension - w.pollInterval = maxPollInterval - ticker.Reset(w.pollInterval) - w.logDebug("Extended polling interval to: %v after %v of inactivity", - w.pollInterval, inactiveDuration.Round(time.Second)) + w.pollInterval, inactiveDuration.Round(time.Minute)) } } @@ -268,6 +260,7 @@ func (w *Watcher) logError(format string, args ...any) { w.log.Error("[Watcher] [%s] %s", w.dir, fmt.Sprintf(format, args...)) } +// checkForChanges detects if any files have been added, modified, or deleted func (w *Watcher) checkForChanges() (bool, error) { // Get current state currentFiles := make(map[string]FileInfo) @@ -308,43 +301,36 @@ func (w *Watcher) checkForChanges() (bool, error) { return true, nil } - // Check for modified files - var changed bool + // Check for modified, added, or removed files for path, currentInfo := range currentFiles { prevInfo, exists := previousFiles[path] if !exists { // New file w.logDebug("New file detected: %s", path) - changed = true - break + w.updateFiles(currentFiles) + return true, nil } if currentInfo.ModTime != prevInfo.ModTime || currentInfo.Size != prevInfo.Size { // File modified w.logDebug("File modified: %s", path) - changed = true - break + w.updateFiles(currentFiles) + return true, nil } } // Check for deleted files - if !changed { - for path := range previousFiles { - if _, exists := currentFiles[path]; !exists { - // File deleted - w.logDebug("File deleted: %s", path) - changed = true - break - } + for path := range previousFiles { + if _, exists := currentFiles[path]; !exists { + // File deleted + w.logDebug("File deleted: %s", path) + w.updateFiles(currentFiles) + return true, nil } } - // Update internal files state if there were changes - if changed { - w.updateFiles(currentFiles) - } - - return changed, nil + // No changes detected + return false, nil } // updateFiles updates the internal file list diff --git a/moonshark.go b/moonshark.go index e30ee0c..e7b6286 100644 --- a/moonshark.go +++ b/moonshark.go @@ -208,8 +208,15 @@ func main() { } }() + httpLoggingEnabled := cfg.GetBool("http_logging_enabled", true) + if httpLoggingEnabled { + log.Info("HTTP logging is enabled") + } else { + log.Info("HTTP logging is disabled") + } + // Create HTTP server - server := http.New(luaRouter, staticRouter, luaRunner, log) + server := http.New(luaRouter, staticRouter, luaRunner, log, httpLoggingEnabled) // Handle graceful shutdown stop := make(chan os.Signal, 1)