// 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/g/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 } } }() }