Sfoglia il codice sorgente

:recycle: Adjust addRiffCards/removeRiffCards implementation to be asynchronous transaction https://github.com/siyuan-note/siyuan/issues/7936

Liang Ding 2 anni fa
parent
commit
3e14b4f29c
3 ha cambiato i file con 58 aggiunte e 104 eliminazioni
  1. 28 10
      kernel/api/riff.go
  2. 19 91
      kernel/model/flashcard.go
  3. 11 3
      kernel/model/transaction.go

+ 28 - 10
kernel/api/riff.go

@@ -216,13 +216,22 @@ func removeRiffCards(c *gin.Context) {
 	for _, blockID := range blockIDsArg {
 		blockIDs = append(blockIDs, blockID.(string))
 	}
-	err := model.RemoveFlashcardsByBlockIDs(deckID, blockIDs)
-	if nil != err {
-		ret.Code = -1
-		ret.Msg = err.Error()
-		return
+
+	transactions := []*model.Transaction{
+		{
+			DoOperations: []*model.Operation{
+				{
+					Action:   "removeFlashcards",
+					DeckID:   deckID,
+					BlockIDs: blockIDs,
+				},
+			},
+		},
 	}
 
+	model.PerformTransactions(&transactions)
+	model.WaitForWritingFiles()
+
 	if "" != deckID {
 		deck := model.Decks[deckID]
 		ret.Data = deckData(deck)
@@ -245,13 +254,22 @@ func addRiffCards(c *gin.Context) {
 	for _, blockID := range blockIDsArg {
 		blockIDs = append(blockIDs, blockID.(string))
 	}
-	err := model.AddFlashcards(deckID, blockIDs)
-	if nil != err {
-		ret.Code = -1
-		ret.Msg = err.Error()
-		return
+
+	transactions := []*model.Transaction{
+		{
+			DoOperations: []*model.Operation{
+				{
+					Action:   "addFlashcards",
+					DeckID:   deckID,
+					BlockIDs: blockIDs,
+				},
+			},
+		},
 	}
 
+	model.PerformTransactions(&transactions)
+	model.WaitForWritingFiles()
+
 	deck := model.Decks[deckID]
 	ret.Data = deckData(deck)
 }

+ 19 - 91
kernel/model/flashcard.go

@@ -456,95 +456,20 @@ func getAllDueFlashcards(reviewedCardIDs []string) (ret []*Flashcard) {
 	return
 }
 
-func RemoveFlashcardsByCardIDs(deckID string, cardIDs []string) (err error) {
+func (tx *Transaction) doRemoveFlashcards(operation *Operation) (ret *TxErr) {
 	deckLock.Lock()
 	defer deckLock.Unlock()
 
 	if syncingStorages {
-		err = errors.New(Conf.Language(81))
-		return
-	}
-
-	var needRemoveDeckAttrBlockIDs []string
-	if "" == deckID {
-		// 在 All 卡包中移除
-		var affectedBlockIDs []string
-		for _, deck := range Decks {
-			changed := false
-			for _, cardID := range cardIDs {
-				card := deck.GetCard(cardID)
-				if nil == card {
-					continue
-				}
-
-				affectedBlockIDs = append(affectedBlockIDs, card.BlockID())
-				deck.RemoveCard(cardID)
-				changed = true
-			}
-
-			if changed {
-				if err = deck.Save(); nil != err {
-					return
-				}
-			}
-
-			// 检查刚刚移除的卡片关联的块是否还存在更多关联的卡片
-			affectedBlockIDs = gulu.Str.RemoveDuplicatedElem(affectedBlockIDs)
-			for _, blockID := range affectedBlockIDs {
-				moreRelatedCards := deck.GetCardsByBlockID(blockID)
-				if 1 > len(moreRelatedCards) {
-					needRemoveDeckAttrBlockIDs = append(needRemoveDeckAttrBlockIDs, blockID)
-				}
-			}
-		}
-	} else {
-		// 在指定卡包中移除
-		deck := Decks[deckID]
-		if nil == deck {
-			return
-		}
-
-		var affectedBlockIDs []string
-		for _, cardID := range cardIDs {
-			card := deck.GetCard(cardID)
-			if nil == card {
-				continue
-			}
-
-			affectedBlockIDs = append(affectedBlockIDs, card.BlockID())
-			deck.RemoveCard(cardID)
-			if err = deck.Save(); nil != err {
-				return
-			}
-		}
-
-		// 检查刚刚移除的卡片关联的块是否还存在更多关联的卡片
-		affectedBlockIDs = gulu.Str.RemoveDuplicatedElem(affectedBlockIDs)
-		for _, blockID := range affectedBlockIDs {
-			moreRelatedCards := deck.GetCardsByBlockID(blockID)
-			if 1 > len(moreRelatedCards) {
-				needRemoveDeckAttrBlockIDs = append(needRemoveDeckAttrBlockIDs, blockID)
-			}
-		}
-	}
-
-	if err = removeBlocksDeckAttr(needRemoveDeckAttrBlockIDs, deckID); nil != err {
+		ret = &TxErr{code: TxErrCodeDataIsSyncing}
 		return
 	}
-	return
-}
-
-func RemoveFlashcardsByBlockIDs(deckID string, blockIDs []string) (err error) {
-	deckLock.Lock()
-	defer deckLock.Unlock()
 
-	if syncingStorages {
-		err = errors.New(Conf.Language(81))
-		return
-	}
+	deckID := operation.DeckID
+	blockIDs := operation.BlockIDs
 
-	if err = removeBlocksDeckAttr(blockIDs, deckID); nil != err {
-		return
+	if err := tx.removeBlocksDeckAttr(blockIDs, deckID); nil != err {
+		return &TxErr{code: TxErrCodeWriteTree, msg: err.Error(), id: deckID}
 	}
 
 	if "" == deckID { // 支持在 All 卡包中移除闪卡 https://github.com/siyuan-note/siyuan/issues/7425
@@ -557,7 +482,7 @@ func RemoveFlashcardsByBlockIDs(deckID string, blockIDs []string) (err error) {
 	return
 }
 
-func removeBlocksDeckAttr(blockIDs []string, deckID string) (err error) {
+func (tx *Transaction) removeBlocksDeckAttr(blockIDs []string, deckID string) (err error) {
 	var rootIDs []string
 	blockRoots := map[string]string{}
 	for _, blockID := range blockIDs {
@@ -577,7 +502,7 @@ func removeBlocksDeckAttr(blockIDs []string, deckID string) (err error) {
 
 		tree := trees[rootID]
 		if nil == tree {
-			tree, _ = loadTreeByBlockID(blockID)
+			tree, _ = tx.loadTree(blockID)
 		}
 		if nil == tree {
 			continue
@@ -612,7 +537,7 @@ func removeBlocksDeckAttr(blockIDs []string, deckID string) (err error) {
 			node.SetIALAttr("custom-riff-decks", val)
 		}
 
-		if err = indexWriteJSONQueue(tree); nil != err {
+		if err = tx.writeTree(tree); nil != err {
 			return
 		}
 
@@ -643,15 +568,18 @@ func removeFlashcardsByBlockIDs(blockIDs []string, deck *riff.Deck) {
 	}
 }
 
-func AddFlashcards(deckID string, blockIDs []string) (err error) {
+func (tx *Transaction) doAddFlashcards(operation *Operation) (ret *TxErr) {
 	deckLock.Lock()
 	defer deckLock.Unlock()
 
 	if syncingStorages {
-		err = errors.New(Conf.Language(81))
+		ret = &TxErr{code: TxErrCodeDataIsSyncing}
 		return
 	}
 
+	deckID := operation.DeckID
+	blockIDs := operation.BlockIDs
+
 	blockRoots := map[string]string{}
 	for _, blockID := range blockIDs {
 		bt := treenode.GetBlockTree(blockID)
@@ -668,7 +596,7 @@ func AddFlashcards(deckID string, blockIDs []string) (err error) {
 
 		tree := trees[rootID]
 		if nil == tree {
-			tree, _ = loadTreeByBlockID(blockID)
+			tree, _ = tx.loadTree(blockID)
 		}
 		if nil == tree {
 			continue
@@ -691,8 +619,8 @@ func AddFlashcards(deckID string, blockIDs []string) (err error) {
 		val = strings.TrimSuffix(val, ",")
 		node.SetIALAttr("custom-riff-decks", val)
 
-		if err = indexWriteJSONQueue(tree); nil != err {
-			return
+		if err := tx.writeTree(tree); nil != err {
+			return &TxErr{code: TxErrCodeWriteTree, msg: err.Error(), id: deckID}
 		}
 
 		cache.PutBlockIAL(blockID, parse.IAL2Map(node.KramdownIAL))
@@ -715,8 +643,8 @@ func AddFlashcards(deckID string, blockIDs []string) (err error) {
 		cardID := ast.NewNodeID()
 		deck.AddCard(cardID, blockID)
 	}
-	err = deck.Save()
-	if nil != err {
+
+	if err := deck.Save(); nil != err {
 		logging.LogErrorf("save deck [%s] failed: %s", deckID, err)
 		return
 	}

+ 11 - 3
kernel/model/transaction.go

@@ -155,6 +155,7 @@ func PerformTransactions(transactions *[]*Transaction) {
 
 const (
 	TxErrCodeBlockNotFound  = 0
+	TxErrCodeDataIsSyncing  = 1
 	TxErrCodeWriteTree      = 2
 	TxErrWriteAttributeView = 3
 )
@@ -208,7 +209,11 @@ func performTx(tx *Transaction) (ret *TxErr) {
 		case "unfoldHeading":
 			ret = tx.doUnfoldHeading(op)
 		case "setAttrs":
-			ret = tx.setAttrs(op)
+			ret = tx.doSetAttrs(op)
+		case "addFlashcards":
+			ret = tx.doAddFlashcards(op)
+		case "removeFlashcards":
+			ret = tx.doRemoveFlashcards(op)
 		case "insertAttrViewBlock":
 			ret = tx.doInsertAttrViewBlock(op)
 		case "removeAttrViewBlock":
@@ -927,7 +932,7 @@ func (tx *Transaction) doCreate(operation *Operation) (ret *TxErr) {
 	return
 }
 
-func (tx *Transaction) setAttrs(operation *Operation) (ret *TxErr) {
+func (tx *Transaction) doSetAttrs(operation *Operation) (ret *TxErr) {
 	id := operation.ID
 	tree, err := tx.loadTree(id)
 	if nil != err {
@@ -968,7 +973,7 @@ func (tx *Transaction) setAttrs(operation *Operation) (ret *TxErr) {
 		}
 	}
 
-	if err = indexWriteJSONQueue(tree); nil != err {
+	if err = tx.writeTree(tree); nil != err {
 		return
 	}
 	cache.PutBlockIAL(id, parse.IAL2Map(node.KramdownIAL))
@@ -1007,6 +1012,9 @@ type Operation struct {
 	PreviousID string      `json:"previousID"`
 	NextID     string      `json:"nextID"`
 	RetData    interface{} `json:"retData"`
+	BlockIDs   []string    `json:"blockIDs"`
+
+	DeckID string `json:"deckID"` // 用于添加/删除闪卡
 
 	SrcIDs []string `json:"srcIDs"` // 用于将块拖拽到属性视图中
 	Name   string   `json:"name"`   // 用于属性视图列名