github.com/zhongdalu/gf@v1.0.0/g/os/gfsnotify/gfsnotify_watcher_loop.go (about)

     1  // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/zhongdalu/gf.
     6  
     7  package gfsnotify
     8  
     9  import (
    10  	"github.com/zhongdalu/gf/g/container/glist"
    11  )
    12  
    13  // 监听循环
    14  func (w *Watcher) startWatchLoop() {
    15  	go func() {
    16  		for {
    17  			select {
    18  			// 关闭事件
    19  			case <-w.closeChan:
    20  				return
    21  
    22  			// 监听事件
    23  			case ev := <-w.watcher.Events:
    24  				//fmt.Println("ev:", ev.String())
    25  				w.cache.SetIfNotExist(ev.String(), func() interface{} {
    26  					w.events.Push(&Event{
    27  						event:   ev,
    28  						Path:    ev.Name,
    29  						Op:      Op(ev.Op),
    30  						Watcher: w,
    31  					})
    32  					return struct{}{}
    33  				}, REPEAT_EVENT_FILTER_INTERVAL)
    34  
    35  			case <-w.watcher.Errors:
    36  				//fmt.Fprintf(os.Stderr, "[gfsnotify] error: %s\n", err.Error())
    37  			}
    38  		}
    39  	}()
    40  }
    41  
    42  // 获得文件路径的监听回调,包括层级的监听回调。
    43  func (w *Watcher) getCallbacks(path string) (callbacks []*Callback) {
    44  	// 首先检索path对应的回调函数
    45  	if v := w.callbacks.Get(path); v != nil {
    46  		for _, v := range v.(*glist.List).FrontAll() {
    47  			callback := v.(*Callback)
    48  			callbacks = append(callbacks, callback)
    49  		}
    50  	}
    51  	// 其次查找父级目录有无回调注册
    52  	dirPath := fileDir(path)
    53  	if v := w.callbacks.Get(dirPath); v != nil {
    54  		for _, v := range v.(*glist.List).FrontAll() {
    55  			callback := v.(*Callback)
    56  			callbacks = append(callbacks, callback)
    57  		}
    58  	}
    59  	// 最后回溯查找递归回调函数
    60  	for {
    61  		parentDirPath := fileDir(dirPath)
    62  		if parentDirPath == dirPath {
    63  			break
    64  		}
    65  		if v := w.callbacks.Get(parentDirPath); v != nil {
    66  			for _, v := range v.(*glist.List).FrontAll() {
    67  				callback := v.(*Callback)
    68  				if callback.recursive {
    69  					callbacks = append(callbacks, callback)
    70  				}
    71  			}
    72  		}
    73  		dirPath = parentDirPath
    74  	}
    75  	return
    76  }
    77  
    78  // 事件循环(核心逻辑)
    79  func (w *Watcher) startEventLoop() {
    80  	go func() {
    81  		for {
    82  			if v := w.events.Pop(); v != nil {
    83  				event := v.(*Event)
    84  				// 如果该路径一个回调也没有,那么没有必要执行后续逻辑,删除对该文件的监听
    85  				callbacks := w.getCallbacks(event.Path)
    86  				if len(callbacks) == 0 {
    87  					w.watcher.Remove(event.Path)
    88  					continue
    89  				}
    90  				switch {
    91  				// 如果是删除操作,那么需要判断是否文件真正不存在了,如果存在,那么将此事件认为“假删除”
    92  				case event.IsRemove():
    93  					if fileExists(event.Path) {
    94  						// 底层重新添加监控(不用担心重复添加)
    95  						w.watcher.Add(event.Path)
    96  						// 修改事件操作为重命名(相当于重命名为自身名称,最终名称没变)
    97  						event.Op = RENAME
    98  					}
    99  
   100  				// 如果是重命名操作,那么需要判断是否文件真正不存在了,如果存在,那么将此事件认为“假命名”
   101  				// (特别是某些编辑器在编辑文件时会先对文件RENAME再CHMOD)
   102  				case event.IsRename():
   103  					if fileExists(event.Path) {
   104  						// 底层有可能去掉了监控, 这里重新添加监控(不用担心重复添加)
   105  						w.watcher.Add(event.Path)
   106  						// 修改事件操作为修改属性
   107  						event.Op = CHMOD
   108  					}
   109  
   110  				// 创建文件/目录
   111  				case event.IsCreate():
   112  					// =========================================
   113  					// 注意这里只是添加底层监听,并没有注册任何的回调函数,
   114  					// 默认的回调函数为父级的递归回调
   115  					// =========================================
   116  					if fileIsDir(event.Path) {
   117  						// 递归添加
   118  						for _, subPath := range fileAllDirs(event.Path) {
   119  							if fileIsDir(subPath) {
   120  								w.watcher.Add(subPath)
   121  							}
   122  						}
   123  					} else {
   124  						// 添加文件监听
   125  						w.watcher.Add(event.Path)
   126  					}
   127  
   128  				}
   129  				// 执行回调处理,异步处理
   130  				for _, v := range callbacks {
   131  					go func(callback *Callback) {
   132  						defer func() {
   133  							// 是否退出监控
   134  							if err := recover(); err != nil {
   135  								switch err {
   136  								case gFSNOTIFY_EVENT_EXIT:
   137  									w.RemoveCallback(callback.Id)
   138  								default:
   139  									panic(err)
   140  								}
   141  							}
   142  						}()
   143  						callback.Func(event)
   144  					}(v)
   145  				}
   146  			} else {
   147  				break
   148  			}
   149  		}
   150  	}()
   151  }