206 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
package files
 | 
						|
 | 
						|
import (
 | 
						|
	"math/rand"
 | 
						|
	"path/filepath"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	sessionInProgress sync.Map
 | 
						|
	maxSearchResults  = 100
 | 
						|
)
 | 
						|
 | 
						|
func (si *Index) Search(search string, scope string, sourceSession string) ([]string, map[string]map[string]bool) {
 | 
						|
	// Remove slashes
 | 
						|
	scope = strings.TrimLeft(scope, "/")
 | 
						|
	scope = strings.TrimRight(scope, "/")
 | 
						|
	runningHash := generateRandomHash(4)
 | 
						|
	sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map
 | 
						|
	searchOptions := ParseSearch(search)
 | 
						|
	fileListTypes := make(map[string]map[string]bool)
 | 
						|
	matching := []string{}
 | 
						|
	count := 0
 | 
						|
	for _, searchTerm := range searchOptions.Terms {
 | 
						|
		if searchTerm == "" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		si.mu.Lock()
 | 
						|
		for dirName, dir := range si.Directories {
 | 
						|
			isDir := true
 | 
						|
			files := []string{}
 | 
						|
			for _, item := range dir.Items {
 | 
						|
				if !item.IsDir {
 | 
						|
					files = append(files, item.Name)
 | 
						|
				}
 | 
						|
			}
 | 
						|
			value, found := sessionInProgress.Load(sourceSession)
 | 
						|
			if !found || value != runningHash {
 | 
						|
				si.mu.Unlock()
 | 
						|
				return []string{}, map[string]map[string]bool{}
 | 
						|
			}
 | 
						|
			if count > maxSearchResults {
 | 
						|
				break
 | 
						|
			}
 | 
						|
			pathName := scopedPathNameFilter(dirName, scope, isDir)
 | 
						|
			if pathName == "" {
 | 
						|
				continue // path not matched
 | 
						|
			}
 | 
						|
			fileTypes := map[string]bool{}
 | 
						|
			si.mu.Unlock()
 | 
						|
			matches, fileType := si.containsSearchTerm(dirName, searchTerm, *searchOptions, isDir, fileTypes)
 | 
						|
			si.mu.Lock()
 | 
						|
			if matches {
 | 
						|
				fileListTypes[pathName] = fileType
 | 
						|
				matching = append(matching, pathName)
 | 
						|
				count++
 | 
						|
			}
 | 
						|
			isDir = false
 | 
						|
			for _, file := range files {
 | 
						|
				if file == "" {
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				value, found := sessionInProgress.Load(sourceSession)
 | 
						|
				if !found || value != runningHash {
 | 
						|
					return []string{}, map[string]map[string]bool{}
 | 
						|
				}
 | 
						|
 | 
						|
				if count > maxSearchResults {
 | 
						|
					break
 | 
						|
				}
 | 
						|
				fullName := strings.TrimLeft(pathName+file, "/")
 | 
						|
				fileTypes := map[string]bool{}
 | 
						|
				si.mu.Unlock()
 | 
						|
				matches, fileType := si.containsSearchTerm(fullName, searchTerm, *searchOptions, isDir, fileTypes)
 | 
						|
				si.mu.Lock()
 | 
						|
				if !matches {
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				fileListTypes[fullName] = fileType
 | 
						|
				matching = append(matching, fullName)
 | 
						|
				count++
 | 
						|
			}
 | 
						|
		}
 | 
						|
		si.mu.Unlock()
 | 
						|
	}
 | 
						|
	// Sort the strings based on the number of elements after splitting by "/"
 | 
						|
	sort.Slice(matching, func(i, j int) bool {
 | 
						|
		parts1 := strings.Split(matching[i], "/")
 | 
						|
		parts2 := strings.Split(matching[j], "/")
 | 
						|
		return len(parts1) < len(parts2)
 | 
						|
	})
 | 
						|
	return matching, fileListTypes
 | 
						|
}
 | 
						|
 | 
						|
func scopedPathNameFilter(pathName string, scope string, isDir bool) string {
 | 
						|
	pathName = strings.TrimLeft(pathName, "/")
 | 
						|
	pathName = strings.TrimRight(pathName, "/")
 | 
						|
	if strings.HasPrefix(pathName, scope) || scope == "" {
 | 
						|
		pathName = strings.TrimPrefix(pathName, scope)
 | 
						|
		pathName = strings.TrimLeft(pathName, "/")
 | 
						|
		if isDir {
 | 
						|
			pathName = pathName + "/"
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		pathName = "" // return not matched
 | 
						|
	}
 | 
						|
	return pathName
 | 
						|
}
 | 
						|
 | 
						|
func (si *Index) containsSearchTerm(pathName string, searchTerm string, options SearchOptions, isDir bool, fileTypes map[string]bool) (bool, map[string]bool) {
 | 
						|
	largerThan := int64(options.LargerThan) * 1024 * 1024
 | 
						|
	smallerThan := int64(options.SmallerThan) * 1024 * 1024
 | 
						|
	conditions := options.Conditions
 | 
						|
	fileName := filepath.Base(pathName)
 | 
						|
	adjustedPath := si.makeIndexPath(pathName, isDir)
 | 
						|
 | 
						|
	// Convert to lowercase if not exact match
 | 
						|
	if !conditions["exact"] {
 | 
						|
		fileName = strings.ToLower(fileName)
 | 
						|
		searchTerm = strings.ToLower(searchTerm)
 | 
						|
	}
 | 
						|
 | 
						|
	// Check if the file name contains the search term
 | 
						|
	if !strings.Contains(fileName, searchTerm) {
 | 
						|
		return false, map[string]bool{}
 | 
						|
	}
 | 
						|
 | 
						|
	// Initialize file size and fileTypes map
 | 
						|
	var fileSize int64
 | 
						|
	extension := filepath.Ext(fileName)
 | 
						|
 | 
						|
	// Collect file types
 | 
						|
	for _, k := range AllFiletypeOptions {
 | 
						|
		if IsMatchingType(extension, k) {
 | 
						|
			fileTypes[k] = true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	fileTypes["dir"] = isDir
 | 
						|
	// Get file info if needed for size-related conditions
 | 
						|
	if largerThan > 0 || smallerThan > 0 {
 | 
						|
		fileInfo, exists := si.GetMetadataInfo(adjustedPath)
 | 
						|
		if !exists {
 | 
						|
			return false, fileTypes
 | 
						|
		} else if !isDir {
 | 
						|
			// Look for specific file in ReducedItems
 | 
						|
			for _, item := range fileInfo.ReducedItems {
 | 
						|
				lower := strings.ToLower(item.Name)
 | 
						|
				if strings.Contains(lower, searchTerm) {
 | 
						|
					if item.Size == 0 {
 | 
						|
						return false, fileTypes
 | 
						|
					}
 | 
						|
					fileSize = item.Size
 | 
						|
					break
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			fileSize = fileInfo.Size
 | 
						|
		}
 | 
						|
		if fileSize == 0 {
 | 
						|
			return false, fileTypes
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Evaluate all conditions
 | 
						|
	for t, v := range conditions {
 | 
						|
		if t == "exact" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		switch t {
 | 
						|
		case "larger":
 | 
						|
			if largerThan > 0 {
 | 
						|
				if fileSize <= largerThan {
 | 
						|
					return false, fileTypes
 | 
						|
				}
 | 
						|
			}
 | 
						|
		case "smaller":
 | 
						|
			if smallerThan > 0 {
 | 
						|
				if fileSize >= smallerThan {
 | 
						|
					return false, fileTypes
 | 
						|
				}
 | 
						|
			}
 | 
						|
		default:
 | 
						|
			// Handle other file type conditions
 | 
						|
			notMatchType := v != fileTypes[t]
 | 
						|
			if notMatchType {
 | 
						|
				return false, fileTypes
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return true, fileTypes
 | 
						|
}
 | 
						|
 | 
						|
func generateRandomHash(length int) string {
 | 
						|
	const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
 | 
						|
	rand.New(rand.NewSource(time.Now().UnixNano()))
 | 
						|
	result := make([]byte, length)
 | 
						|
	for i := range result {
 | 
						|
		result[i] = charset[rand.Intn(len(charset))]
 | 
						|
	}
 | 
						|
	return string(result)
 | 
						|
}
 |