139 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
package index
 | 
						|
 | 
						|
import (
 | 
						|
	"log"
 | 
						|
	"os"
 | 
						|
	"slices"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/gtsteffaniak/filebrowser/settings"
 | 
						|
)
 | 
						|
 | 
						|
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:  []string{},
 | 
						|
		Files: []string{},
 | 
						|
	}
 | 
						|
	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)
 | 
						|
	}
 | 
						|
}
 |