github.com/gogf/gf/v2@v2.7.4/os/gspath/gspath_cache.go (about)

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