filebrowser/backend/index/indexing.go

143 lines
3.6 KiB
Go
Raw Normal View History

package index
import (
"log"
"os"
"slices"
"strings"
"sync"
"time"
"github.com/gtsteffaniak/filebrowser/settings"
)
const (
maxIndexSize = 1000
)
type Index struct {
Dirs []string
Files []string
}
var (
rootPath string = "/srv"
indexes Index
indexMutex sync.RWMutex
lastIndexed time.Time
)
func GetIndex() *Index {
return &indexes
}
func Initialize(intervalMinutes uint32) {
// Initialize the index
indexes = Index{
Dirs: make([]string, 0, maxIndexSize),
Files: make([]string, 0, maxIndexSize),
}
rootPath = settings.GlobalConfiguration.Server.Root
var numFiles, numDirs int
log.Println("Indexing files...")
lastIndexedStart := time.Now()
// Call the function to index files and directories
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
if err != nil {
log.Fatal(err)
}
lastIndexed = lastIndexedStart
go indexingScheduler(intervalMinutes)
log.Println("Successfully indexed files.")
log.Println("Files found :", totalNumFiles)
log.Println("Directories found :", totalNumDirs)
}
func indexingScheduler(intervalMinutes uint32) {
log.Printf("Indexing scheduler will run every %v minutes", intervalMinutes)
for {
indexes.Dirs = slices.Compact(indexes.Dirs)
indexes.Files = slices.Compact(indexes.Files)
time.Sleep(time.Duration(intervalMinutes) * time.Minute)
var numFiles, numDirs int
lastIndexedStart := time.Now()
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
if err != nil {
log.Fatal(err)
}
lastIndexed = lastIndexedStart
if totalNumFiles+totalNumDirs > 0 {
log.Println("re-indexing found changes and updated the index.")
}
}
}
func removeFromSlice(slice []string, target string) []string {
for i, s := range slice {
if s == target {
// Swap the target element with the last element
slice[i], slice[len(slice)-1] = slice[len(slice)-1], slice[i]
// Resize the slice to exclude the last element
slice = slice[:len(slice)-1]
break // Exit the loop, assuming there's only one target element
}
}
return slice
}
// Define a function to recursively index files and directories
func indexFiles(path string, numFiles *int, numDirs *int) (int, int, error) {
// Check if the current directory has been modified since last indexing
dir, err := os.Open(path)
if err != nil {
// directory must have been deleted, remove from index
indexes.Dirs = removeFromSlice(indexes.Dirs, path)
indexes.Files = removeFromSlice(indexes.Files, path)
}
defer dir.Close()
dirInfo, err := dir.Stat()
if err != nil {
return *numFiles, *numDirs, err
}
// Compare the last modified time of the directory with the last indexed time
if dirInfo.ModTime().Before(lastIndexed) {
return *numFiles, *numDirs, nil
}
// Read the directory contents
files, err := dir.Readdir(-1)
if err != nil {
return *numFiles, *numDirs, err
}
// Iterate over the files and directories
for _, file := range files {
if file.IsDir() {
*numDirs++
addToIndex(path, file.Name(), true)
_, _, err := indexFiles(path+"/"+file.Name(), numFiles, numDirs) // recursive
if err != nil {
log.Println("Could not index :", err)
}
} else {
*numFiles++
addToIndex(path, file.Name(), false)
}
}
return *numFiles, *numDirs, nil
}
func addToIndex(path string, fileName string, isDir bool) {
indexMutex.Lock()
defer indexMutex.Unlock()
path = strings.TrimPrefix(path, rootPath+"/")
path = strings.TrimSuffix(path, "/")
adjustedPath := path + "/" + fileName
if path == rootPath {
adjustedPath = fileName
}
if isDir {
indexes.Dirs = append(indexes.Dirs, adjustedPath)
} else {
indexes.Files = append(indexes.Files, adjustedPath)
}
}