gfsnotify_watcher_loop.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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
  7. import (
  8. "github.com/gogf/gf/container/glist"
  9. "github.com/gogf/gf/internal/intlog"
  10. )
  11. // startWatchLoop starts the loop for event listening fro underlying inotify monitor.
  12. func (w *Watcher) startWatchLoop() {
  13. go func() {
  14. for {
  15. select {
  16. // Close event.
  17. case <-w.closeChan:
  18. return
  19. // Event listening.
  20. case ev := <-w.watcher.Events:
  21. // Filter the repeated event in custom duration.
  22. w.cache.SetIfNotExist(ev.String(), func() (interface{}, error) {
  23. w.events.Push(&Event{
  24. event: ev,
  25. Path: ev.Name,
  26. Op: Op(ev.Op),
  27. Watcher: w,
  28. })
  29. return struct{}{}, nil
  30. }, repeatEventFilterDuration)
  31. case err := <-w.watcher.Errors:
  32. intlog.Error(err)
  33. }
  34. }
  35. }()
  36. }
  37. // getCallbacks searches and returns all callbacks with given <path>.
  38. // It also searches its parent for callbacks if they're recursive.
  39. func (w *Watcher) getCallbacks(path string) (callbacks []*Callback) {
  40. // Firstly add the callbacks of itself.
  41. if v := w.callbacks.Get(path); v != nil {
  42. for _, v := range v.(*glist.List).FrontAll() {
  43. callback := v.(*Callback)
  44. callbacks = append(callbacks, callback)
  45. }
  46. }
  47. // Secondly searches its parent for callbacks.
  48. dirPath := fileDir(path)
  49. if v := w.callbacks.Get(dirPath); v != nil {
  50. for _, v := range v.(*glist.List).FrontAll() {
  51. callback := v.(*Callback)
  52. if callback.recursive {
  53. callbacks = append(callbacks, callback)
  54. }
  55. }
  56. }
  57. // Lastly searches the parent recursively for callbacks.
  58. for {
  59. parentDirPath := fileDir(dirPath)
  60. if parentDirPath == dirPath {
  61. break
  62. }
  63. if v := w.callbacks.Get(parentDirPath); v != nil {
  64. for _, v := range v.(*glist.List).FrontAll() {
  65. callback := v.(*Callback)
  66. if callback.recursive {
  67. callbacks = append(callbacks, callback)
  68. }
  69. }
  70. }
  71. dirPath = parentDirPath
  72. }
  73. return
  74. }
  75. // startEventLoop is the core event handler.
  76. func (w *Watcher) startEventLoop() {
  77. go func() {
  78. for {
  79. if v := w.events.Pop(); v != nil {
  80. event := v.(*Event)
  81. // If there's no any callback of this path, it removes it from monitor.
  82. callbacks := w.getCallbacks(event.Path)
  83. if len(callbacks) == 0 {
  84. w.watcher.Remove(event.Path)
  85. continue
  86. }
  87. switch {
  88. case event.IsRemove():
  89. // It should check again the existence of the path.
  90. // It adds it back to the monitor if it still exists.
  91. if fileExists(event.Path) {
  92. // It adds the path back to monitor.
  93. // We need no worry about the repeat adding.
  94. if err := w.watcher.Add(event.Path); err != nil {
  95. intlog.Error(err)
  96. } else {
  97. intlog.Printf("fake remove event, watcher re-adds monitor for: %s", event.Path)
  98. }
  99. // Change the event to RENAME, which means it renames itself to its origin name.
  100. event.Op = RENAME
  101. }
  102. case event.IsRename():
  103. // It should check again the existence of the path.
  104. // It adds it back to the monitor if it still exists.
  105. // Especially Some editors might do RENAME and then CHMOD when it's editing file.
  106. if fileExists(event.Path) {
  107. // It might lost the monitoring for the path, so we add the path back to monitor.
  108. // We need no worry about the repeat adding.
  109. if err := w.watcher.Add(event.Path); err != nil {
  110. intlog.Error(err)
  111. } else {
  112. intlog.Printf("fake rename event, watcher re-adds monitor for: %s", event.Path)
  113. }
  114. // Change the event to CHMOD.
  115. event.Op = CHMOD
  116. }
  117. case event.IsCreate():
  118. // =========================================
  119. // Note that it here just adds the path to monitor without any callback registering,
  120. // because its parent already has the callbacks.
  121. // =========================================
  122. if fileIsDir(event.Path) {
  123. // If it's a folder, it then does adding recursively to monitor.
  124. for _, subPath := range fileAllDirs(event.Path) {
  125. if fileIsDir(subPath) {
  126. if err := w.watcher.Add(subPath); err != nil {
  127. intlog.Error(err)
  128. } else {
  129. intlog.Printf("folder creation event, watcher adds monitor for: %s", subPath)
  130. }
  131. }
  132. }
  133. } else {
  134. // If it's a file, it directly adds it to monitor.
  135. if err := w.watcher.Add(event.Path); err != nil {
  136. intlog.Error(err)
  137. } else {
  138. intlog.Printf("file creation event, watcher adds monitor for: %s", event.Path)
  139. }
  140. }
  141. }
  142. // Calling the callbacks in order.
  143. for _, v := range callbacks {
  144. go func(callback *Callback) {
  145. defer func() {
  146. if err := recover(); err != nil {
  147. switch err {
  148. case callbackExitEventPanicStr:
  149. w.RemoveCallback(callback.Id)
  150. default:
  151. panic(err)
  152. }
  153. }
  154. }()
  155. callback.Func(event)
  156. }(v)
  157. }
  158. } else {
  159. break
  160. }
  161. }
  162. }()
  163. }