transaction.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // SiYuan - Build Your Eternal Digital Garden
  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. "errors"
  19. "fmt"
  20. "net/http"
  21. "time"
  22. "github.com/88250/gulu"
  23. "github.com/gin-gonic/gin"
  24. "github.com/siyuan-note/filelock"
  25. "github.com/siyuan-note/logging"
  26. "github.com/siyuan-note/siyuan/kernel/model"
  27. "github.com/siyuan-note/siyuan/kernel/sql"
  28. "github.com/siyuan-note/siyuan/kernel/util"
  29. )
  30. func performTransactions(c *gin.Context) {
  31. start := time.Now()
  32. ret := gulu.Ret.NewResult()
  33. defer c.JSON(http.StatusOK, ret)
  34. arg, ok := util.JsonArg(c, ret)
  35. if !ok {
  36. return
  37. }
  38. trans := arg["transactions"]
  39. data, err := gulu.JSON.MarshalJSON(trans)
  40. if nil != err {
  41. ret.Code = -1
  42. ret.Msg = "parses request failed"
  43. return
  44. }
  45. if !util.IsBooted() {
  46. ret.Code = -1
  47. ret.Msg = fmt.Sprintf(model.Conf.Language(74), int(util.GetBootProgress()))
  48. ret.Data = map[string]interface{}{"closeTimeout": 5000}
  49. return
  50. }
  51. var transactions []*model.Transaction
  52. if err = gulu.JSON.UnmarshalJSON(data, &transactions); nil != err {
  53. ret.Code = -1
  54. ret.Msg = "parses request failed"
  55. return
  56. }
  57. if op := model.IsSetAttrs(&transactions); nil != op {
  58. attrs := map[string]string{}
  59. if err = gulu.JSON.UnmarshalJSON([]byte(op.Data.(string)), &attrs); nil != err {
  60. return
  61. }
  62. err = model.SetBlockAttrs(op.ID, attrs)
  63. } else {
  64. err = model.PerformTransactions(&transactions)
  65. }
  66. if errors.Is(err, filelock.ErrUnableAccessFile) {
  67. ret.Code = 1
  68. return
  69. }
  70. if nil != err {
  71. tx, txErr := sql.BeginTx()
  72. if nil != txErr {
  73. logging.LogFatalf("transaction failed: %s", txErr)
  74. return
  75. }
  76. sql.ClearBoxHash(tx)
  77. sql.CommitTx(tx)
  78. logging.LogFatalf("transaction failed: %s", err)
  79. return
  80. }
  81. ret.Data = transactions
  82. app := arg["app"].(string)
  83. session := arg["session"].(string)
  84. if model.IsFoldHeading(&transactions) || model.IsUnfoldHeading(&transactions) {
  85. model.WaitForWritingFiles()
  86. }
  87. pushTransactions(app, session, transactions)
  88. elapsed := time.Now().Sub(start).Milliseconds()
  89. c.Header("Server-Timing", fmt.Sprintf("total;dur=%d", elapsed))
  90. }
  91. func pushTransactions(app, session string, transactions []*model.Transaction) {
  92. evt := util.NewCmdResult("transactions", 0, util.PushModeBroadcastExcludeSelf, util.PushModeBroadcastExcludeSelf)
  93. evt.AppId = app
  94. evt.SessionId = session
  95. evt.Data = transactions
  96. util.PushEvent(evt)
  97. }