Browse Source

🧑‍💻 siyuan-note#12718 (#12723)

Misuzu2027 9 tháng trước cách đây
mục cha
commit
7afea33d36
4 tập tin đã thay đổi với 157 bổ sung15 xóa
  1. 24 0
      kernel/api/block.go
  2. 1 0
      kernel/api/router.go
  3. 52 15
      kernel/filesys/tree.go
  4. 80 0
      kernel/model/blockinfo.go

+ 24 - 0
kernel/api/block.go

@@ -278,6 +278,30 @@ func getDocInfo(c *gin.Context) {
 	ret.Data = info
 }
 
+func getDocsInfo(c *gin.Context) {
+	ret := gulu.Ret.NewResult()
+	defer c.JSON(http.StatusOK, ret)
+
+	arg, ok := util.JsonArg(c, ret)
+	if !ok {
+		return
+	}
+	idsArg := arg["ids"].([]interface{})
+	var ids []string
+	for _, id := range idsArg {
+		ids = append(ids, id.(string))
+	}
+	queryRefCount := arg["refCount"].(bool)
+	queryAv := arg["av"].(bool)
+	info := model.GetDocsInfo(ids, queryRefCount, queryAv)
+	if nil == info {
+		ret.Code = -1
+		ret.Msg = fmt.Sprintf(model.Conf.Language(15), ids)
+		return
+	}
+	ret.Data = info
+}
+
 func getRecentUpdatedBlocks(c *gin.Context) {
 	ret := gulu.Ret.NewResult()
 	defer c.JSON(http.StatusOK, ret)

+ 1 - 0
kernel/api/router.go

@@ -182,6 +182,7 @@ func ServeAPI(ginServer *gin.Engine) {
 	ginServer.Handle("POST", "/api/block/getContentWordCount", model.CheckAuth, getContentWordCount)
 	ginServer.Handle("POST", "/api/block/getRecentUpdatedBlocks", model.CheckAuth, getRecentUpdatedBlocks)
 	ginServer.Handle("POST", "/api/block/getDocInfo", model.CheckAuth, getDocInfo)
+	ginServer.Handle("POST", "/api/block/getDocsInfo", model.CheckAuth, getDocsInfo)
 	ginServer.Handle("POST", "/api/block/checkBlockExist", model.CheckAuth, checkBlockExist)
 	ginServer.Handle("POST", "/api/block/checkBlockFold", model.CheckAuth, checkBlockFold)
 	ginServer.Handle("POST", "/api/block/insertBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, insertBlock)

+ 52 - 15
kernel/filesys/tree.go

@@ -21,10 +21,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"os"
-	"path/filepath"
-	"strings"
-
 	"github.com/88250/lute"
 	"github.com/88250/lute/parse"
 	"github.com/88250/lute/render"
@@ -34,23 +30,39 @@ import (
 	"github.com/siyuan-note/siyuan/kernel/cache"
 	"github.com/siyuan-note/siyuan/kernel/treenode"
 	"github.com/siyuan-note/siyuan/kernel/util"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
 )
 
 func LoadTrees(ids []string) (ret map[string]*parse.Tree) {
-	ret, tmpCache := map[string]*parse.Tree{}, map[string]*parse.Tree{}
+	ret = map[string]*parse.Tree{}
 	bts := treenode.GetBlockTrees(ids)
 	luteEngine := util.NewLute()
-	for id, bt := range bts {
-		tree := tmpCache[bt.RootID]
-		if nil == tree {
-			tree, _ = LoadTree(bt.BoxID, bt.Path, luteEngine)
-			if nil == tree {
-				logging.LogWarnf("load tree [%s] failed: %s", id, bt.Path)
-				continue
-			}
-			tmpCache[bt.RootID] = tree
+	var boxIDs []string
+	var paths []string
+	seen := make(map[string]bool)
+	for _, bt := range bts {
+		key := bt.BoxID + bt.Path
+		if !seen[key] {
+			seen[key] = true
+			boxIDs = append(boxIDs, bt.BoxID)
+			paths = append(paths, bt.Path)
 		}
-		ret[id] = tree
+	}
+
+	trees, errs := BatchLoadTrees(boxIDs, paths, luteEngine)
+
+	for i := range trees {
+		tree := trees[i]
+		err := errs[i]
+		if err != nil || tree == nil {
+			logging.LogErrorf("load tree failed: %s", err)
+			continue
+		}
+
+		ret[tree.ID] = tree
 	}
 	return
 }
@@ -67,6 +79,31 @@ func LoadTree(boxID, p string, luteEngine *lute.Lute) (ret *parse.Tree, err erro
 	return
 }
 
+func BatchLoadTrees(boxIDs, paths []string, luteEngine *lute.Lute) ([]*parse.Tree, []error) {
+	var wg sync.WaitGroup
+	results := make([]*parse.Tree, len(paths))
+	errors := make([]error, len(paths))
+
+	for i := range paths {
+		wg.Add(1)
+		go func(i int) {
+			defer wg.Done()
+
+			boxID := boxIDs[i]
+			path := paths[i]
+
+			tree, err := LoadTree(boxID, path, luteEngine)
+
+			results[i] = tree
+			errors[i] = err
+		}(i)
+	}
+
+	wg.Wait()
+
+	return results, errors
+}
+
 func LoadTreeByData(data []byte, boxID, p string, luteEngine *lute.Lute) (ret *parse.Tree, err error) {
 	ret = parseJSON2Tree(boxID, p, data, luteEngine)
 	if nil == ret {

+ 80 - 0
kernel/model/blockinfo.go

@@ -17,6 +17,7 @@
 package model
 
 import (
+	"github.com/siyuan-note/siyuan/kernel/filesys"
 	"os"
 	"path/filepath"
 	"sort"
@@ -123,6 +124,85 @@ func GetDocInfo(blockID string) (ret *BlockInfo) {
 	return
 }
 
+func GetDocsInfo(blockIDs []string, queryRefCount bool, queryAv bool) (rets []*BlockInfo) {
+	WaitForWritingFiles()
+
+	trees := filesys.LoadTrees(blockIDs)
+	for _, blockID := range blockIDs {
+		tree := trees[blockID]
+		if nil == tree {
+			continue
+		}
+		title := tree.Root.IALAttr("title")
+		ret := &BlockInfo{ID: blockID, RootID: tree.Root.ID, Name: title}
+		ret.IAL = parse.IAL2Map(tree.Root.KramdownIAL)
+		scrollData := ret.IAL["scroll"]
+		if 0 < len(scrollData) {
+			scroll := map[string]interface{}{}
+			if parseErr := gulu.JSON.UnmarshalJSON([]byte(scrollData), &scroll); nil != parseErr {
+				logging.LogWarnf("parse scroll data [%s] failed: %s", scrollData, parseErr)
+				delete(ret.IAL, "scroll")
+			} else {
+				if zoomInId := scroll["zoomInId"]; nil != zoomInId {
+					if !treenode.ExistBlockTree(zoomInId.(string)) {
+						delete(ret.IAL, "scroll")
+					}
+				} else {
+					if startId := scroll["startId"]; nil != startId {
+						if !treenode.ExistBlockTree(startId.(string)) {
+							delete(ret.IAL, "scroll")
+						}
+					}
+					if endId := scroll["endId"]; nil != endId {
+						if !treenode.ExistBlockTree(endId.(string)) {
+							delete(ret.IAL, "scroll")
+						}
+					}
+				}
+			}
+		}
+		if queryRefCount {
+			ret.RefIDs, _ = sql.QueryRefIDsByDefID(blockID, false)
+			ret.RefCount = len(ret.RefIDs) // 填充块引计数
+		}
+
+		if queryAv {
+			// 填充属性视图角标 Display the database title on the block superscript https://github.com/siyuan-note/siyuan/issues/10545
+			avIDs := strings.Split(ret.IAL[av.NodeAttrNameAvs], ",")
+			for _, avID := range avIDs {
+				avName, getErr := av.GetAttributeViewName(avID)
+				if nil != getErr {
+					continue
+				}
+
+				if "" == avName {
+					avName = Conf.language(105)
+				}
+
+				attrView := &AttrView{ID: avID, Name: avName}
+				ret.AttrViews = append(ret.AttrViews, attrView)
+			}
+		}
+
+		var subFileCount int
+		boxLocalPath := filepath.Join(util.DataDir, tree.Box)
+		subFiles, err := os.ReadDir(filepath.Join(boxLocalPath, strings.TrimSuffix(tree.Path, ".sy")))
+		if err == nil {
+			for _, subFile := range subFiles {
+				if strings.HasSuffix(subFile.Name(), ".sy") {
+					subFileCount++
+				}
+			}
+		}
+		ret.SubFileCount = subFileCount
+		ret.Icon = tree.Root.IALAttr("icon")
+
+		rets = append(rets, ret)
+
+	}
+	return
+}
+
 func GetBlockRefText(id string) string {
 	bt := treenode.GetBlockTree(id)
 	if nil == bt {