ソースを参照

:art: `/资源` 支持搜索未索引的文件 https://github.com/siyuan-note/siyuan/issues/5416

Liang Ding 3 年 前
コミット
4a64f5592f

+ 59 - 0
kernel/cache/asset.go

@@ -0,0 +1,59 @@
+// SiYuan - Build Your Eternal Digital Garden
+// Copyright (c) 2020-present, b3log.org
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+package cache
+
+import (
+	"io/fs"
+	"path/filepath"
+	"strings"
+	"sync"
+
+	"github.com/siyuan-note/siyuan/kernel/util"
+)
+
+type Asset struct {
+	HName   string `json:"hName"`
+	Path    string `json:"path"`
+	Updated int64  `json:"updated"`
+}
+
+var Assets = sync.Map{}
+
+func LoadAssets() {
+	Assets = sync.Map{}
+	assets := filepath.Join(util.DataDir, "assets")
+	filepath.Walk(assets, func(path string, info fs.FileInfo, err error) error {
+		if info.IsDir() {
+			if strings.HasPrefix(info.Name(), ".") {
+				return filepath.SkipDir
+			}
+			return nil
+		}
+		if strings.HasSuffix(info.Name(), ".sya") {
+			return nil
+		}
+
+		hName := util.RemoveID(info.Name())
+		path = filepath.ToSlash(strings.TrimPrefix(path, util.DataDir))[1:]
+		Assets.Store(path, &Asset{
+			HName:   hName,
+			Path:    path,
+			Updated: info.ModTime().UnixMilli(),
+		})
+		return nil
+	})
+}

+ 2 - 0
kernel/main.go

@@ -19,6 +19,7 @@
 package main
 
 import (
+	"github.com/siyuan-note/siyuan/kernel/cache"
 	"github.com/siyuan-note/siyuan/kernel/model"
 	"github.com/siyuan-note/siyuan/kernel/server"
 	"github.com/siyuan-note/siyuan/kernel/sql"
@@ -48,6 +49,7 @@ func main() {
 	go model.AutoFlushTx()
 	go sql.AutoFlushTreeQueue()
 	go treenode.AutoFlushBlockTree()
+	go cache.LoadAssets()
 	model.WatchAssets()
 	model.HandleSignal()
 }

+ 2 - 0
kernel/mobile/kernel.go

@@ -23,6 +23,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/siyuan-note/siyuan/kernel/cache"
 	"github.com/siyuan-note/siyuan/kernel/model"
 	"github.com/siyuan-note/siyuan/kernel/server"
 	"github.com/siyuan-note/siyuan/kernel/sql"
@@ -61,6 +62,7 @@ func StartKernel(container, appDir, workspaceDir, nativeLibDir, privateDataDir,
 		go model.AutoFlushTx()
 		go sql.AutoFlushTreeQueue()
 		go treenode.AutoFlushBlockTree()
+		go cache.LoadAssets()
 	}()
 }
 

+ 25 - 17
kernel/model/assets.go

@@ -37,6 +37,7 @@ import (
 	"github.com/gabriel-vasile/mimetype"
 	"github.com/siyuan-note/filelock"
 	"github.com/siyuan-note/httpclient"
+	"github.com/siyuan-note/siyuan/kernel/cache"
 	"github.com/siyuan-note/siyuan/kernel/search"
 	"github.com/siyuan-note/siyuan/kernel/sql"
 	"github.com/siyuan-note/siyuan/kernel/treenode"
@@ -161,25 +162,32 @@ func NetImg2LocalAssets(rootID string) (err error) {
 	return
 }
 
-type Asset struct {
-	HName string `json:"hName"`
-	Name  string `json:"name"`
-	Path  string `json:"path"`
-}
+func SearchAssetsByName(keyword string) (ret []*cache.Asset) {
+	ret = []*cache.Asset{}
 
-func SearchAssetsByName(keyword string) (ret []*Asset) {
-	ret = []*Asset{}
-	sqlAssets := sql.QueryAssetsByName(keyword)
-	for _, sqlAsset := range sqlAssets {
-		hName := util.RemoveID(sqlAsset.Name)
-		_, hName = search.MarkText(hName, keyword, 64, Conf.Search.CaseSensitive)
-		asset := &Asset{
-			HName: hName,
-			Name:  sqlAsset.Name,
-			Path:  sqlAsset.Path,
+	count := 0
+	cache.Assets.Range(func(k, v interface{}) bool {
+		asset := v.(*cache.Asset)
+		if !strings.Contains(strings.ToLower(asset.HName), strings.ToLower(keyword)) {
+			return true
 		}
-		ret = append(ret, asset)
-	}
+
+		_, hName := search.MarkText(asset.HName, keyword, 64, Conf.Search.CaseSensitive)
+		ret = append(ret, &cache.Asset{
+			HName:   hName,
+			Path:    asset.Path,
+			Updated: asset.Updated,
+		})
+		count++
+		if Conf.Search.Limit <= count {
+			return false
+		}
+		return true
+	})
+
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].Updated > ret[j].Updated
+	})
 	return
 }
 

+ 4 - 0
kernel/model/assets_watcher.go

@@ -23,6 +23,7 @@ import (
 	"time"
 
 	"github.com/fsnotify/fsnotify"
+	"github.com/siyuan-note/siyuan/kernel/cache"
 	"github.com/siyuan-note/siyuan/kernel/util"
 )
 
@@ -78,6 +79,9 @@ func watchAssets() {
 					// 外部修改已有资源文件后纳入云端同步 https://github.com/siyuan-note/siyuan/issues/4694
 					IncSync()
 				}
+
+				// 重新缓存资源文件,以便使用 /资源 搜索
+				cache.LoadAssets()
 			}
 		}
 	}()

+ 4 - 0
kernel/model/assets_watcher_darwin.go

@@ -23,6 +23,7 @@ import (
 	"time"
 
 	"github.com/radovskyb/watcher"
+	"github.com/siyuan-note/siyuan/kernel/cache"
 	"github.com/siyuan-note/siyuan/kernel/util"
 )
 
@@ -54,6 +55,9 @@ func watchAssets() {
 				if watcher.Write == event.Op {
 					IncSync()
 				}
+
+				// 重新缓存资源文件,以便使用 /资源 搜索
+				cache.LoadAssets()
 			case err, ok := <-assetsWatcher.Error:
 				if !ok {
 					return

+ 0 - 16
kernel/sql/aseet.go

@@ -93,22 +93,6 @@ func docTitleImgAsset(root *ast.Node) *Asset {
 	return nil
 }
 
-func QueryAssetsByName(name string) (ret []*Asset) {
-	ret = []*Asset{}
-	sqlStmt := "SELECT * FROM assets WHERE name LIKE ? GROUP BY id ORDER BY id DESC LIMIT 32"
-	rows, err := query(sqlStmt, "%"+name+"%")
-	if nil != err {
-		util.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
-		return
-	}
-	defer rows.Close()
-	for rows.Next() {
-		asset := scanAssetRows(rows)
-		ret = append(ret, asset)
-	}
-	return
-}
-
 func QueryAssetByHash(hash string) (ret *Asset) {
 	sqlStmt := "SELECT * FROM assets WHERE hash = ?"
 	row := queryRow(sqlStmt, hash)