transaction.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // SiYuan - Refactor your thinking
  2. // Copyright (c) 2020-present, b3log.org
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package api
  17. import (
  18. "fmt"
  19. "net/http"
  20. "strings"
  21. "time"
  22. "github.com/88250/gulu"
  23. "github.com/gin-gonic/gin"
  24. "github.com/siyuan-note/siyuan/kernel/model"
  25. "github.com/siyuan-note/siyuan/kernel/util"
  26. )
  27. func performTransactions(c *gin.Context) {
  28. start := time.Now()
  29. ret := gulu.Ret.NewResult()
  30. defer c.JSON(http.StatusOK, ret)
  31. arg, ok := util.JsonArg(c, ret)
  32. if !ok {
  33. return
  34. }
  35. trans := arg["transactions"]
  36. data, err := gulu.JSON.MarshalJSON(trans)
  37. if nil != err {
  38. ret.Code = -1
  39. ret.Msg = "parses request failed"
  40. return
  41. }
  42. if !util.IsBooted() {
  43. ret.Code = -1
  44. ret.Msg = fmt.Sprintf(model.Conf.Language(74), int(util.GetBootProgress()))
  45. ret.Data = map[string]interface{}{"closeTimeout": 5000}
  46. return
  47. }
  48. timestamp := int64(arg["reqId"].(float64))
  49. var transactions []*model.Transaction
  50. if err = gulu.JSON.UnmarshalJSON(data, &transactions); nil != err {
  51. ret.Code = -1
  52. ret.Msg = "parses request failed"
  53. return
  54. }
  55. for _, transaction := range transactions {
  56. transaction.Timestamp = timestamp
  57. }
  58. model.PerformTransactions(&transactions)
  59. ret.Data = transactions
  60. app := arg["app"].(string)
  61. session := arg["session"].(string)
  62. pushTransactions(app, session, transactions)
  63. if model.IsFoldHeading(&transactions) || model.IsUnfoldHeading(&transactions) || model.IsMoveOutlineHeading(&transactions) {
  64. if model.IsMoveOutlineHeading(&transactions) {
  65. if retData := transactions[0].DoOperations[0].RetData; nil != retData {
  66. util.PushReloadDoc(retData.(string))
  67. }
  68. }
  69. }
  70. elapsed := time.Now().Sub(start).Milliseconds()
  71. c.Header("Server-Timing", fmt.Sprintf("total;dur=%d", elapsed))
  72. }
  73. func pushTransactions(app, session string, transactions []*model.Transaction) {
  74. pushMode := util.PushModeBroadcastExcludeSelf
  75. if 0 < len(transactions) && 0 < len(transactions[0].DoOperations) {
  76. model.WaitForWritingFiles() // 等待文件写入完成,后续渲染才能读取到最新的数据
  77. action := transactions[0].DoOperations[0].Action
  78. isAttrViewTx := strings.Contains(strings.ToLower(action), "attrview")
  79. if isAttrViewTx && "setAttrViewName" != action {
  80. pushMode = util.PushModeBroadcast
  81. }
  82. }
  83. evt := util.NewCmdResult("transactions", 0, pushMode)
  84. evt.AppId = app
  85. evt.SessionId = session
  86. evt.Data = transactions
  87. for _, tx := range transactions {
  88. tx.WaitForCommit()
  89. }
  90. util.PushEvent(evt)
  91. }