open_db_request.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. //go:build js && wasm
  2. // +build js,wasm
  3. package idb
  4. import (
  5. "context"
  6. "fmt"
  7. "log"
  8. "github.com/hack-pad/safejs"
  9. )
  10. // OpenDBRequest provides access to the results of requests to open or delete databases (performed using Factory.open and Factory.DeleteDatabase).
  11. type OpenDBRequest struct {
  12. *Request
  13. }
  14. // Upgrader is a function that can upgrade the given database from an old version to a new one.
  15. type Upgrader func(db *Database, oldVersion, newVersion uint) error
  16. func newOpenDBRequest(ctx context.Context, req *Request, upgrader Upgrader) (*OpenDBRequest, error) {
  17. ctx, cancel := context.WithCancel(ctx)
  18. err := req.ListenSuccess(ctx, func() {
  19. defer cancel()
  20. err := openDBListenSuccess(req)
  21. if err != nil {
  22. panic(err)
  23. }
  24. })
  25. if err != nil {
  26. return nil, err
  27. }
  28. upgrade, err := safejs.FuncOf(func(this safejs.Value, args []safejs.Value) interface{} {
  29. err := openDBUpgradeNeeded(req, upgrader, args)
  30. if err != nil {
  31. panic(err)
  32. }
  33. return nil
  34. })
  35. if err != nil {
  36. return nil, err
  37. }
  38. _, err = req.jsRequest.Call(addEventListener, "upgradeneeded", upgrade)
  39. if err != nil {
  40. return nil, tryAsDOMException(err)
  41. }
  42. go func() {
  43. <-ctx.Done()
  44. _, err := req.jsRequest.Call(removeEventListener, "upgradeneeded", upgrade)
  45. if err != nil {
  46. panic(err)
  47. }
  48. upgrade.Release()
  49. }()
  50. return &OpenDBRequest{req}, nil
  51. }
  52. func openDBListenSuccess(req *Request) error {
  53. jsDB, err := req.result()
  54. if err != nil {
  55. return err
  56. }
  57. versionChange, err := safejs.FuncOf(func(safejs.Value, []safejs.Value) interface{} {
  58. log.Println("Version change detected, closing DB...")
  59. _, closeErr := jsDB.Call("close")
  60. if closeErr != nil {
  61. log.Println("Error closing DB:", closeErr)
  62. }
  63. return nil
  64. })
  65. if err != nil {
  66. return err
  67. }
  68. _, err = jsDB.Call(addEventListener, "versionchange", versionChange)
  69. return tryAsDOMException(err)
  70. }
  71. func openDBUpgradeNeeded(req *Request, upgrader Upgrader, args []safejs.Value) error {
  72. event := args[0]
  73. jsDatabase, err := req.result()
  74. if err != nil {
  75. return err
  76. }
  77. db := wrapDatabase(jsDatabase)
  78. oldVersionValue, err := event.Get("oldVersion")
  79. if err != nil {
  80. return err
  81. }
  82. oldVersion, err := oldVersionValue.Int()
  83. if err != nil {
  84. return err
  85. }
  86. newVersionValue, err := event.Get("newVersion")
  87. if err != nil {
  88. return err
  89. }
  90. newVersion, err := newVersionValue.Int()
  91. if err != nil {
  92. return err
  93. }
  94. if oldVersion < 0 || newVersion < 0 {
  95. return fmt.Errorf("Unexpected negative oldVersion or newVersion: %d, %d", oldVersion, newVersion)
  96. }
  97. return upgrader(db, uint(oldVersion), uint(newVersion))
  98. }
  99. // Result returns the result of the request. If the request failed and the result is not available, an error is returned.
  100. func (o *OpenDBRequest) Result() (*Database, error) {
  101. db, err := o.Request.result()
  102. if err != nil {
  103. return nil, err
  104. }
  105. return wrapDatabase(db), nil
  106. }
  107. // Await waits for success or failure, then returns the results.
  108. func (o *OpenDBRequest) Await(ctx context.Context) (*Database, error) {
  109. db, err := o.Request.await(ctx)
  110. if err != nil {
  111. return nil, err
  112. }
  113. return wrapDatabase(db), nil
  114. }