/
gfsnotify_watcher.go
142 lines (133 loc) · 4.21 KB
/
gfsnotify_watcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// 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 (
"errors"
"fmt"
"github.com/gogf/gf/g/container/glist"
)
// 添加监控,path参数支持文件或者目录路径,recursive为非必需参数,默认为递归监控(当path为目录时)。
// 如果添加目录,这里只会返回目录的callback,按照callback删除时会递归删除。
func (w *Watcher) Add(path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
// 首先添加这个文件/目录
callback, err = w.addWithCallbackFunc(path, callbackFunc, recursive...)
if err != nil {
return nil, err
}
// 如果需要递归,那么递归添加其下的子级目录,
// 注意!!
// 1、这里只递归添加**目录**, 而非文件,因为监控了目录即监控了其下一级的文件;
// 2、这里只是添加底层监控对象对**子级所有目录**的监控,没有任何回调函数的设置,在事件产生时会回溯查找父级的回调函数;
if fileIsDir(path) && (len(recursive) == 0 || recursive[0]) {
for _, subPath := range fileAllDirs(path) {
if fileIsDir(subPath) {
w.watcher.Add(subPath)
}
}
}
return
}
// 添加对指定文件/目录的监听,并给定回调函数
func (w *Watcher) addWithCallbackFunc(path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
// 这里统一转换为当前系统的绝对路径,便于统一监控文件名称
if t := fileRealPath(path); t == "" {
return nil, errors.New(fmt.Sprintf(`"%s" does not exist`, path))
} else {
path = t
}
callback = &Callback{
Id: callbackIdGenerator.Add(1),
Func: callbackFunc,
Path: path,
recursive: true,
}
if len(recursive) > 0 {
callback.recursive = recursive[0]
}
// 注册回调函数
w.callbacks.LockFunc(func(m map[string]interface{}) {
list := (*glist.List)(nil)
if v, ok := m[path]; !ok {
list = glist.New()
m[path] = list
} else {
list = v.(*glist.List)
}
callback.elem = list.PushBack(callback)
})
// 添加底层监听
w.watcher.Add(path)
// 添加成功后会注册该callback id到全局的哈希表
callbackIdMap.Set(callback.Id, callback)
return
}
// 关闭监听管理对象
func (w *Watcher) Close() {
w.events.Close()
w.watcher.Close()
close(w.closeChan)
}
// 递归移除对指定文件/目录的所有监听回调
func (w *Watcher) Remove(path string) error {
// 首先移除path注册的回调注册,以及callbackIdMap中的ID
if r := w.callbacks.Remove(path); r != nil {
list := r.(*glist.List)
for {
if r := list.PopFront(); r != nil {
callbackIdMap.Remove(r.(*Callback).Id)
} else {
break
}
}
}
// 其次递归判断所有的子级是否可删除监听
if subPaths, err := fileScanDir(path, "*", true); err == nil && len(subPaths) > 0 {
for _, subPath := range subPaths {
if w.checkPathCanBeRemoved(subPath) {
w.watcher.Remove(subPath)
}
}
}
// 最后移除底层的监听
return w.watcher.Remove(path)
}
// 判断给定的路径是否可以删除监听(只有所有回调函数都没有了才能删除)
func (w *Watcher) checkPathCanBeRemoved(path string) bool {
// 首先检索path对应的回调函数
if v := w.callbacks.Get(path); v != nil {
return false
}
// 其次查找父级目录有无回调注册
dirPath := fileDir(path)
if v := w.callbacks.Get(dirPath); v != nil {
return false
}
// 最后回溯查找递归回调函数
for {
parentDirPath := fileDir(dirPath)
if parentDirPath == dirPath {
break
}
if v := w.callbacks.Get(parentDirPath); v != nil {
return false
}
dirPath = parentDirPath
}
return true
}
// 根据指定的回调函数ID,移出指定的inotify回调函数
func (w *Watcher) RemoveCallback(callbackId int) {
callback := (*Callback)(nil)
if r := callbackIdMap.Get(callbackId); r != nil {
callback = r.(*Callback)
}
if callback != nil {
if r := w.callbacks.Get(callback.Path); r != nil {
r.(*glist.List).Remove(callback.elem)
}
callbackIdMap.Remove(callbackId)
}
}