2023-06-15 01:08:09 +00:00
|
|
|
package search
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2023-06-16 17:29:43 +00:00
|
|
|
"sync"
|
|
|
|
"sort"
|
2023-06-15 01:08:09 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2023-06-16 17:29:43 +00:00
|
|
|
var (
|
|
|
|
rootPath = "/srv" // DO NOT include trailing slash
|
|
|
|
indexes map[string][]string
|
|
|
|
mutex sync.RWMutex
|
|
|
|
lastIndexed time.Time
|
|
|
|
)
|
2023-06-15 01:08:09 +00:00
|
|
|
|
2023-06-15 15:30:49 +00:00
|
|
|
func InitializeIndex(intervalMinutes uint32) {
|
2023-06-15 01:08:09 +00:00
|
|
|
// Initialize the indexes map
|
2023-06-16 17:29:43 +00:00
|
|
|
indexes = make(map[string][]string)
|
|
|
|
var numFiles, numDirs int
|
2023-06-15 15:30:49 +00:00
|
|
|
log.Println("Indexing files...")
|
2023-06-16 17:29:43 +00:00
|
|
|
lastIndexedStart := time.Now()
|
2023-06-15 01:08:09 +00:00
|
|
|
// Call the function to index files and directories
|
2023-06-16 17:29:43 +00:00
|
|
|
totalNumFiles, totalNumDirs, err := indexFiles(rootPath,&numFiles,&numDirs)
|
2023-06-15 01:08:09 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2023-06-16 17:29:43 +00:00
|
|
|
lastIndexed = lastIndexedStart
|
2023-06-15 15:30:49 +00:00
|
|
|
go indexingScheduler(intervalMinutes)
|
|
|
|
log.Println("Successfully indexed files.")
|
2023-06-16 17:29:43 +00:00
|
|
|
log.Println("Files found :",totalNumFiles)
|
|
|
|
log.Println("Directories found :",totalNumDirs)
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 15:30:49 +00:00
|
|
|
func indexingScheduler(intervalMinutes uint32) {
|
2023-06-16 17:29:43 +00:00
|
|
|
log.Printf("Indexing scheduler will run every %v minutes",intervalMinutes)
|
2023-06-15 15:30:49 +00:00
|
|
|
for {
|
|
|
|
time.Sleep(time.Duration(intervalMinutes) * time.Minute)
|
2023-06-16 17:29:43 +00:00
|
|
|
var numFiles, numDirs int
|
|
|
|
lastIndexedStart := time.Now()
|
|
|
|
totalNumFiles, totalNumDirs, err := indexFiles(rootPath,&numFiles,&numDirs)
|
2023-06-15 15:30:49 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2023-06-16 17:29:43 +00:00
|
|
|
lastIndexed = lastIndexedStart
|
|
|
|
if totalNumFiles+totalNumDirs > 0 {
|
|
|
|
log.Println("re-indexing found changes and updated the index.")
|
|
|
|
}
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Define a function to recursively index files and directories
|
2023-06-16 17:29:43 +00:00
|
|
|
func indexFiles(path string, numFiles *int, numDirs *int) (int,int,error) {
|
2023-06-15 01:08:09 +00:00
|
|
|
// 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
|
|
|
|
delete(indexes, path)
|
|
|
|
}
|
|
|
|
defer dir.Close()
|
|
|
|
dirInfo, err := dir.Stat()
|
|
|
|
if err != nil {
|
2023-06-16 17:29:43 +00:00
|
|
|
return *numFiles,*numDirs,err
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
|
|
|
// Compare the last modified time of the directory with the last indexed time
|
2023-06-16 17:29:43 +00:00
|
|
|
if dirInfo.ModTime().Before(lastIndexed) {
|
|
|
|
return *numFiles,*numDirs,nil
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
|
|
|
// Read the directory contents
|
|
|
|
files, err := dir.Readdir(-1)
|
|
|
|
if err != nil {
|
2023-06-16 17:29:43 +00:00
|
|
|
return *numFiles,*numDirs,err
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
|
|
|
// Iterate over the files and directories
|
|
|
|
for _, file := range files {
|
|
|
|
if file.IsDir() {
|
2023-06-16 17:29:43 +00:00
|
|
|
*numDirs++
|
|
|
|
indexFiles(path+"/"+file.Name(),numFiles,numDirs)
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
2023-06-16 17:29:43 +00:00
|
|
|
*numFiles++
|
|
|
|
addToIndex(path, file.Name())
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
2023-06-16 17:29:43 +00:00
|
|
|
return *numFiles,*numDirs,nil
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
|
|
|
|
2023-06-16 17:29:43 +00:00
|
|
|
func addToIndex(path string, fileName string) {
|
|
|
|
mutex.Lock()
|
|
|
|
defer mutex.Unlock()
|
|
|
|
path = strings.TrimPrefix(path,rootPath+"/")
|
|
|
|
path = strings.TrimSuffix(path,"/")
|
|
|
|
if path == rootPath {
|
|
|
|
path = "/"
|
|
|
|
}
|
2023-06-15 01:08:09 +00:00
|
|
|
info, exists := indexes[path]
|
|
|
|
if !exists {
|
2023-06-16 17:29:43 +00:00
|
|
|
info = []string{}
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
2023-06-16 17:29:43 +00:00
|
|
|
info = append(info, fileName)
|
2023-06-15 01:08:09 +00:00
|
|
|
indexes[path] = info
|
|
|
|
}
|
|
|
|
|
2023-06-16 17:29:43 +00:00
|
|
|
func SearchAllIndexes(searchTerm string, scope string, files []string, dirs []string) ([]string, []string) {
|
|
|
|
mutex.RLock()
|
|
|
|
defer mutex.RUnlock()
|
|
|
|
|
|
|
|
var matchingFiles []string
|
|
|
|
var matchingDirs []string
|
|
|
|
|
2023-06-15 01:08:09 +00:00
|
|
|
// Iterate over the indexes
|
2023-06-16 17:29:43 +00:00
|
|
|
for dirName, v := range indexes {
|
|
|
|
searchItems := v
|
2023-06-15 01:08:09 +00:00
|
|
|
// Iterate over the path names
|
2023-06-15 15:30:49 +00:00
|
|
|
for _, pathName := range searchItems {
|
2023-06-16 17:29:43 +00:00
|
|
|
if dirName != "/" {
|
|
|
|
pathName = dirName+"/"+pathName
|
|
|
|
}
|
2023-06-15 01:08:09 +00:00
|
|
|
// Check if the path name contains the search term
|
2023-06-15 15:30:49 +00:00
|
|
|
if !containsSearchTerm(pathName, searchTerm) {
|
|
|
|
continue
|
|
|
|
}
|
2023-06-16 17:29:43 +00:00
|
|
|
pathName = scopedPathNameFilter(pathName, scope)
|
2023-06-15 15:30:49 +00:00
|
|
|
if pathName == "" {
|
|
|
|
continue
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
2023-06-16 17:29:43 +00:00
|
|
|
matchingFiles = append(matchingFiles, pathName)
|
|
|
|
}
|
|
|
|
// Check if the path name contains the search term
|
|
|
|
if !containsSearchTerm(dirName, searchTerm) {
|
|
|
|
continue
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
2023-06-16 17:29:43 +00:00
|
|
|
pathName := scopedPathNameFilter(dirName, scope)
|
|
|
|
if pathName == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
matchingDirs = append(matchingDirs, pathName)
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
2023-06-16 17:29:43 +00:00
|
|
|
|
|
|
|
// Sort the strings based on the number of elements after splitting by "/"
|
|
|
|
sort.Slice(matchingFiles, func(i, j int) bool {
|
|
|
|
parts1 := strings.Split(matchingFiles[i], "/")
|
|
|
|
parts2 := strings.Split(matchingFiles[j], "/")
|
|
|
|
return len(parts1) < len(parts2)
|
|
|
|
})
|
|
|
|
// Sort the strings based on the number of elements after splitting by "/"
|
|
|
|
sort.Slice(matchingDirs, func(i, j int) bool {
|
|
|
|
parts1 := strings.Split(matchingDirs[i], "/")
|
|
|
|
parts2 := strings.Split(matchingDirs[j], "/")
|
|
|
|
return len(parts1) < len(parts2)
|
|
|
|
})
|
|
|
|
|
|
|
|
// Copy the matching files and dirs to the final slices
|
|
|
|
files = append([]string{}, matchingFiles...)
|
|
|
|
dirs = append([]string{}, matchingDirs...)
|
|
|
|
|
|
|
|
return files, dirs
|
2023-06-15 01:08:09 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 15:30:49 +00:00
|
|
|
func scopedPathNameFilter(pathName string, scope string) string {
|
|
|
|
scope = strings.TrimPrefix(scope, "/")
|
|
|
|
if strings.HasPrefix(pathName, scope) {
|
|
|
|
pathName = strings.TrimPrefix(pathName, scope)
|
|
|
|
} else {
|
|
|
|
pathName = ""
|
|
|
|
}
|
|
|
|
return pathName
|
|
|
|
}
|
|
|
|
|
2023-06-15 01:08:09 +00:00
|
|
|
func containsSearchTerm(pathName string, searchTerm string) bool {
|
|
|
|
path := getLastPathComponent(pathName)
|
|
|
|
// Perform case-insensitive search
|
|
|
|
pathNameLower := strings.ToLower(path)
|
|
|
|
searchTermLower := strings.ToLower(searchTerm)
|
|
|
|
|
|
|
|
return strings.Contains(pathNameLower, searchTermLower)
|
|
|
|
}
|
|
|
|
func getLastPathComponent(path string) string {
|
|
|
|
// Use filepath.Base to extract the last component of the path
|
|
|
|
return filepath.Base(path)
|
|
|
|
}
|