gfsnotify.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Copyright 2018 gf Author(https://github.com/gogf/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/gogf/gf.
  6. // Package gfsnotify provides a platform-independent interface for file system notifications.
  7. package gfsnotify
  8. import (
  9. "errors"
  10. "fmt"
  11. "github.com/gogf/gf/container/gset"
  12. "github.com/gogf/gf/internal/intlog"
  13. "sync"
  14. "time"
  15. "github.com/fsnotify/fsnotify"
  16. "github.com/gogf/gf/container/glist"
  17. "github.com/gogf/gf/container/gmap"
  18. "github.com/gogf/gf/container/gqueue"
  19. "github.com/gogf/gf/container/gtype"
  20. "github.com/gogf/gf/os/gcache"
  21. )
  22. // Watcher is the monitor for file changes.
  23. type Watcher struct {
  24. watcher *fsnotify.Watcher // Underlying fsnotify object.
  25. events *gqueue.Queue // Used for internal event management.
  26. cache *gcache.Cache // Used for repeated event filter.
  27. nameSet *gset.StrSet // Used for AddOnce feature.
  28. callbacks *gmap.StrAnyMap // Path(file/folder) to callbacks mapping.
  29. closeChan chan struct{} // Used for watcher closing notification.
  30. }
  31. // Callback is the callback function for Watcher.
  32. type Callback struct {
  33. Id int // Unique id for callback object.
  34. Func func(event *Event) // Callback function.
  35. Path string // Bound file path (absolute).
  36. name string // Registered name for AddOnce.
  37. elem *glist.Element // Element in the callbacks of watcher.
  38. recursive bool // Is bound to path recursively or not.
  39. }
  40. // Event is the event produced by underlying fsnotify.
  41. type Event struct {
  42. event fsnotify.Event // Underlying event.
  43. Path string // Absolute file path.
  44. Op Op // File operation.
  45. Watcher *Watcher // Parent watcher.
  46. }
  47. // Op is the bits union for file operations.
  48. type Op uint32
  49. const (
  50. CREATE Op = 1 << iota
  51. WRITE
  52. REMOVE
  53. RENAME
  54. CHMOD
  55. )
  56. const (
  57. repeatEventFilterDuration = time.Millisecond // Duration for repeated event filter.
  58. callbackExitEventPanicStr = "exit" // Custom exit event for internal usage.
  59. )
  60. var (
  61. mu sync.Mutex // Mutex for concurrent safety of defaultWatcher.
  62. defaultWatcher *Watcher // Default watcher.
  63. callbackIdMap = gmap.NewIntAnyMap(true) // Id to callback mapping.
  64. callbackIdGenerator = gtype.NewInt() // Atomic id generator for callback.
  65. )
  66. // New creates and returns a new watcher.
  67. // Note that the watcher number is limited by the file handle setting of the system.
  68. // Eg: fs.inotify.max_user_instances system variable in linux systems.
  69. func New() (*Watcher, error) {
  70. w := &Watcher{
  71. cache: gcache.New(),
  72. events: gqueue.New(),
  73. nameSet: gset.NewStrSet(true),
  74. closeChan: make(chan struct{}),
  75. callbacks: gmap.NewStrAnyMap(true),
  76. }
  77. if watcher, err := fsnotify.NewWatcher(); err == nil {
  78. w.watcher = watcher
  79. } else {
  80. intlog.Printf("New watcher failed: %v", err)
  81. return nil, err
  82. }
  83. w.startWatchLoop()
  84. w.startEventLoop()
  85. return w, nil
  86. }
  87. // Add monitors <path> using default watcher with callback function <callbackFunc>.
  88. // The optional parameter <recursive> specifies whether monitoring the <path> recursively, which is true in default.
  89. func Add(path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
  90. w, err := getDefaultWatcher()
  91. if err != nil {
  92. return nil, err
  93. }
  94. return w.Add(path, callbackFunc, recursive...)
  95. }
  96. // AddOnce monitors <path> using default watcher with callback function <callbackFunc> only once using unique name <name>.
  97. // If AddOnce is called multiple times with the same <name> parameter, <path> is only added to monitor once. It returns error
  98. // if it's called twice with the same <name>.
  99. //
  100. // The optional parameter <recursive> specifies whether monitoring the <path> recursively, which is true in default.
  101. func AddOnce(name, path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
  102. w, err := getDefaultWatcher()
  103. if err != nil {
  104. return nil, err
  105. }
  106. return w.AddOnce(name, path, callbackFunc, recursive...)
  107. }
  108. // Remove removes all monitoring callbacks of given <path> from watcher recursively.
  109. func Remove(path string) error {
  110. w, err := getDefaultWatcher()
  111. if err != nil {
  112. return err
  113. }
  114. return w.Remove(path)
  115. }
  116. // RemoveCallback removes specified callback with given id from watcher.
  117. func RemoveCallback(callbackId int) error {
  118. w, err := getDefaultWatcher()
  119. if err != nil {
  120. return err
  121. }
  122. callback := (*Callback)(nil)
  123. if r := callbackIdMap.Get(callbackId); r != nil {
  124. callback = r.(*Callback)
  125. }
  126. if callback == nil {
  127. return errors.New(fmt.Sprintf(`callback for id %d not found`, callbackId))
  128. }
  129. w.RemoveCallback(callbackId)
  130. return nil
  131. }
  132. // Exit is only used in the callback function, which can be used to remove current callback
  133. // of itself from the watcher.
  134. func Exit() {
  135. panic(callbackExitEventPanicStr)
  136. }
  137. // getDefaultWatcher creates and returns the default watcher.
  138. // This is used for lazy initialization purpose.
  139. func getDefaultWatcher() (*Watcher, error) {
  140. mu.Lock()
  141. defer mu.Unlock()
  142. if defaultWatcher != nil {
  143. return defaultWatcher, nil
  144. }
  145. var err error
  146. defaultWatcher, err = New()
  147. return defaultWatcher, err
  148. }