github.com/zhongdalu/gf@v1.0.0/g/os/gfsnotify/gfsnotify.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 provides a platform-independent interface for file system notifications.
     8  //
     9  // 文件监控.
    10  package gfsnotify
    11  
    12  import (
    13  	"errors"
    14  	"fmt"
    15  
    16  	"github.com/zhongdalu/gf/g/container/glist"
    17  	"github.com/zhongdalu/gf/g/container/gmap"
    18  	"github.com/zhongdalu/gf/g/container/gqueue"
    19  	"github.com/zhongdalu/gf/g/container/gtype"
    20  	"github.com/zhongdalu/gf/g/os/gcache"
    21  	"github.com/zhongdalu/gf/third/github.com/fsnotify/fsnotify"
    22  )
    23  
    24  // 监听管理对象
    25  type Watcher struct {
    26  	watcher   *fsnotify.Watcher // 底层fsnotify对象
    27  	events    *gqueue.Queue     // 过滤后的事件通知,不会出现重复事件
    28  	cache     *gcache.Cache     // 缓存对象,主要用于事件重复过滤
    29  	callbacks *gmap.StrAnyMap   // 注册的所有绝对路径(文件/目录)及其对应的回调函数列表map
    30  	closeChan chan struct{}     // 关闭事件
    31  }
    32  
    33  // 注册的监听回调方法
    34  type Callback struct {
    35  	Id        int                // 唯一ID
    36  	Func      func(event *Event) // 回调方法
    37  	Path      string             // 监听的文件/目录
    38  	elem      *glist.Element     // 指向回调函数链表中的元素项位置(便于删除)
    39  	recursive bool               // 当目录时,是否递归监听(使用在子文件/目录回溯查找回调函数时)
    40  }
    41  
    42  // 监听事件对象
    43  type Event struct {
    44  	event   fsnotify.Event // 底层事件对象
    45  	Path    string         // 文件绝对路径
    46  	Op      Op             // 触发监听的文件操作
    47  	Watcher *Watcher       // 事件对应的监听对象
    48  }
    49  
    50  // 按位进行识别的操作集合
    51  type Op uint32
    52  
    53  // 必须放到一个const分组里面
    54  const (
    55  	CREATE Op = 1 << iota
    56  	WRITE
    57  	REMOVE
    58  	RENAME
    59  	CHMOD
    60  )
    61  
    62  const (
    63  	REPEAT_EVENT_FILTER_INTERVAL = 1      // (毫秒)重复事件过滤间隔
    64  	gFSNOTIFY_EVENT_EXIT         = "exit" // 是否退出回调执行
    65  )
    66  
    67  var (
    68  	// 默认的Watcher对象
    69  	defaultWatcher, _ = New()
    70  	// 默认的watchers是否初始化,使用时才创建
    71  	watcherInited = gtype.NewBool()
    72  	// 回调方法ID与对象指针的映射哈希表,用于根据ID快速查找回调对象
    73  	callbackIdMap = gmap.NewIntAnyMap()
    74  	// 回调函数的ID生成器(原子操作)
    75  	callbackIdGenerator = gtype.NewInt()
    76  )
    77  
    78  // 创建监听管理对象,主要注意的是创建监听对象会占用系统的inotify句柄数量,受到 fs.inotify.max_user_instances 的限制
    79  func New() (*Watcher, error) {
    80  	w := &Watcher{
    81  		cache:     gcache.New(),
    82  		events:    gqueue.New(),
    83  		closeChan: make(chan struct{}),
    84  		callbacks: gmap.NewStrAnyMap(),
    85  	}
    86  	if watcher, err := fsnotify.NewWatcher(); err == nil {
    87  		w.watcher = watcher
    88  	} else {
    89  		return nil, err
    90  	}
    91  	w.startWatchLoop()
    92  	w.startEventLoop()
    93  	return w, nil
    94  }
    95  
    96  // 添加对指定文件/目录的监听,并给定回调函数;如果给定的是一个目录,默认递归监控。
    97  func Add(path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
    98  	return defaultWatcher.Add(path, callbackFunc, recursive...)
    99  }
   100  
   101  // 递归移除对指定文件/目录的所有监听回调
   102  func Remove(path string) error {
   103  	return defaultWatcher.Remove(path)
   104  }
   105  
   106  // 根据指定的回调函数ID,移出指定的inotify回调函数
   107  func RemoveCallback(callbackId int) error {
   108  	callback := (*Callback)(nil)
   109  	if r := callbackIdMap.Get(callbackId); r != nil {
   110  		callback = r.(*Callback)
   111  	}
   112  	if callback == nil {
   113  		return errors.New(fmt.Sprintf(`callback for id %d not found`, callbackId))
   114  	}
   115  	defaultWatcher.RemoveCallback(callbackId)
   116  	return nil
   117  }
   118  
   119  // 在回调方法中调用该方法退出回调注册
   120  func Exit() {
   121  	panic(gFSNOTIFY_EVENT_EXIT)
   122  }