Files
gf/os/gfsnotify/gfsnotify_watcher_loop.go

174 lines
5.0 KiB
Go
Raw Normal View History

// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
2018-11-16 18:20:09 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
2018-11-16 18:20:09 +08:00
package gfsnotify
import (
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/container/glist"
2019-10-31 23:37:33 +08:00
"github.com/gogf/gf/internal/intlog"
2018-11-16 18:20:09 +08:00
)
2019-10-31 23:37:33 +08:00
// startWatchLoop starts the loop for event listening fro underlying inotify monitor.
2018-11-16 18:20:09 +08:00
func (w *Watcher) startWatchLoop() {
2019-06-19 09:06:52 +08:00
go func() {
for {
select {
2019-10-31 23:37:33 +08:00
// Close event.
2019-06-19 09:06:52 +08:00
case <-w.closeChan:
return
2018-11-16 18:20:09 +08:00
2019-10-31 23:37:33 +08:00
// Event listening.
2019-06-19 09:06:52 +08:00
case ev := <-w.watcher.Events:
2019-10-31 23:37:33 +08:00
// Filter the repeated event in custom duration.
2019-06-19 09:06:52 +08:00
w.cache.SetIfNotExist(ev.String(), func() interface{} {
w.events.Push(&Event{
event: ev,
Path: ev.Name,
Op: Op(ev.Op),
Watcher: w,
})
return struct{}{}
}, repeatEventFilterDuration)
2018-11-16 18:20:09 +08:00
2019-10-31 23:37:33 +08:00
case err := <-w.watcher.Errors:
intlog.Error(err)
2019-06-19 09:06:52 +08:00
}
}
}()
2018-11-16 18:20:09 +08:00
}
2019-10-31 23:37:33 +08:00
// getCallbacks searches and returns all callbacks with given <path>.
// It also searches its parent for callbacks if they're recursive.
func (w *Watcher) getCallbacks(path string) (callbacks []*Callback) {
2019-10-31 23:37:33 +08:00
// Firstly add the callbacks of itself.
2019-06-19 09:06:52 +08:00
if v := w.callbacks.Get(path); v != nil {
for _, v := range v.(*glist.List).FrontAll() {
callback := v.(*Callback)
callbacks = append(callbacks, callback)
}
}
2019-10-31 23:37:33 +08:00
// Secondly searches its parent for callbacks.
2019-06-19 09:06:52 +08:00
dirPath := fileDir(path)
if v := w.callbacks.Get(dirPath); v != nil {
for _, v := range v.(*glist.List).FrontAll() {
callback := v.(*Callback)
2019-10-31 23:37:33 +08:00
if callback.recursive {
callbacks = append(callbacks, callback)
}
2019-06-19 09:06:52 +08:00
}
}
2019-10-31 23:37:33 +08:00
// Lastly searches the parent recursively for callbacks.
2019-06-19 09:06:52 +08:00
for {
parentDirPath := fileDir(dirPath)
if parentDirPath == dirPath {
break
}
if v := w.callbacks.Get(parentDirPath); v != nil {
for _, v := range v.(*glist.List).FrontAll() {
callback := v.(*Callback)
if callback.recursive {
callbacks = append(callbacks, callback)
}
}
}
dirPath = parentDirPath
}
return
2018-11-16 18:20:09 +08:00
}
2019-10-31 23:37:33 +08:00
// startEventLoop is the core event handler.
2018-11-16 18:20:09 +08:00
func (w *Watcher) startEventLoop() {
2019-06-19 09:06:52 +08:00
go func() {
for {
if v := w.events.Pop(); v != nil {
event := v.(*Event)
2019-10-31 23:37:33 +08:00
// If there's no any callback of this path, it removes it from monitor.
2019-06-19 09:06:52 +08:00
callbacks := w.getCallbacks(event.Path)
if len(callbacks) == 0 {
2019-11-01 15:31:26 +08:00
w.watcher.Remove(event.Path)
2019-06-19 09:06:52 +08:00
continue
}
switch {
case event.IsRemove():
2019-10-31 23:37:33 +08:00
// It should check again the existence of the path.
// It adds it back to the monitor if it still exists.
2019-06-19 09:06:52 +08:00
if fileExists(event.Path) {
2019-10-31 23:37:33 +08:00
// It adds the path back to monitor.
// We need no worry about the repeat adding.
if err := w.watcher.Add(event.Path); err != nil {
intlog.Error(err)
} else {
intlog.Printf("fake remove event, watcher re-adds monitor for: %s", event.Path)
2019-10-31 23:37:33 +08:00
}
// Change the event to RENAME, which means it renames itself to its origin name.
2019-06-19 09:06:52 +08:00
event.Op = RENAME
}
2018-11-16 18:20:09 +08:00
2019-06-19 09:06:52 +08:00
case event.IsRename():
2019-10-31 23:37:33 +08:00
// It should check again the existence of the path.
// It adds it back to the monitor if it still exists.
// Especially Some editors might do RENAME and then CHMOD when it's editing file.
2019-06-19 09:06:52 +08:00
if fileExists(event.Path) {
2019-10-31 23:37:33 +08:00
// It might lost the monitoring for the path, so we add the path back to monitor.
// We need no worry about the repeat adding.
if err := w.watcher.Add(event.Path); err != nil {
intlog.Error(err)
} else {
intlog.Printf("fake rename event, watcher re-adds monitor for: %s", event.Path)
2019-10-31 23:37:33 +08:00
}
// Change the event to CHMOD.
2019-06-19 09:06:52 +08:00
event.Op = CHMOD
}
2018-11-16 18:20:09 +08:00
2019-06-19 09:06:52 +08:00
case event.IsCreate():
// =========================================
2019-10-31 23:37:33 +08:00
// Note that it here just adds the path to monitor without any callback registering,
// because its parent already has the callbacks.
2019-06-19 09:06:52 +08:00
// =========================================
if fileIsDir(event.Path) {
2019-10-31 23:37:33 +08:00
// If it's a folder, it then does adding recursively to monitor.
2019-06-19 09:06:52 +08:00
for _, subPath := range fileAllDirs(event.Path) {
if fileIsDir(subPath) {
2019-10-31 23:37:33 +08:00
if err := w.watcher.Add(subPath); err != nil {
intlog.Error(err)
} else {
intlog.Printf("folder creation event, watcher adds monitor for: %s", subPath)
2019-10-31 23:37:33 +08:00
}
2019-06-19 09:06:52 +08:00
}
}
} else {
2019-10-31 23:37:33 +08:00
// If it's a file, it directly adds it to monitor.
if err := w.watcher.Add(event.Path); err != nil {
intlog.Error(err)
} else {
intlog.Printf("file creation event, watcher adds monitor for: %s", event.Path)
2019-10-31 23:37:33 +08:00
}
2019-06-19 09:06:52 +08:00
}
2018-11-16 18:20:09 +08:00
2019-06-19 09:06:52 +08:00
}
2019-10-31 23:37:33 +08:00
// Calling the callbacks in order.
2019-06-19 09:06:52 +08:00
for _, v := range callbacks {
go func(callback *Callback) {
defer func() {
if err := recover(); err != nil {
switch err {
case callbackExitEventPanicStr:
2019-06-19 09:06:52 +08:00
w.RemoveCallback(callback.Id)
default:
panic(err)
}
}
}()
callback.Func(event)
}(v)
}
} else {
break
}
}
}()
}