mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 04:07:47 +08:00
152 lines
4.1 KiB
Go
152 lines
4.1 KiB
Go
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
|
//
|
|
// 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.
|
|
|
|
package gfsnotify
|
|
|
|
import (
|
|
"github.com/gogf/gf/container/glist"
|
|
)
|
|
|
|
// 监听循环
|
|
func (w *Watcher) startWatchLoop() {
|
|
go func() {
|
|
for {
|
|
select {
|
|
// 关闭事件
|
|
case <-w.closeChan:
|
|
return
|
|
|
|
// 监听事件
|
|
case ev := <-w.watcher.Events:
|
|
//fmt.Println("ev:", ev.String())
|
|
w.cache.SetIfNotExist(ev.String(), func() interface{} {
|
|
w.events.Push(&Event{
|
|
event: ev,
|
|
Path: ev.Name,
|
|
Op: Op(ev.Op),
|
|
Watcher: w,
|
|
})
|
|
return struct{}{}
|
|
}, REPEAT_EVENT_FILTER_INTERVAL)
|
|
|
|
case <-w.watcher.Errors:
|
|
//fmt.Fprintf(os.Stderr, "[gfsnotify] error: %s\n", err.Error())
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
// 获得文件路径的监听回调,包括层级的监听回调。
|
|
func (w *Watcher) getCallbacks(path string) (callbacks []*Callback) {
|
|
// 首先检索path对应的回调函数
|
|
if v := w.callbacks.Get(path); v != nil {
|
|
for _, v := range v.(*glist.List).FrontAll() {
|
|
callback := v.(*Callback)
|
|
callbacks = append(callbacks, callback)
|
|
}
|
|
}
|
|
// 其次查找父级目录有无回调注册
|
|
dirPath := fileDir(path)
|
|
if v := w.callbacks.Get(dirPath); v != nil {
|
|
for _, v := range v.(*glist.List).FrontAll() {
|
|
callback := v.(*Callback)
|
|
callbacks = append(callbacks, callback)
|
|
}
|
|
}
|
|
// 最后回溯查找递归回调函数
|
|
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
|
|
}
|
|
|
|
// 事件循环(核心逻辑)
|
|
func (w *Watcher) startEventLoop() {
|
|
go func() {
|
|
for {
|
|
if v := w.events.Pop(); v != nil {
|
|
event := v.(*Event)
|
|
// 如果该路径一个回调也没有,那么没有必要执行后续逻辑,删除对该文件的监听
|
|
callbacks := w.getCallbacks(event.Path)
|
|
if len(callbacks) == 0 {
|
|
w.watcher.Remove(event.Path)
|
|
continue
|
|
}
|
|
switch {
|
|
// 如果是删除操作,那么需要判断是否文件真正不存在了,如果存在,那么将此事件认为“假删除”
|
|
case event.IsRemove():
|
|
if fileExists(event.Path) {
|
|
// 底层重新添加监控(不用担心重复添加)
|
|
w.watcher.Add(event.Path)
|
|
// 修改事件操作为重命名(相当于重命名为自身名称,最终名称没变)
|
|
event.Op = RENAME
|
|
}
|
|
|
|
// 如果是重命名操作,那么需要判断是否文件真正不存在了,如果存在,那么将此事件认为“假命名”
|
|
// (特别是某些编辑器在编辑文件时会先对文件RENAME再CHMOD)
|
|
case event.IsRename():
|
|
if fileExists(event.Path) {
|
|
// 底层有可能去掉了监控, 这里重新添加监控(不用担心重复添加)
|
|
w.watcher.Add(event.Path)
|
|
// 修改事件操作为修改属性
|
|
event.Op = CHMOD
|
|
}
|
|
|
|
// 创建文件/目录
|
|
case event.IsCreate():
|
|
// =========================================
|
|
// 注意这里只是添加底层监听,并没有注册任何的回调函数,
|
|
// 默认的回调函数为父级的递归回调
|
|
// =========================================
|
|
if fileIsDir(event.Path) {
|
|
// 递归添加
|
|
for _, subPath := range fileAllDirs(event.Path) {
|
|
if fileIsDir(subPath) {
|
|
w.watcher.Add(subPath)
|
|
}
|
|
}
|
|
} else {
|
|
// 添加文件监听
|
|
w.watcher.Add(event.Path)
|
|
}
|
|
|
|
}
|
|
// 执行回调处理,异步处理
|
|
for _, v := range callbacks {
|
|
go func(callback *Callback) {
|
|
defer func() {
|
|
// 是否退出监控
|
|
if err := recover(); err != nil {
|
|
switch err {
|
|
case gFSNOTIFY_EVENT_EXIT:
|
|
w.RemoveCallback(callback.Id)
|
|
default:
|
|
panic(err)
|
|
}
|
|
}
|
|
}()
|
|
callback.Func(event)
|
|
}(v)
|
|
}
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
}
|