2021-01-17 21:46:25 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2019-03-12 00:24:31 +08:00
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
|
|
|
|
// Package gspath implements file index and search for folders.
|
2019-06-19 09:06:52 +08:00
|
|
|
//
|
2019-03-12 00:24:31 +08:00
|
|
|
|
|
|
|
package gspath
|
|
|
|
|
|
|
|
import (
|
2019-06-19 09:06:52 +08:00
|
|
|
"runtime"
|
|
|
|
"strings"
|
2019-07-29 21:01:19 +08:00
|
|
|
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/os/gfile"
|
|
|
|
"github.com/gogf/gf/v2/os/gfsnotify"
|
|
|
|
"github.com/gogf/gf/v2/text/gstr"
|
2019-03-12 00:24:31 +08:00
|
|
|
)
|
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// updateCacheByPath adds all files under `path` recursively.
|
2019-03-12 00:24:31 +08:00
|
|
|
func (sp *SPath) updateCacheByPath(path string) {
|
2019-06-14 10:35:12 +08:00
|
|
|
if sp.cache == nil {
|
|
|
|
return
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
sp.addToCache(path, path)
|
2019-03-12 00:24:31 +08:00
|
|
|
}
|
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// formatCacheName formats `name` with following rules:
|
2019-10-12 23:56:03 +08:00
|
|
|
// 1. The separator is unified to char '/'.
|
|
|
|
// 2. The name should be started with '/' (similar as HTTP URI).
|
2019-03-12 00:24:31 +08:00
|
|
|
func (sp *SPath) formatCacheName(name string) string {
|
2019-06-19 09:06:52 +08:00
|
|
|
if runtime.GOOS != "linux" {
|
|
|
|
name = gstr.Replace(name, "\\", "/")
|
|
|
|
}
|
|
|
|
return "/" + strings.Trim(name, "./")
|
2019-03-12 00:24:31 +08:00
|
|
|
}
|
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// nameFromPath converts `filePath` to cache name.
|
2019-03-12 00:24:31 +08:00
|
|
|
func (sp *SPath) nameFromPath(filePath, rootPath string) string {
|
2019-06-19 09:06:52 +08:00
|
|
|
name := gstr.Replace(filePath, rootPath, "")
|
|
|
|
name = sp.formatCacheName(name)
|
|
|
|
return name
|
2019-03-12 00:24:31 +08:00
|
|
|
}
|
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// makeCacheValue formats `filePath` to cache value.
|
2019-03-12 00:24:31 +08:00
|
|
|
func (sp *SPath) makeCacheValue(filePath string, isDir bool) string {
|
2019-06-19 09:06:52 +08:00
|
|
|
if isDir {
|
|
|
|
return filePath + "_D_"
|
|
|
|
}
|
|
|
|
return filePath + "_F_"
|
2019-03-12 00:24:31 +08:00
|
|
|
}
|
|
|
|
|
2019-10-12 23:56:03 +08:00
|
|
|
// parseCacheValue parses cache value to file path and type.
|
2019-03-12 00:24:31 +08:00
|
|
|
func (sp *SPath) parseCacheValue(value string) (filePath string, isDir bool) {
|
2019-06-19 09:06:52 +08:00
|
|
|
if value[len(value)-2 : len(value)-1][0] == 'F' {
|
|
|
|
return value[:len(value)-3], false
|
|
|
|
}
|
|
|
|
return value[:len(value)-3], true
|
2019-03-12 00:24:31 +08:00
|
|
|
}
|
|
|
|
|
2019-10-12 23:56:03 +08:00
|
|
|
// addToCache adds an item to cache.
|
2021-10-21 18:22:47 +08:00
|
|
|
// If `filePath` is a directory, it also adds its all sub files/directories recursively
|
2019-10-12 23:56:03 +08:00
|
|
|
// to the cache.
|
2019-03-12 00:24:31 +08:00
|
|
|
func (sp *SPath) addToCache(filePath, rootPath string) {
|
2019-10-12 23:56:03 +08:00
|
|
|
// Add itself firstly.
|
2019-06-19 09:06:52 +08:00
|
|
|
idDir := gfile.IsDir(filePath)
|
2019-10-12 23:56:03 +08:00
|
|
|
sp.cache.SetIfNotExist(
|
|
|
|
sp.nameFromPath(filePath, rootPath), sp.makeCacheValue(filePath, idDir),
|
|
|
|
)
|
|
|
|
// If it's a directory, it adds its all sub files/directories recursively.
|
2019-06-19 09:06:52 +08:00
|
|
|
if idDir {
|
|
|
|
if files, err := gfile.ScanDir(filePath, "*", true); err == nil {
|
|
|
|
//fmt.Println("gspath add to cache:", filePath, files)
|
|
|
|
for _, path := range files {
|
|
|
|
sp.cache.SetIfNotExist(sp.nameFromPath(path, rootPath), sp.makeCacheValue(path, gfile.IsDir(path)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-12 00:24:31 +08:00
|
|
|
}
|
|
|
|
|
2019-10-12 23:56:03 +08:00
|
|
|
// addMonitorByPath adds gfsnotify monitoring recursively.
|
|
|
|
// When the files under the directory are updated, the cache will be updated meanwhile.
|
|
|
|
// Note that since the listener is added recursively, if you delete a directory, the files (including the directory)
|
|
|
|
// under the directory will also generate delete events, which means it will generate N+1 events in total
|
|
|
|
// if a directory deleted and there're N files under it.
|
2019-03-12 00:24:31 +08:00
|
|
|
func (sp *SPath) addMonitorByPath(path string) {
|
2019-06-19 09:06:52 +08:00
|
|
|
if sp.cache == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
_, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
|
|
|
//glog.Debug(event.String())
|
|
|
|
switch {
|
|
|
|
case event.IsRemove():
|
|
|
|
sp.cache.Remove(sp.nameFromPath(event.Path, path))
|
2019-03-12 00:24:31 +08:00
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
case event.IsRename():
|
|
|
|
if !gfile.Exists(event.Path) {
|
|
|
|
sp.cache.Remove(sp.nameFromPath(event.Path, path))
|
|
|
|
}
|
2019-03-12 00:24:31 +08:00
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
case event.IsCreate():
|
|
|
|
sp.addToCache(event.Path, path)
|
|
|
|
}
|
|
|
|
}, true)
|
2019-03-12 00:24:31 +08:00
|
|
|
}
|
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// removeMonitorByPath removes gfsnotify monitoring of `path` recursively.
|
2019-03-12 00:24:31 +08:00
|
|
|
func (sp *SPath) removeMonitorByPath(path string) {
|
2019-06-19 09:06:52 +08:00
|
|
|
if sp.cache == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
_ = gfsnotify.Remove(path)
|
|
|
|
}
|