Compare commits

..

No commits in common. "522a5770edd371b15ad60ccd5aa77d5cab5b3f0c" and "87aadc857400ccfdd3443795798cd74075b2dc80" have entirely different histories.

5 changed files with 94 additions and 125 deletions

View File

@ -19,18 +19,16 @@ type Server struct {
luaRunner *runner.LuaRunner luaRunner *runner.LuaRunner
logger *logger.Logger logger *logger.Logger
httpServer *http.Server httpServer *http.Server
loggingEnabled bool
} }
// New creates a new HTTP server with optimized connection settings // New creates a new HTTP server with optimized connection settings
func New(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter, runner *runner.LuaRunner, log *logger.Logger, loggingEnabled bool) *Server { func New(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter, runner *runner.LuaRunner, log *logger.Logger) *Server {
server := &Server{ server := &Server{
luaRouter: luaRouter, luaRouter: luaRouter,
staticRouter: staticRouter, staticRouter: staticRouter,
luaRunner: runner, luaRunner: runner,
logger: log, logger: log,
httpServer: &http.Server{}, httpServer: &http.Server{},
loggingEnabled: loggingEnabled,
} }
server.httpServer.Handler = server server.httpServer.Handler = server
@ -76,9 +74,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
statusCode := wrappedWriter.StatusCode() statusCode := wrappedWriter.StatusCode()
// Log the request with our custom format // Log the request with our custom format
if s.loggingEnabled {
LogRequest(s.logger, statusCode, r, duration) LogRequest(s.logger, statusCode, r, duration)
}
} }
// handleRequest processes the actual request // handleRequest processes the actual request

View File

@ -212,8 +212,21 @@ func (c *RequireCache) RefreshAll() int {
return 0 return 0
} }
// For maximum performance, just clear everything // Collect paths to check
c.Clear() 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++
}
}
// Reset the needsRefresh flag // Reset the needsRefresh flag
c.needsRefresh.Store(false) c.needsRefresh.Store(false)
@ -254,13 +267,6 @@ 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 // Try each path
for _, path := range paths { for _, path := range paths {
// Clean the path to handle .. and such (security) // Clean the path to handle .. and such (security)
@ -289,7 +295,7 @@ func findAndCompileModule(
return value.([]byte), nil return value.([]byte), nil
} }
// Check file modification time if cache is marked for refresh // Only do refresh check if marked as needed (by watcher)
if cache.needsRefresh.Load() { if cache.needsRefresh.Load() {
fileInfo, err := os.Stat(cleanPath) fileInfo, err := os.Stat(cleanPath)
// Remove from cache if file changed or doesn't exist // Remove from cache if file changed or doesn't exist
@ -297,15 +303,10 @@ func findAndCompileModule(
cache.modules.Delete(cleanPath) cache.modules.Delete(cleanPath)
// Continue to recompile // Continue to recompile
} else { } else {
// Update last used time and return cached bytecode
entry.LastUsed = time.Now()
cache.modules.Store(cleanPath, entry)
return entry.Bytecode, nil return entry.Bytecode, nil
} }
} else { } else {
// Update last used time and return cached bytecode // No refresh needed, use cached bytecode
entry.LastUsed = time.Now()
cache.modules.Store(cleanPath, entry)
return entry.Bytecode, nil return entry.Bytecode, nil
} }
} }

View File

@ -10,18 +10,14 @@ func WatchLuaModules(luaRunner *runner.LuaRunner, libDirs []string, log *logger.
watchers := make([]*Watcher, 0, len(libDirs)) watchers := make([]*Watcher, 0, len(libDirs))
for _, dir := range libDirs { for _, dir := range libDirs {
// Create a directory-specific callback that only does minimal work // Create a directory-specific callback that only signals changes
// without doing heavy processing in the callback itself
dirCopy := dir // Capture for closure dirCopy := dir // Capture for closure
callback := func() error { callback := func() error {
log.Debug("Detected changes in Lua module directory: %s", dirCopy) log.Debug("Detected changes in Lua module directory: %s", dirCopy)
// Only mark that refresh is needed instead of doing refresh now
// Completely reset the cache to match fresh-start performance luaRunner.RequireCache().MarkNeedsRefresh()
luaRunner.RequireCache().Clear()
// Force reset of Lua's module registry
luaRunner.ResetPackageLoaded()
return nil return nil
} }
@ -31,11 +27,13 @@ func WatchLuaModules(luaRunner *runner.LuaRunner, libDirs []string, log *logger.
Log: log, Log: log,
Recursive: true, Recursive: true,
Adaptive: true, Adaptive: true,
DebounceTime: defaultDebounceTime, // Use a longer debounce time to avoid too frequent updates
DebounceTime: defaultDebounceTime * 4,
} }
watcher, err := WatchDirectory(config) watcher, err := WatchDirectory(config)
if err != nil { if err != nil {
// Close any watchers we've already created
for _, w := range watchers { for _, w := range watchers {
w.Close() w.Close()
} }

View File

@ -14,7 +14,9 @@ import (
const ( const (
defaultPollInterval = 1 * time.Second // Initial polling interval defaultPollInterval = 1 * time.Second // Initial polling interval
extendedPollInterval = 5 * time.Second // Extended polling interval after inactivity extendedPollInterval = 5 * time.Second // Extended polling interval after inactivity
inactivityThreshold = 10 * time.Minute // Time before extending polling interval 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
) )
// Default debounce time between detected change and callback // Default debounce time between detected change and callback
@ -119,7 +121,7 @@ func WatchDirectory(config WatcherConfig) (*Watcher, error) {
go w.debounceLoop() go w.debounceLoop()
if config.Adaptive { if config.Adaptive {
w.logDebug("Started watching with adaptive polling (1s default, 5s after 10m inactivity)") w.logDebug("Started watching with adaptive polling")
} else { } else {
w.logDebug("Started watching with fixed polling interval: %v", pollInterval) w.logDebug("Started watching with fixed polling interval: %v", pollInterval)
} }
@ -171,11 +173,17 @@ func (w *Watcher) watchLoop() {
inactiveDuration := time.Since(w.lastChangeTime) inactiveDuration := time.Since(w.lastChangeTime)
if w.pollInterval == w.basePollInterval && inactiveDuration > inactivityThreshold { if w.pollInterval == w.basePollInterval && inactiveDuration > inactivityThreshold {
// Extend polling interval // First extension
w.pollInterval = extendedPollInterval w.pollInterval = extendedPollInterval
ticker.Reset(w.pollInterval) ticker.Reset(w.pollInterval)
w.logDebug("Extended polling interval to: %v after %v of inactivity", w.logDebug("Extended polling interval to: %v after %v of inactivity",
w.pollInterval, inactiveDuration.Round(time.Minute)) 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))
} }
} }
@ -260,7 +268,6 @@ func (w *Watcher) logError(format string, args ...any) {
w.log.Error("[Watcher] [%s] %s", w.dir, fmt.Sprintf(format, args...)) 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) { func (w *Watcher) checkForChanges() (bool, error) {
// Get current state // Get current state
currentFiles := make(map[string]FileInfo) currentFiles := make(map[string]FileInfo)
@ -301,36 +308,43 @@ func (w *Watcher) checkForChanges() (bool, error) {
return true, nil return true, nil
} }
// Check for modified, added, or removed files // Check for modified files
var changed bool
for path, currentInfo := range currentFiles { for path, currentInfo := range currentFiles {
prevInfo, exists := previousFiles[path] prevInfo, exists := previousFiles[path]
if !exists { if !exists {
// New file // New file
w.logDebug("New file detected: %s", path) w.logDebug("New file detected: %s", path)
w.updateFiles(currentFiles) changed = true
return true, nil break
} }
if currentInfo.ModTime != prevInfo.ModTime || currentInfo.Size != prevInfo.Size { if currentInfo.ModTime != prevInfo.ModTime || currentInfo.Size != prevInfo.Size {
// File modified // File modified
w.logDebug("File modified: %s", path) w.logDebug("File modified: %s", path)
w.updateFiles(currentFiles) changed = true
return true, nil break
} }
} }
// Check for deleted files // Check for deleted files
if !changed {
for path := range previousFiles { for path := range previousFiles {
if _, exists := currentFiles[path]; !exists { if _, exists := currentFiles[path]; !exists {
// File deleted // File deleted
w.logDebug("File deleted: %s", path) w.logDebug("File deleted: %s", path)
w.updateFiles(currentFiles) changed = true
return true, nil break
}
} }
} }
// No changes detected // Update internal files state if there were changes
return false, nil if changed {
w.updateFiles(currentFiles)
}
return changed, nil
} }
// updateFiles updates the internal file list // updateFiles updates the internal file list

View File

@ -17,13 +17,6 @@ import (
"git.sharkk.net/Sky/Moonshark/core/watchers" "git.sharkk.net/Sky/Moonshark/core/watchers"
) )
// WatcherConfig holds the configuration for which watchers to enable
type WatcherConfig struct {
Routes bool
Static bool
Modules bool
}
// initRouters sets up the Lua and static routers // initRouters sets up the Lua and static routers
func initRouters(routesDir, staticDir string, log *logger.Logger) (*routers.LuaRouter, *routers.StaticRouter, error) { func initRouters(routesDir, staticDir string, log *logger.Logger) (*routers.LuaRouter, *routers.StaticRouter, error) {
// Ensure directories exist // Ensure directories exist
@ -55,12 +48,11 @@ func initRouters(routesDir, staticDir string, log *logger.Logger) (*routers.LuaR
// setupWatchers initializes and starts all file watchers // setupWatchers initializes and starts all file watchers
func setupWatchers(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter, func setupWatchers(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter,
luaRunner *runner.LuaRunner, routesDir string, staticDir string, luaRunner *runner.LuaRunner, routesDir string, staticDir string,
libDirs []string, log *logger.Logger, config WatcherConfig) ([]func() error, error) { libDirs []string, log *logger.Logger) ([]func() error, error) {
var cleanupFuncs []func() error var cleanupFuncs []func() error
// Set up watcher for Lua routes // Set up watcher for Lua routes
if config.Routes {
luaRouterWatcher, err := watchers.WatchLuaRouter(luaRouter, routesDir, log) luaRouterWatcher, err := watchers.WatchLuaRouter(luaRouter, routesDir, log)
if err != nil { if err != nil {
log.Warning("Failed to watch routes directory: %v", err) log.Warning("Failed to watch routes directory: %v", err)
@ -68,10 +60,8 @@ func setupWatchers(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRou
cleanupFuncs = append(cleanupFuncs, luaRouterWatcher.Close) cleanupFuncs = append(cleanupFuncs, luaRouterWatcher.Close)
log.Info("File watcher active for Lua routes") log.Info("File watcher active for Lua routes")
} }
}
// Set up watcher for static files // Set up watcher for static files
if config.Static {
staticWatcher, err := watchers.WatchStaticRouter(staticRouter, staticDir, log) staticWatcher, err := watchers.WatchStaticRouter(staticRouter, staticDir, log)
if err != nil { if err != nil {
log.Warning("Failed to watch static directory: %v", err) log.Warning("Failed to watch static directory: %v", err)
@ -79,10 +69,9 @@ func setupWatchers(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRou
cleanupFuncs = append(cleanupFuncs, staticWatcher.Close) cleanupFuncs = append(cleanupFuncs, staticWatcher.Close)
log.Info("File watcher active for static files") log.Info("File watcher active for static files")
} }
}
// Set up watchers for Lua modules libraries // Set up watchers for Lua modules libraries
if config.Modules && len(libDirs) > 0 { if len(libDirs) > 0 {
moduleWatchers, err := watchers.WatchLuaModules(luaRunner, libDirs, log) moduleWatchers, err := watchers.WatchLuaModules(luaRunner, libDirs, log)
if err != nil { if err != nil {
log.Warning("Failed to watch Lua module directories: %v", err) log.Warning("Failed to watch Lua module directories: %v", err)
@ -170,34 +159,12 @@ func main() {
// Set up file watchers if enabled // Set up file watchers if enabled
var cleanupFuncs []func() error var cleanupFuncs []func() error
if cfg.GetBool("watchers", true) {
// Get watcher configuration (default all disabled) cleanupFuncs, err = setupWatchers(luaRouter, staticRouter, luaRunner, routesDir, staticDir, libDirs, log)
watcherConfig := WatcherConfig{
Routes: false,
Static: false,
Modules: false,
}
// Enable watchers based on map configuration
watchersMap := cfg.GetMap("watchers")
if watchersMap != nil {
if routes, ok := watchersMap["routes"].(bool); ok && routes {
watcherConfig.Routes = true
}
if static, ok := watchersMap["static"].(bool); ok && static {
watcherConfig.Static = true
}
if modules, ok := watchersMap["modules"].(bool); ok && modules {
watcherConfig.Modules = true
}
}
// Setup enabled watchers
cleanupFuncs, err = setupWatchers(luaRouter, staticRouter, luaRunner,
routesDir, staticDir, libDirs, log, watcherConfig)
if err != nil { if err != nil {
log.Warning("Error setting up watchers: %v", err) log.Warning("Error setting up watchers: %v", err)
} }
}
// Register cleanup functions // Register cleanup functions
defer func() { defer func() {
@ -208,15 +175,8 @@ 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 // Create HTTP server
server := http.New(luaRouter, staticRouter, luaRunner, log, httpLoggingEnabled) server := http.New(luaRouter, staticRouter, luaRunner, log)
// Handle graceful shutdown // Handle graceful shutdown
stop := make(chan os.Signal, 1) stop := make(chan os.Signal, 1)