mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-10-29 09:07:30 +08:00
145 lines
3.2 KiB
Go
145 lines
3.2 KiB
Go
package model
|
|
|
|
import (
|
|
. "github.com/mickael-kerjean/filestash/server/common"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type PathQuandidate struct {
|
|
Path string
|
|
Score int
|
|
}
|
|
|
|
func scoreBoostForPath(p string) int {
|
|
b := strings.ToLower(filepath.Base(p))
|
|
|
|
// some path are garbage we don't want to explore unless there's nothing else to do
|
|
if b == "node_modules" {
|
|
return -100
|
|
} else if strings.HasPrefix(b, ".") {
|
|
return -10
|
|
}
|
|
|
|
// not all path are equally interesting, we bump the score of what we thing is interesting
|
|
score := 0
|
|
if strings.Contains(b, "document") {
|
|
score += 3
|
|
} else if strings.Contains(b, "project") {
|
|
score += 3
|
|
} else if strings.Contains(b, "home") {
|
|
score += 3
|
|
} else if strings.Contains(b, "note") {
|
|
score += 3
|
|
}
|
|
return score
|
|
}
|
|
|
|
func scoreBoostForFilesInDirectory(f []os.FileInfo) int {
|
|
s := 0
|
|
for i:=0; i<len(f); i++ {
|
|
name := f[i].Name()
|
|
if f[i].IsDir() == false {
|
|
if strings.HasSuffix(name, ".org") {
|
|
s += 2
|
|
} else if strings.HasSuffix(name, ".pdf") {
|
|
s += 1
|
|
} else if strings.HasSuffix(name, ".doc") || strings.HasSuffix(name, ".docx") {
|
|
s += 1
|
|
} else if strings.HasSuffix(name, ".md") {
|
|
s += 1
|
|
} else if strings.HasSuffix(name, ".pdf") {
|
|
s += 1
|
|
}
|
|
}
|
|
if s > 4 {
|
|
return 4
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
func scoreBoostOnDepth(p string) int {
|
|
return - strings.Count(p, "/")
|
|
}
|
|
|
|
func SearchStateLess(app *App, path string, keyword string) []File {
|
|
files := make([]File, 0)
|
|
toVisit := []PathQuandidate{PathQuandidate{path, 0}}
|
|
MAX_SEARCH_TIME := 300 * time.Millisecond
|
|
|
|
for start := time.Now() ; time.Since(start) < MAX_SEARCH_TIME; {
|
|
if len(toVisit) == 0 {
|
|
return files
|
|
}
|
|
currentPath := toVisit[0]
|
|
if len(toVisit) == 0 {
|
|
toVisit = make([]PathQuandidate, 0)
|
|
} else {
|
|
toVisit = toVisit[1:]
|
|
}
|
|
|
|
// Ls on the directory
|
|
f, err := app.Backend.Ls(currentPath.Path)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
score1 := scoreBoostForFilesInDirectory(f)
|
|
for i:=0; i<len(f); i++ {
|
|
name := f[i].Name()
|
|
// keyword matching
|
|
isAMatch := true
|
|
for _, key := range strings.Split(keyword, " "){
|
|
if strings.Contains(strings.ToLower(name), strings.ToLower(key)) == false {
|
|
isAMatch = false
|
|
}
|
|
}
|
|
if isAMatch {
|
|
files = append(files, File{
|
|
FName: name,
|
|
FType: func() string {
|
|
if f[i].IsDir() {
|
|
return "directory"
|
|
}
|
|
return "file"
|
|
}(),
|
|
FSize: f[i].Size(),
|
|
FTime: f[i].ModTime().Unix() * 1000,
|
|
FPath: currentPath.Path + name,
|
|
})
|
|
}
|
|
|
|
// follow directories
|
|
fullpath := currentPath.Path + name + "/"
|
|
relativePath := strings.ToLower(strings.TrimSuffix(strings.TrimPrefix(fullpath, path), "/"))
|
|
score2 := scoreBoostOnDepth(relativePath) * 2
|
|
if f[i].IsDir() {
|
|
score := scoreBoostForPath(relativePath)
|
|
if score < 0 {
|
|
continue
|
|
}
|
|
score += score1
|
|
score += score2
|
|
score += currentPath.Score
|
|
t := make([]PathQuandidate, len(toVisit) + 1)
|
|
k := 0
|
|
for k=0; k<len(toVisit); k++{
|
|
if score > toVisit[k].Score {
|
|
break
|
|
}
|
|
t[k] = toVisit[k]
|
|
}
|
|
t[k] = PathQuandidate{fullpath, score}
|
|
for k=k+1; k<len(toVisit) + 1; k++ {
|
|
t[k] = toVisit[k - 1]
|
|
}
|
|
toVisit = t
|
|
}
|
|
}
|
|
}
|
|
return files
|
|
}
|