Compare commits
No commits in common. "522a5770edd371b15ad60ccd5aa77d5cab5b3f0c" and "87aadc857400ccfdd3443795798cd74075b2dc80" have entirely different histories.
522a5770ed
...
87aadc8574
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
52
moonshark.go
52
moonshark.go
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user