github.com/webx-top/com@v1.2.12/monitor.go (about) 1 /* 2 3 Copyright 2016 Wenhui Shen <www.webx.top> 4 5 Licensed under the Apache License, Version 2.0 (the "License"); 6 you may not use this file except in compliance with the License. 7 You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11 Unless required by applicable law or agreed to in writing, software 12 distributed under the License is distributed on an "AS IS" BASIS, 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 See the License for the specific language governing permissions and 15 limitations under the License. 16 17 */ 18 19 package com 20 21 import ( 22 "errors" 23 "log" 24 "os" 25 "path/filepath" 26 "sync" 27 28 "github.com/admpub/fsnotify" 29 ) 30 31 var ( 32 DefaultMonitor = NewMonitor() 33 MonitorEventEmptyFn = func(string) {} 34 ) 35 36 func NewMonitor() *MonitorEvent { 37 return &MonitorEvent{ 38 Create: MonitorEventEmptyFn, 39 Delete: MonitorEventEmptyFn, 40 Modify: MonitorEventEmptyFn, 41 Chmod: MonitorEventEmptyFn, 42 Rename: MonitorEventEmptyFn, 43 filters: []func(string) bool{}, 44 } 45 } 46 47 //MonitorEvent 监控事件函数 48 type MonitorEvent struct { 49 //文件事件 50 Create func(string) //创建 51 Delete func(string) //删除(包含文件夹和文件。因为已经删除,无法确定是文件夹还是文件) 52 Modify func(string) //修改(包含修改权限。如果是文件夹,则内部的文件被更改也会触发此事件) 53 Chmod func(string) //修改权限(windows不支持) 54 Rename func(string) //重命名 55 56 //其它 57 Channel chan bool //管道 58 Debug bool 59 watcher *fsnotify.Watcher 60 filters []func(string) bool 61 lock sync.RWMutex 62 } 63 64 func (m *MonitorEvent) AddFilter(args ...func(string) bool) *MonitorEvent { 65 if m.filters == nil { 66 m.filters = []func(string) bool{} 67 } 68 m.filters = append(m.filters, args...) 69 return m 70 } 71 72 func (m *MonitorEvent) SetFilters(args ...func(string) bool) *MonitorEvent { 73 m.filters = args 74 return m 75 } 76 77 func (m *MonitorEvent) Watch(args ...func(string) bool) *MonitorEvent { 78 m.SetFilters(args...) 79 go func() { 80 m.backendListen() 81 <-m.Channel 82 }() 83 return m 84 } 85 86 func (m *MonitorEvent) Close() error { 87 if m.Channel != nil { 88 close(m.Channel) 89 } 90 if m.watcher != nil { 91 return m.watcher.Close() 92 } 93 return nil 94 } 95 96 func (m *MonitorEvent) Watcher() *fsnotify.Watcher { 97 m.lock.Lock() 98 defer m.lock.Unlock() 99 if m.watcher == nil { 100 var err error 101 m.watcher, err = fsnotify.NewWatcher() 102 m.Channel = make(chan bool) 103 m.filters = []func(string) bool{} 104 if err != nil { 105 log.Panic(err) 106 } 107 } 108 return m.watcher 109 } 110 111 func (m *MonitorEvent) backendListen() *MonitorEvent { 112 go m.listen() 113 return m 114 } 115 116 func (m *MonitorEvent) AddDir(dir string) error { 117 f, err := os.Stat(dir) 118 if err != nil { 119 return err 120 } 121 if !f.IsDir() { 122 return errors.New(dir + ` is not dir.`) 123 } 124 err = filepath.Walk(dir, func(f string, info os.FileInfo, err error) error { 125 if err != nil { 126 return err 127 } 128 if info.IsDir() { 129 if m.Debug { 130 log.Println(`[Monitor]`, `Add Watch:`, f) 131 } 132 return m.Watcher().Add(f) 133 } 134 return nil 135 }) 136 return err 137 } 138 139 func (m *MonitorEvent) AddFile(file string) error { 140 if m.Debug { 141 log.Println(`[Monitor]`, `Add Watch:`, file) 142 } 143 return m.Watcher().Add(file) 144 } 145 146 func (m *MonitorEvent) Remove(fileOrDir string) error { 147 if m.watcher != nil { 148 return m.watcher.Remove(fileOrDir) 149 } 150 return nil 151 } 152 153 func (m *MonitorEvent) listen() { 154 for { 155 watcher := m.Watcher() 156 select { 157 case ev, ok := <-watcher.Events: 158 if !ok { 159 return 160 } 161 if m.Debug { 162 log.Println(`[Monitor]`, `Trigger Event:`, ev) 163 } 164 if m.filters != nil { 165 var skip bool 166 for _, filter := range m.filters { 167 if !filter(ev.Name) { 168 skip = true 169 break 170 } 171 } 172 if skip { 173 break 174 } 175 } 176 switch { 177 case ev.Op&fsnotify.Create == fsnotify.Create: 178 if m.IsDir(ev.Name) { 179 watcher.Add(ev.Name) 180 } 181 if m.Create != nil { 182 m.Create(ev.Name) 183 } 184 case ev.Op&fsnotify.Remove == fsnotify.Remove: 185 if m.IsDir(ev.Name) { 186 watcher.Remove(ev.Name) 187 } 188 if m.Delete != nil { 189 m.Delete(ev.Name) 190 } 191 case ev.Op&fsnotify.Write == fsnotify.Write: 192 if m.Modify != nil { 193 m.Modify(ev.Name) 194 } 195 case ev.Op&fsnotify.Rename == fsnotify.Rename: 196 watcher.Remove(ev.Name) 197 if m.Rename != nil { 198 m.Rename(ev.Name) 199 } 200 case ev.Op&fsnotify.Chmod == fsnotify.Chmod: 201 if m.Chmod != nil { 202 m.Chmod(ev.Name) 203 } 204 } 205 case err, ok := <-watcher.Errors: 206 if !ok { 207 return 208 } 209 if err != nil { 210 log.Println("Watcher error:", err) 211 } 212 } 213 } 214 } 215 216 func (m *MonitorEvent) IsDir(path string) bool { 217 d, e := os.Stat(path) 218 if e != nil { 219 return false 220 } 221 return d.IsDir() 222 } 223 224 //Monitor 文件监测 225 func Monitor(rootDir string, callback *MonitorEvent, args ...func(string) bool) error { 226 watcher := callback.Watcher() 227 defer watcher.Close() 228 callback.Watch(args...) 229 err := callback.AddDir(rootDir) 230 if err != nil { 231 callback.Close() 232 return err 233 } 234 return nil 235 }