gspath_cache.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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 gspath implements file index and search for folders.
  7. //
  8. package gspath
  9. import (
  10. "runtime"
  11. "strings"
  12. "github.com/gogf/gf/os/gfile"
  13. "github.com/gogf/gf/os/gfsnotify"
  14. "github.com/gogf/gf/text/gstr"
  15. )
  16. // updateCacheByPath adds all files under <path> recursively.
  17. func (sp *SPath) updateCacheByPath(path string) {
  18. if sp.cache == nil {
  19. return
  20. }
  21. sp.addToCache(path, path)
  22. }
  23. // formatCacheName formats <name> with following rules:
  24. // 1. The separator is unified to char '/'.
  25. // 2. The name should be started with '/' (similar as HTTP URI).
  26. func (sp *SPath) formatCacheName(name string) string {
  27. if runtime.GOOS != "linux" {
  28. name = gstr.Replace(name, "\\", "/")
  29. }
  30. return "/" + strings.Trim(name, "./")
  31. }
  32. // nameFromPath converts <filePath> to cache name.
  33. func (sp *SPath) nameFromPath(filePath, rootPath string) string {
  34. name := gstr.Replace(filePath, rootPath, "")
  35. name = sp.formatCacheName(name)
  36. return name
  37. }
  38. // makeCacheValue formats <filePath> to cache value.
  39. func (sp *SPath) makeCacheValue(filePath string, isDir bool) string {
  40. if isDir {
  41. return filePath + "_D_"
  42. }
  43. return filePath + "_F_"
  44. }
  45. // parseCacheValue parses cache value to file path and type.
  46. func (sp *SPath) parseCacheValue(value string) (filePath string, isDir bool) {
  47. if value[len(value)-2 : len(value)-1][0] == 'F' {
  48. return value[:len(value)-3], false
  49. }
  50. return value[:len(value)-3], true
  51. }
  52. // addToCache adds an item to cache.
  53. // If <filePath> is a directory, it also adds its all sub files/directories recursively
  54. // to the cache.
  55. func (sp *SPath) addToCache(filePath, rootPath string) {
  56. // Add itself firstly.
  57. idDir := gfile.IsDir(filePath)
  58. sp.cache.SetIfNotExist(
  59. sp.nameFromPath(filePath, rootPath), sp.makeCacheValue(filePath, idDir),
  60. )
  61. // If it's a directory, it adds its all sub files/directories recursively.
  62. if idDir {
  63. if files, err := gfile.ScanDir(filePath, "*", true); err == nil {
  64. //fmt.Println("gspath add to cache:", filePath, files)
  65. for _, path := range files {
  66. sp.cache.SetIfNotExist(sp.nameFromPath(path, rootPath), sp.makeCacheValue(path, gfile.IsDir(path)))
  67. }
  68. } else {
  69. //fmt.Errorf(err.Error())
  70. }
  71. }
  72. }
  73. // addMonitorByPath adds gfsnotify monitoring recursively.
  74. // When the files under the directory are updated, the cache will be updated meanwhile.
  75. // Note that since the listener is added recursively, if you delete a directory, the files (including the directory)
  76. // under the directory will also generate delete events, which means it will generate N+1 events in total
  77. // if a directory deleted and there're N files under it.
  78. func (sp *SPath) addMonitorByPath(path string) {
  79. if sp.cache == nil {
  80. return
  81. }
  82. _, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {
  83. //glog.Debug(event.String())
  84. switch {
  85. case event.IsRemove():
  86. sp.cache.Remove(sp.nameFromPath(event.Path, path))
  87. case event.IsRename():
  88. if !gfile.Exists(event.Path) {
  89. sp.cache.Remove(sp.nameFromPath(event.Path, path))
  90. }
  91. case event.IsCreate():
  92. sp.addToCache(event.Path, path)
  93. }
  94. }, true)
  95. }
  96. // removeMonitorByPath removes gfsnotify monitoring of <path> recursively.
  97. func (sp *SPath) removeMonitorByPath(path string) {
  98. if sp.cache == nil {
  99. return
  100. }
  101. _ = gfsnotify.Remove(path)
  102. }