filebrowser/backend/files/indexing.go

205 lines
5.1 KiB
Go
Raw Normal View History

package files
import (
"log"
"os"
2024-09-16 21:01:16 +00:00
"path/filepath"
"strings"
"sync"
"time"
"github.com/gtsteffaniak/filebrowser/settings"
)
type Index struct {
Root string
2024-11-21 00:15:30 +00:00
Directories map[string]*FileInfo
NumDirs int
NumFiles int
inProgress bool
LastIndexed time.Time
mu sync.RWMutex
}
var (
rootPath string = "/srv"
indexes []*Index
indexesMutex sync.RWMutex
)
func InitializeIndex(intervalMinutes uint32, schedule bool) {
if schedule {
go indexingScheduler(intervalMinutes)
}
}
func indexingScheduler(intervalMinutes uint32) {
if settings.Config.Server.Root != "" {
rootPath = settings.Config.Server.Root
}
si := GetIndex(rootPath)
for {
startTime := time.Now()
// Set the indexing flag to indicate that indexing is in progress
si.resetCount()
// Perform the indexing operation
2024-11-21 00:15:30 +00:00
err := si.indexFiles("/")
// Reset the indexing flag to indicate that indexing has finished
si.inProgress = false
// Update the LastIndexed time
si.LastIndexed = time.Now()
if err != nil {
log.Printf("Error during indexing: %v", err)
}
if si.NumFiles+si.NumDirs > 0 {
timeIndexedInSeconds := int(time.Since(startTime).Seconds())
log.Println("Successfully indexed files.")
log.Printf("Time spent indexing: %v seconds\n", timeIndexedInSeconds)
log.Printf("Files found: %v\n", si.NumFiles)
log.Printf("Directories found: %v\n", si.NumDirs)
}
// Sleep for the specified interval
time.Sleep(time.Duration(intervalMinutes) * time.Minute)
}
}
// Define a function to recursively index files and directories
2024-11-21 00:15:30 +00:00
func (si *Index) indexFiles(adjustedPath string) error {
realPath := strings.TrimRight(si.Root, "/") + adjustedPath
2024-10-07 22:44:53 +00:00
// Open the directory
2024-11-21 00:15:30 +00:00
dir, err := os.Open(realPath)
if err != nil {
2024-11-21 00:15:30 +00:00
si.RemoveDirectory(adjustedPath) // Remove if it can't be opened
2024-10-07 22:44:53 +00:00
return err
}
2024-10-07 22:44:53 +00:00
defer dir.Close()
dirInfo, err := dir.Stat()
if err != nil {
return err
}
2024-11-21 00:15:30 +00:00
// Skip directories that haven't been modified since the last index
2024-10-07 22:44:53 +00:00
if dirInfo.ModTime().Before(si.LastIndexed) {
return nil
}
2024-10-07 22:44:53 +00:00
// Read directory contents
files, err := dir.Readdir(-1)
if err != nil {
return err
}
2024-10-07 22:44:53 +00:00
var totalSize int64
var numDirs, numFiles int
2024-11-21 00:15:30 +00:00
fileInfos := []ReducedItem{}
dirInfos := map[string]*FileInfo{}
combinedPath := adjustedPath + "/"
if adjustedPath == "/" {
combinedPath = "/"
}
2024-11-21 00:15:30 +00:00
// Process each file and directory in the current directory
2024-10-07 22:44:53 +00:00
for _, file := range files {
2024-11-21 00:15:30 +00:00
itemInfo := &FileInfo{
2024-10-07 22:44:53 +00:00
ModTime: file.ModTime(),
}
2024-11-21 00:15:30 +00:00
if file.IsDir() {
itemInfo.Name = file.Name()
itemInfo.Path = combinedPath + file.Name()
// Recursively index the subdirectory
err := si.indexFiles(itemInfo.Path)
if err != nil {
log.Printf("Failed to index directory %s: %v", itemInfo.Path, err)
continue
}
// Fetch the metadata for the subdirectory after indexing
subDirInfo, exists := si.GetMetadataInfo(itemInfo.Path, true)
if exists {
itemInfo.Size = subDirInfo.Size
totalSize += subDirInfo.Size // Add subdirectory size to the total
}
dirInfos[itemInfo.Name] = itemInfo
2024-10-07 22:44:53 +00:00
numDirs++
} else {
2024-11-21 00:15:30 +00:00
itemInfo := &ReducedItem{
Name: file.Name(),
ModTime: file.ModTime(),
Size: file.Size(),
Mode: file.Mode(),
}
_ = itemInfo.detectType(combinedPath+file.Name(), true, false, false)
fileInfos = append(fileInfos, *itemInfo)
totalSize += itemInfo.Size
2024-10-07 22:44:53 +00:00
numFiles++
}
}
// Create FileInfo for the current directory
dirFileInfo := &FileInfo{
2024-11-21 00:15:30 +00:00
Path: adjustedPath,
Files: fileInfos,
Dirs: dirInfos,
Size: totalSize,
ModTime: dirInfo.ModTime(),
}
2024-10-07 22:44:53 +00:00
2024-11-21 00:15:30 +00:00
// Update the current directory metadata in the index
si.UpdateMetadata(dirFileInfo)
2024-10-07 22:44:53 +00:00
si.NumDirs += numDirs
si.NumFiles += numFiles
2024-11-21 00:15:30 +00:00
2024-10-07 22:44:53 +00:00
return nil
}
2024-11-21 00:15:30 +00:00
func (si *Index) makeIndexPath(subPath string) string {
if strings.HasPrefix(subPath, "./") {
subPath = strings.TrimPrefix(subPath, ".")
2024-10-07 22:44:53 +00:00
}
2024-11-21 00:15:30 +00:00
if strings.HasPrefix(subPath, ".") || si.Root == subPath {
return "/"
}
2024-09-16 21:01:16 +00:00
// clean path
subPath = strings.TrimSuffix(subPath, "/")
// remove index prefix
adjustedPath := strings.TrimPrefix(subPath, si.Root)
// remove trailing slash
adjustedPath = strings.TrimSuffix(adjustedPath, "/")
2024-10-07 22:44:53 +00:00
if !strings.HasPrefix(adjustedPath, "/") {
adjustedPath = "/" + adjustedPath
}
return adjustedPath
}
2024-11-21 00:15:30 +00:00
//func getParentPath(path string) string {
// // Trim trailing slash for consistency
// path = strings.TrimSuffix(path, "/")
// if path == "" || path == "/" {
// return "" // Root has no parent
// }
//
// lastSlash := strings.LastIndex(path, "/")
// if lastSlash == -1 {
// return "/" // Parent of a top-level directory
// }
// return path[:lastSlash]
//}
func (si *Index) recursiveUpdateDirSizes(parentDir string, childInfo *FileInfo, previousSize int64) {
childDirName := filepath.Base(childInfo.Path)
if parentDir == childDirName {
return
}
dir, exists := si.GetMetadataInfo(parentDir, true)
if !exists {
return
}
dir.Dirs[childDirName] = childInfo
newSize := dir.Size - previousSize + childInfo.Size
dir.Size += newSize
si.UpdateMetadata(dir)
dir, _ = si.GetMetadataInfo(parentDir, true)
si.recursiveUpdateDirSizes(filepath.Dir(parentDir), dir, newSize)
}