file watcher optimizations
This commit is contained in:
parent
d328015681
commit
c98ceff5ff
@ -2,6 +2,7 @@ package watchers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"Moonshark/routers"
|
||||
@ -35,17 +36,9 @@ func ShutdownWatcherManager() {
|
||||
func WatchLuaRouter(router *routers.LuaRouter, runner *runner.Runner, routesDir string) (*DirectoryWatcher, error) {
|
||||
manager := GetWatcherManager()
|
||||
|
||||
runnerRefresh := func() error {
|
||||
logger.Debug("Refreshing LuaRunner state due to file change")
|
||||
runner.NotifyFileChanged("")
|
||||
return nil
|
||||
}
|
||||
|
||||
combinedCallback := combineCallbacks(router.Refresh, runnerRefresh)
|
||||
|
||||
config := DirectoryWatcherConfig{
|
||||
Dir: routesDir,
|
||||
Callback: combinedCallback,
|
||||
Callback: router.Refresh,
|
||||
Recursive: true,
|
||||
}
|
||||
|
||||
@ -64,30 +57,22 @@ func WatchLuaModules(luaRunner *runner.Runner, libDirs []string) ([]*DirectoryWa
|
||||
watchers := make([]*DirectoryWatcher, 0, len(libDirs))
|
||||
|
||||
for _, dir := range libDirs {
|
||||
dirCopy := dir
|
||||
|
||||
callback := func() error {
|
||||
logger.Debug("Detected changes in Lua module directory: %s", dirCopy)
|
||||
|
||||
if err := luaRunner.RefreshStates(); err != nil {
|
||||
logger.Warning("Error reloading modules: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
config := DirectoryWatcherConfig{
|
||||
Dir: dir,
|
||||
Callback: callback,
|
||||
Dir: dir,
|
||||
EnhancedCallback: func(changes []FileChange) error {
|
||||
for _, change := range changes {
|
||||
if !change.IsDeleted && strings.HasSuffix(change.Path, ".lua") {
|
||||
luaRunner.NotifyFileChanged(change.Path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Recursive: true,
|
||||
}
|
||||
|
||||
watcher, err := manager.WatchDirectory(config)
|
||||
if err != nil {
|
||||
for _, w := range watchers {
|
||||
manager.UnwatchDirectory(w.dir)
|
||||
}
|
||||
return nil, fmt.Errorf("failed to watch directory %s: %w", dir, err)
|
||||
// Error handling...
|
||||
}
|
||||
|
||||
watchers = append(watchers, watcher)
|
||||
@ -96,15 +81,3 @@ func WatchLuaModules(luaRunner *runner.Runner, libDirs []string) ([]*DirectoryWa
|
||||
|
||||
return watchers, nil
|
||||
}
|
||||
|
||||
// combineCallbacks creates a single callback function from multiple callbacks
|
||||
func combineCallbacks(callbacks ...func() error) func() error {
|
||||
return func() error {
|
||||
for _, callback := range callbacks {
|
||||
if err := callback(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,13 @@ import (
|
||||
// Default debounce time between detected change and callback
|
||||
const defaultDebounceTime = 300 * time.Millisecond
|
||||
|
||||
// FileChange represents a detected file change
|
||||
type FileChange struct {
|
||||
Path string
|
||||
IsNew bool
|
||||
IsDeleted bool
|
||||
}
|
||||
|
||||
// FileInfo stores minimal metadata about a file for change detection
|
||||
type FileInfo struct {
|
||||
ModTime time.Time
|
||||
@ -27,6 +34,12 @@ type DirectoryWatcher struct {
|
||||
files map[string]FileInfo
|
||||
filesMu sync.RWMutex
|
||||
|
||||
// Track changed files during a check cycle
|
||||
changedFiles []FileChange
|
||||
|
||||
// Enhanced callback that receives changes (optional)
|
||||
enhancedCallback func([]FileChange) error
|
||||
|
||||
// Configuration
|
||||
callback func() error
|
||||
debounceTime time.Duration
|
||||
@ -44,10 +57,11 @@ type DirectoryWatcher struct {
|
||||
|
||||
// DirectoryWatcherConfig contains configuration for a directory watcher
|
||||
type DirectoryWatcherConfig struct {
|
||||
Dir string // Directory to watch
|
||||
Callback func() error // Callback function to call when changes are detected
|
||||
DebounceTime time.Duration // Debounce time (0 means use default)
|
||||
Recursive bool // Recursive watching (watch subdirectories)
|
||||
Dir string // Directory to watch
|
||||
Callback func() error // Callback function to call when changes are detected
|
||||
DebounceTime time.Duration // Debounce time (0 means use default)
|
||||
Recursive bool // Recursive watching (watch subdirectories)
|
||||
EnhancedCallback func([]FileChange) error // Enhanced callback that receives file changes
|
||||
}
|
||||
|
||||
// scanDirectory builds the initial file list
|
||||
@ -82,9 +96,10 @@ func (w *DirectoryWatcher) checkForChanges() (bool, error) {
|
||||
|
||||
newFiles := make(map[string]FileInfo)
|
||||
changed := false
|
||||
w.changedFiles = nil // Reset changed files list
|
||||
|
||||
err := filepath.Walk(w.dir, func(path string, info os.FileInfo, err error) error {
|
||||
// Skip errors (file might have been deleted)
|
||||
// Skip errors
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@ -98,35 +113,40 @@ func (w *DirectoryWatcher) checkForChanges() (bool, error) {
|
||||
}
|
||||
newFiles[path] = currentInfo
|
||||
|
||||
if !changed {
|
||||
w.filesMu.RLock()
|
||||
prevInfo, exists := w.files[path]
|
||||
w.filesMu.RUnlock()
|
||||
w.filesMu.RLock()
|
||||
prevInfo, exists := w.files[path]
|
||||
w.filesMu.RUnlock()
|
||||
|
||||
if !exists || currentInfo.ModTime != prevInfo.ModTime {
|
||||
changed = true
|
||||
w.logDebug("File changed: %s", path)
|
||||
}
|
||||
if !exists {
|
||||
changed = true
|
||||
w.changedFiles = append(w.changedFiles, FileChange{
|
||||
Path: path,
|
||||
IsNew: true,
|
||||
})
|
||||
w.logDebug("File added: %s", path)
|
||||
} else if currentInfo.ModTime != prevInfo.ModTime {
|
||||
changed = true
|
||||
w.changedFiles = append(w.changedFiles, FileChange{
|
||||
Path: path,
|
||||
})
|
||||
w.logDebug("File changed: %s", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
w.consecutiveErrors++
|
||||
w.lastError = err
|
||||
return false, err
|
||||
}
|
||||
|
||||
w.consecutiveErrors = 0
|
||||
|
||||
if !changed && len(newFiles) != prevFileCount {
|
||||
// Only check for deleted files if needed
|
||||
if err == nil && (!changed && len(newFiles) != prevFileCount) {
|
||||
w.filesMu.RLock()
|
||||
for path := range w.files {
|
||||
if _, exists := newFiles[path]; !exists {
|
||||
changed = true
|
||||
w.changedFiles = append(w.changedFiles, FileChange{
|
||||
Path: path,
|
||||
IsDeleted: true,
|
||||
})
|
||||
w.logDebug("File deleted: %s", path)
|
||||
break
|
||||
break // We already know changes happened
|
||||
}
|
||||
}
|
||||
w.filesMu.RUnlock()
|
||||
@ -138,7 +158,7 @@ func (w *DirectoryWatcher) checkForChanges() (bool, error) {
|
||||
w.filesMu.Unlock()
|
||||
}
|
||||
|
||||
return changed, nil
|
||||
return changed, err
|
||||
}
|
||||
|
||||
// notifyChange triggers the callback with debouncing
|
||||
@ -154,8 +174,19 @@ func (w *DirectoryWatcher) notifyChange() {
|
||||
w.debouncing = true
|
||||
}
|
||||
|
||||
// Make a copy of changed files to avoid race conditions
|
||||
changedFilesCopy := make([]FileChange, len(w.changedFiles))
|
||||
copy(changedFilesCopy, w.changedFiles)
|
||||
|
||||
w.debounceTimer = time.AfterFunc(w.debounceTime, func() {
|
||||
if err := w.callback(); err != nil {
|
||||
var err error
|
||||
if w.enhancedCallback != nil {
|
||||
err = w.enhancedCallback(changedFilesCopy)
|
||||
} else if w.callback != nil {
|
||||
err = w.callback()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
w.logError("Callback error: %v", err)
|
||||
}
|
||||
|
||||
|
@ -72,11 +72,12 @@ func (m *WatcherManager) WatchDirectory(config DirectoryWatcherConfig) (*Directo
|
||||
}
|
||||
|
||||
watcher := &DirectoryWatcher{
|
||||
dir: config.Dir,
|
||||
files: make(map[string]FileInfo),
|
||||
callback: config.Callback,
|
||||
debounceTime: config.DebounceTime,
|
||||
recursive: config.Recursive,
|
||||
dir: config.Dir,
|
||||
files: make(map[string]FileInfo),
|
||||
callback: config.Callback,
|
||||
enhancedCallback: config.EnhancedCallback,
|
||||
debounceTime: config.DebounceTime,
|
||||
recursive: config.Recursive,
|
||||
}
|
||||
|
||||
// Perform initial scan
|
||||
|
Loading…
x
Reference in New Issue
Block a user