Skip to content
Snippets Groups Projects
Commit a2c658ab authored by Jono Wenger's avatar Jono Wenger
Browse files

Merge remote-tracking branch 'origin/release' into XX-4382/databaseInWorker2

# Conflicts:
#	indexedDb/impl/channels/implementation.go
#	indexedDb/impl/channels/implementation_test.go
#	indexedDb/impl/channels/init.go
#	indexedDb/impl/dm/implementation.go
#	indexedDb/impl/dm/init.go
#	wasm/channels.go
parents b5a3d7fa a0a0de3c
No related branches found
No related tags found
2 merge requests!67fix for latest client release,!52XX-4382 / Move indexedDb databases to web workers
......@@ -20,7 +20,6 @@ stages:
- test
- build
- tag
- version_check
- doc-update
- version_check
......
......@@ -7,8 +7,8 @@ require (
github.com/hack-pad/go-indexeddb v0.2.0
github.com/pkg/errors v0.9.1
github.com/spf13/jwalterweatherman v1.1.0
gitlab.com/elixxir/client/v4 v4.3.12-0.20230111204451-42f3876835cc
gitlab.com/elixxir/crypto v0.0.7-0.20230109232445-64f3e6192c3a
gitlab.com/elixxir/client/v4 v4.3.12-0.20230113154924-09ab9d5f0387
gitlab.com/elixxir/crypto v0.0.7-0.20230113153754-4be32f0a0a89
gitlab.com/elixxir/primitives v0.0.3-0.20230109222259-f62b2a90b62c
gitlab.com/xx_network/crypto v0.0.5-0.20230109222209-557b66d73c33
gitlab.com/xx_network/primitives v0.0.4-0.20221219230308-4b5550a9247d
......@@ -18,35 +18,25 @@ require (
require (
filippo.io/edwards25519 v1.0.0 // indirect
git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221221204132-2ed1fec765f1 // indirect
github.com/agnivade/wasmbrowsertest v0.6.0 // indirect
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
github.com/badoux/checkmail v1.2.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/chromedp/cdproto v0.0.0-20221108233440-fad8339618ab // indirect
github.com/chromedp/chromedp v0.8.6 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/cloudflare/circl v1.2.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/elliotchance/orderedmap v1.4.0 // indirect
github.com/forPelevin/gomoji v1.1.8 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-interpreter/wagon v0.6.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/pprof v0.0.0-20221103000818-d260c55eee4c // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.11.7 // indirect
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
......
......@@ -548,6 +548,18 @@ gitlab.com/elixxir/client/v4 v4.3.12-0.20230111011720-685725612575 h1:ArQqykxDAq
gitlab.com/elixxir/client/v4 v4.3.12-0.20230111011720-685725612575/go.mod h1:03CuoZNfVcZAbD0IrX/FxOMMwaKUWCMeMWE6781ZDIg=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230111204451-42f3876835cc h1:c+h+mq8ouaCpUbgjAdvCtlk3zZAvxW4GhyePzHbpocc=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230111204451-42f3876835cc/go.mod h1:03CuoZNfVcZAbD0IrX/FxOMMwaKUWCMeMWE6781ZDIg=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230112174912-de174933d587 h1:kdG+nQlSaPOmSEe/YvVK3fria8OZj/bHpZEO4aBXr8M=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230112174912-de174933d587/go.mod h1:hx/wYHaAvX9hse9vUWIzE/4IqWFFMbCDMPuGQAaAGDQ=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230112175132-70ac938c67eb h1:B86ZcS4AdozJlY/GNuzivHjOSPYS3rebqiAwH59yXqI=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230112175132-70ac938c67eb/go.mod h1:hx/wYHaAvX9hse9vUWIzE/4IqWFFMbCDMPuGQAaAGDQ=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230112205052-fc2a77781cff h1:uWWdqP2ZpwabVdrNHxz5l7u607vk7ATD5QVzy5kgkvU=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230112205052-fc2a77781cff/go.mod h1:nWdt+YuNQ5T5LhshVpAuVnYqaVASCFMIyFgG2h8V+is=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230112234243-43cd8e0f61df h1:pq6pT5m4TivgDZNyZdqpK0G/iNeQnBCK4U9kh/arjFE=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230112234243-43cd8e0f61df/go.mod h1:ohWuyRXcETnCnx8X1+WNQhh70wqLd9GQYQVD0YaKW+4=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230113004731-2099bf23f6b7 h1:uafHvqWkuAe/0/TLe/mi14uCE1utOxk3/vBwV32QzCs=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230113004731-2099bf23f6b7/go.mod h1:ohWuyRXcETnCnx8X1+WNQhh70wqLd9GQYQVD0YaKW+4=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230113154924-09ab9d5f0387 h1:EEJ2MOgGzGcu/Pr6xPBFBLPZDPowShPCsyD0sTRmC2Q=
gitlab.com/elixxir/client/v4 v4.3.12-0.20230113154924-09ab9d5f0387/go.mod h1:akit+kacZtAbLxE6DkOJDAy8LfYOw2gy385IQJyDWCY=
gitlab.com/elixxir/comms v0.0.4-0.20230109184457-e10f20295430 h1:OydFdoBbLz5iFzCiYEb+m8Q2pZjdVVCne4m+MyFAzUc=
gitlab.com/elixxir/comms v0.0.4-0.20230109184457-e10f20295430/go.mod h1:aFnxDpIxEEFHdAa2dEeydzo00u/IAcfrqPSEnmeffbY=
gitlab.com/elixxir/comms v0.0.4-0.20230109233320-a0c90d3324a0 h1:jMmI+j4P5e+nmf82xKs679M6EzeuUhQJjOwXhXi6Cl0=
......@@ -556,6 +568,14 @@ gitlab.com/elixxir/crypto v0.0.7-0.20230109182503-bd51c95bdcb3 h1:5au07K9R4K4RMR
gitlab.com/elixxir/crypto v0.0.7-0.20230109182503-bd51c95bdcb3/go.mod h1:7whUm4bnEdEoiVfMnu3TbHgvlrz0Ywp/Tekqg2Wl7vw=
gitlab.com/elixxir/crypto v0.0.7-0.20230109232445-64f3e6192c3a h1:XjE1WZk9DDyw2Rb7p14PWdlpMmsQJFkKVRcMpgMakUQ=
gitlab.com/elixxir/crypto v0.0.7-0.20230109232445-64f3e6192c3a/go.mod h1:5RnVcYvjX6Q0+2Rg/PcWgqJSrhOHgzw14YLbd0AshjE=
gitlab.com/elixxir/crypto v0.0.7-0.20230112173817-b922d4a512ed h1:P5wgqwsvnEMJVnerv7dZ/zP0FcjrqJ9zZRaC9N4XEEo=
gitlab.com/elixxir/crypto v0.0.7-0.20230112173817-b922d4a512ed/go.mod h1:T+uRZRqDdf9C8+VLGNY3mrCoWuoctfzxFlO+XNorIxM=
gitlab.com/elixxir/crypto v0.0.7-0.20230112203618-74f75155c930 h1:28Meq1azAIm96QlPnGKr+hVH/PPF91u9tnhyNivXf/4=
gitlab.com/elixxir/crypto v0.0.7-0.20230112203618-74f75155c930/go.mod h1:T+uRZRqDdf9C8+VLGNY3mrCoWuoctfzxFlO+XNorIxM=
gitlab.com/elixxir/crypto v0.0.7-0.20230112220617-8ac1fa200509 h1:SXHXgaI0dLies9w+nJ26RbMb8Wz+4TzH5gGiJA4scwc=
gitlab.com/elixxir/crypto v0.0.7-0.20230112220617-8ac1fa200509/go.mod h1:T+uRZRqDdf9C8+VLGNY3mrCoWuoctfzxFlO+XNorIxM=
gitlab.com/elixxir/crypto v0.0.7-0.20230113153754-4be32f0a0a89 h1:esw3acCVQDJiRGjtYM5oJ+3mPbGY/eJHcyXn7h3Khzg=
gitlab.com/elixxir/crypto v0.0.7-0.20230113153754-4be32f0a0a89/go.mod h1:T+uRZRqDdf9C8+VLGNY3mrCoWuoctfzxFlO+XNorIxM=
gitlab.com/elixxir/ekv v0.2.1 h1:dtwbt6KmAXG2Tik5d60iDz2fLhoFBgWwST03p7T+9Is=
gitlab.com/elixxir/ekv v0.2.1/go.mod h1:USLD7xeDnuZEavygdrgzNEwZXeLQJK/w1a+htpN+JEU=
gitlab.com/elixxir/primitives v0.0.3-0.20221214192222-988b44a6958a h1:F17FfEjS+/uDI/TTYQD21S5JvNZ9+p9bieau2nyLCzo=
......
......@@ -13,7 +13,6 @@ import (
"crypto/ed25519"
"encoding/base64"
"encoding/json"
"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
"strings"
"sync"
"syscall/js"
......@@ -28,6 +27,7 @@ import (
cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
cryptoChannel "gitlab.com/elixxir/crypto/channel"
"gitlab.com/elixxir/crypto/message"
"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
"gitlab.com/elixxir/xxdk-wasm/utils"
"gitlab.com/xx_network/primitives/id"
)
......@@ -39,6 +39,8 @@ type wasmModel struct {
db *idb.Database
cipher cryptoChannel.Cipher
receivedMessageCB MessageReceivedCallback
deletedMessageCB DeletedMessageCallback
mutedUserCB MutedUserCallback
updateMux sync.Mutex
}
......@@ -79,7 +81,7 @@ func (w *wasmModel) LeaveChannel(channelID *id.ID) {
parentErr := errors.New("failed to LeaveChannel")
// Delete the channel from storage
err := impl.Delete(w.db, channelsStoreName,
err := indexedDb.Delete(w.db, channelsStoreName,
js.ValueOf(channelID.String()))
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
......@@ -488,8 +490,22 @@ func (w *wasmModel) GetMessage(
// DeleteMessage removes a message with the given messageID from storage.
func (w *wasmModel) DeleteMessage(messageID message.ID) error {
msgId := js.ValueOf(base64.StdEncoding.EncodeToString(messageID.Bytes()))
return impl.DeleteIndex(w.db, messageStoreName,
messageStoreMessageIndex, pkeyName, msgId)
err := impl.DeleteIndex(
w.db, messageStoreName, messageStoreMessageIndex, pkeyName, msgId)
if err != nil {
return err
}
go w.deletedMessageCB(messageID)
return nil
}
// MuteUser is called whenever a user is muted or unmuted.
func (w *wasmModel) MuteUser(
channelID *id.ID, pubKey ed25519.PublicKey, unmute bool) {
go w.mutedUserCB(channelID, pubKey, unmute)
}
// msgIDLookup gets the UUID of the Message with the given messageID.
......@@ -510,5 +526,4 @@ func (w *wasmModel) msgIDLookup(messageID message.ID) (*Message, error) {
return nil, err
}
return resultMsg, nil
}
......@@ -10,25 +10,27 @@
package main
import (
"crypto/ed25519"
"encoding/json"
"fmt"
"github.com/hack-pad/go-indexeddb/idb"
"gitlab.com/elixxir/crypto/message"
"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
"gitlab.com/elixxir/xxdk-wasm/storage"
"gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/primitives/netTime"
"os"
"strconv"
"testing"
"time"
"github.com/hack-pad/go-indexeddb/idb"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/v4/channels"
"gitlab.com/elixxir/client/v4/cmix/rounds"
cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
cryptoChannel "gitlab.com/elixxir/crypto/channel"
"gitlab.com/elixxir/crypto/message"
"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
"gitlab.com/elixxir/xxdk-wasm/storage"
"gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/netTime"
)
func TestMain(m *testing.M) {
......@@ -36,14 +38,10 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}
func dummyCallback(uint64, *id.ID, bool) {}
// dummyStoreDatabaseName always returns nil error and adheres to the
// storeDatabaseNameFn type.
func dummyReceivedMessageCB(uint64, *id.ID, bool) {}
func dummyDeletedMessageCB(message.ID) {}
func dummyMutedUserCB(*id.ID, ed25519.PublicKey, bool) {}
func dummyStoreDatabaseName(string) error { return nil }
// dummyStoreEncryptionStatus returns the same encryption status passed into it
// and adheres to the storeEncryptionStatusFn type.
func dummyStoreEncryptionStatus(_ string, encryptionStatus bool) (bool, error) {
return encryptionStatus, nil
}
......@@ -66,7 +64,8 @@ func TestWasmModel_msgIDLookup(t *testing.T) {
testString := "TestWasmModel_msgIDLookup" + cs
testMsgId := message.DeriveChannelMessageID(&id.ID{1}, 0, []byte(testString))
eventModel, err2 := newWASMModel(testString, c, dummyCallback,
eventModel, err2 := newWASMModel(testString, c,
dummyReceivedMessageCB, dummyDeletedMessageCB, dummyMutedUserCB,
dummyStoreDatabaseName, dummyStoreEncryptionStatus)
if err2 != nil {
t.Fatal(err2)
......@@ -96,8 +95,9 @@ func TestWasmModel_DeleteMessage(t *testing.T) {
storage.GetLocalStorage().Clear()
testString := "TestWasmModel_DeleteMessage"
testMsgId := message.DeriveChannelMessageID(&id.ID{1}, 0, []byte(testString))
eventModel, err := newWASMModel(testString, nil, dummyCallback,
dummyStoreDatabaseName, dummyStoreEncryptionStatus)
eventModel, err := newWASMModel(testString, nil, dummyReceivedMessageCB,
dummyDeletedMessageCB, dummyMutedUserCB, dummyStoreDatabaseName,
dummyStoreEncryptionStatus)
if err != nil {
t.Fatal(err)
}
......@@ -153,7 +153,8 @@ func Test_wasmModel_UpdateSentStatus(t *testing.T) {
testString := "Test_wasmModel_UpdateSentStatus" + cs
testMsgId := message.DeriveChannelMessageID(
&id.ID{1}, 0, []byte(testString))
eventModel, err2 := newWASMModel(testString, c, dummyCallback,
eventModel, err2 := newWASMModel(testString, c,
dummyReceivedMessageCB, dummyDeletedMessageCB, dummyMutedUserCB,
dummyStoreDatabaseName, dummyStoreEncryptionStatus)
if err2 != nil {
t.Fatal(err)
......@@ -161,8 +162,8 @@ func Test_wasmModel_UpdateSentStatus(t *testing.T) {
// Store a test message
testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil,
testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0, netTime.Now(),
time.Second, 0, 0, false, false, channels.Sent)
testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0,
netTime.Now(), time.Second, 0, 0, false, false, channels.Sent)
uuid, err2 := eventModel.receiveHelper(testMsg, false)
if err2 != nil {
t.Fatal(err2)
......@@ -221,8 +222,9 @@ func Test_wasmModel_JoinChannel_LeaveChannel(t *testing.T) {
}
t.Run("Test_wasmModel_JoinChannel_LeaveChannel"+cs, func(t *testing.T) {
storage.GetLocalStorage().Clear()
eventModel, err2 := newWASMModel("test", c, dummyCallback,
dummyStoreDatabaseName, dummyStoreEncryptionStatus)
eventModel, err2 := newWASMModel("test", c, dummyReceivedMessageCB,
dummyDeletedMessageCB, dummyMutedUserCB, dummyStoreDatabaseName,
dummyStoreEncryptionStatus)
if err2 != nil {
t.Fatal(err2)
}
......@@ -275,7 +277,8 @@ func Test_wasmModel_UUIDTest(t *testing.T) {
t.Run("Test_wasmModel_UUIDTest"+cs, func(t *testing.T) {
storage.GetLocalStorage().Clear()
testString := "testHello" + cs
eventModel, err2 := newWASMModel(testString, c, dummyCallback,
eventModel, err2 := newWASMModel(testString, c,
dummyReceivedMessageCB, dummyDeletedMessageCB, dummyMutedUserCB,
dummyStoreDatabaseName, dummyStoreEncryptionStatus)
if err2 != nil {
t.Fatal(err2)
......@@ -322,7 +325,8 @@ func Test_wasmModel_DuplicateReceives(t *testing.T) {
t.Run("Test_wasmModel_DuplicateReceives"+cs, func(t *testing.T) {
storage.GetLocalStorage().Clear()
testString := "testHello"
eventModel, err2 := newWASMModel(testString, c, dummyCallback,
eventModel, err2 := newWASMModel(testString, c,
dummyReceivedMessageCB, dummyDeletedMessageCB, dummyMutedUserCB,
dummyStoreDatabaseName, dummyStoreEncryptionStatus)
if err2 != nil {
t.Fatal(err2)
......@@ -372,7 +376,8 @@ func Test_wasmModel_deleteMsgByChannel(t *testing.T) {
testString := "test_deleteMsgByChannel"
totalMessages := 10
expectedMessages := 5
eventModel, err2 := newWASMModel(testString, c, dummyCallback,
eventModel, err2 := newWASMModel(testString, c,
dummyReceivedMessageCB, dummyDeletedMessageCB, dummyMutedUserCB,
dummyStoreDatabaseName, dummyStoreEncryptionStatus)
if err2 != nil {
t.Fatal(err2)
......@@ -443,7 +448,8 @@ func TestWasmModel_receiveHelper_UniqueIndex(t *testing.T) {
t.Run("TestWasmModel_receiveHelper_UniqueIndex"+cs, func(t *testing.T) {
storage.GetLocalStorage().Clear()
testString := fmt.Sprintf("test_receiveHelper_UniqueIndex_%d", i)
eventModel, err2 := newWASMModel(testString, c, dummyCallback,
eventModel, err2 := newWASMModel(testString, c,
dummyReceivedMessageCB, dummyDeletedMessageCB, dummyMutedUserCB,
dummyStoreDatabaseName, dummyStoreEncryptionStatus)
if err2 != nil {
t.Fatal(err2)
......
......@@ -10,11 +10,13 @@
package main
import (
"crypto/ed25519"
"github.com/hack-pad/go-indexeddb/idb"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/v4/channels"
cryptoChannel "gitlab.com/elixxir/crypto/channel"
"gitlab.com/elixxir/crypto/message"
"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
"gitlab.com/xx_network/primitives/id"
"syscall/js"
......@@ -35,6 +37,14 @@ const (
// update is true if the row is old and was edited.
type MessageReceivedCallback func(uuid uint64, channelID *id.ID, update bool)
// DeletedMessageCallback is called any time a message is deleted.
type DeletedMessageCallback func(messageID message.ID)
// MutedUserCallback is called any time a user is muted or unmuted. unmute is
// true if the user has been unmuted and false if they have been muted.
type MutedUserCallback func(
channelID *id.ID, pubKey ed25519.PublicKey, unmute bool)
// storeDatabaseNameFn matches storage.StoreIndexedDb so that the data can be
// sent between the worker and main thread.
type storeDatabaseNameFn func(databaseName string) error
......@@ -47,16 +57,20 @@ type storeEncryptionStatusFn func(
// NewWASMEventModel returns a [channels.EventModel] backed by a wasmModel.
// The name should be a base64 encoding of the users public key.
func NewWASMEventModel(path string, encryption cryptoChannel.Cipher,
cb MessageReceivedCallback, storeDatabaseName storeDatabaseNameFn,
messageReceivedCB MessageReceivedCallback,
deletedMessageCB DeletedMessageCallback,
mutedUserCB MutedUserCallback, storeDatabaseName storeDatabaseNameFn,
storeEncryptionStatus storeEncryptionStatusFn) (channels.EventModel, error) {
databaseName := path + databaseSuffix
return newWASMModel(
databaseName, encryption, cb, storeDatabaseName, storeEncryptionStatus)
return newWASMModel(databaseName, encryption, messageReceivedCB,
deletedMessageCB, mutedUserCB, storeDatabaseName, storeEncryptionStatus)
}
// newWASMModel creates the given [idb.Database] and returns a wasmModel.
func newWASMModel(databaseName string, encryption cryptoChannel.Cipher,
cb MessageReceivedCallback, storeDatabaseName storeDatabaseNameFn,
messageReceivedCB MessageReceivedCallback,
deletedMessageCB DeletedMessageCallback, mutedUserCB MutedUserCallback,
storeDatabaseName storeDatabaseNameFn,
storeEncryptionStatus storeEncryptionStatusFn) (*wasmModel, error) {
// Attempt to open database object
ctx, cancel := impl.NewContext()
......@@ -115,7 +129,13 @@ func newWASMModel(databaseName string, encryption cryptoChannel.Cipher,
jww.WARN.Printf("IndexedDb encryption disabled!")
}
wrapper := &wasmModel{db: db, receivedMessageCB: cb, cipher: encryption}
wrapper := &wasmModel{
db: db,
cipher: encryption,
receivedMessageCB: messageReceivedCB,
deletedMessageCB: deletedMessageCB,
mutedUserCB: mutedUserCB,
}
return wrapper, nil
}
......
......@@ -12,7 +12,6 @@ package main
import (
"crypto/ed25519"
"encoding/json"
"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
"strings"
"sync"
"syscall/js"
......@@ -28,6 +27,7 @@ import (
"github.com/hack-pad/go-indexeddb/idb"
cryptoChannel "gitlab.com/elixxir/crypto/channel"
"gitlab.com/elixxir/crypto/message"
"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
)
// wasmModel implements dm.EventModel interface, which uses the channels system
......@@ -100,8 +100,7 @@ func (w *wasmModel) Receive(messageID message.ID, nickname string, text []byte,
parentErr := errors.New("failed to Receive")
// If there is no extant Conversation, create one.
_, err := impl.Get(
w.db, conversationStoreName, utils.CopyBytesToJS(pubKey))
_, err := impl.Get(w.db, conversationStoreName, utils.CopyBytesToJS(pubKey))
if err != nil {
if strings.Contains(err.Error(), impl.ErrDoesNotExist) {
err = w.joinConversation(nickname, pubKey, dmToken, codeset)
......@@ -143,8 +142,7 @@ func (w *wasmModel) ReceiveText(messageID message.ID, nickname, text string,
parentErr := errors.New("failed to ReceiveText")
// If there is no extant Conversation, create one.
_, err := impl.Get(
w.db, conversationStoreName, utils.CopyBytesToJS(pubKey))
_, err := impl.Get(w.db, conversationStoreName, utils.CopyBytesToJS(pubKey))
if err != nil {
if strings.Contains(err.Error(), impl.ErrDoesNotExist) {
err = w.joinConversation(nickname, pubKey, dmToken, codeset)
......@@ -188,8 +186,7 @@ func (w *wasmModel) ReceiveReply(messageID, reactionTo message.ID, nickname,
parentErr := errors.New("failed to ReceiveReply")
// If there is no extant Conversation, create one.
_, err := impl.Get(
w.db, conversationStoreName, utils.CopyBytesToJS(pubKey))
_, err := impl.Get(w.db, conversationStoreName, utils.CopyBytesToJS(pubKey))
if err != nil {
if strings.Contains(err.Error(), impl.ErrDoesNotExist) {
err = w.joinConversation(nickname, pubKey, dmToken, codeset)
......@@ -233,8 +230,7 @@ func (w *wasmModel) ReceiveReaction(messageID, _ message.ID, nickname,
parentErr := errors.New("failed to ReceiveText")
// If there is no extant Conversation, create one.
_, err := impl.Get(
w.db, conversationStoreName, utils.CopyBytesToJS(pubKey))
_, err := impl.Get(w.db, conversationStoreName, utils.CopyBytesToJS(pubKey))
if err != nil {
if strings.Contains(err.Error(), impl.ErrDoesNotExist) {
err = w.joinConversation(nickname, pubKey, dmToken, codeset)
......
......@@ -196,6 +196,8 @@ func main() {
js.Global().Set("GetClientVersion", js.FuncOf(wasm.GetClientVersion))
js.Global().Set("GetClientGitVersion", js.FuncOf(wasm.GetClientGitVersion))
js.Global().Set("GetClientDependencies", js.FuncOf(wasm.GetClientDependencies))
js.Global().Set("GetWasmSemanticVersion", js.FuncOf(wasm.GetWasmSemanticVersion))
js.Global().Set("GetXXDKSemanticVersion", js.FuncOf(wasm.GetXXDKSemanticVersion))
<-make(chan bool)
os.Exit(0)
......
......@@ -11,9 +11,11 @@ package storage
import (
"os"
"sync"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/v4/bindings"
)
......@@ -38,17 +40,23 @@ func CheckAndStoreVersions() error {
func checkAndStoreVersions(
currentWasmVer, currentClientVer string, ls *LocalStorage) error {
// Get the stored client and WASM versions, if they exists
storedClientVer, err := initOrLoadStoredSemver(
clientVerKey, currentClientVer, ls)
// Get the stored client version, if it exists
storedClientVer, err :=
initOrLoadStoredSemver(clientVerKey, currentClientVer, ls)
if err != nil {
return err
}
// Get the stored WASM versions, if it exists
storedWasmVer, err := initOrLoadStoredSemver(semverKey, currentWasmVer, ls)
if err != nil {
return err
}
// Store old versions to memory
setOldClientSemVersion(storedClientVer)
setOldWasmSemVersion(storedWasmVer)
// Check if client needs an update
if storedClientVer != currentClientVer {
jww.INFO.Printf("xxDK client out of date; upgrading version: v%s → v%s",
......@@ -96,3 +104,43 @@ func initOrLoadStoredSemver(
// Return the stored version
return string(storedVersion), nil
}
// oldVersions contains the old versions of xxdk WASM and xxdk client that were
// stored in storage before being overwritten on update.
var oldVersions struct {
wasm string
client string
sync.Mutex
}
// GetOldWasmSemVersion returns the old version of xxdk WASM before being
// updated.
func GetOldWasmSemVersion() string {
oldVersions.Lock()
defer oldVersions.Unlock()
return oldVersions.wasm
}
// GetOldClientSemVersion returns the old version of xxdk client before being
// updated.
func GetOldClientSemVersion() string {
oldVersions.Lock()
defer oldVersions.Unlock()
return oldVersions.client
}
// setOldWasmSemVersion sets the old version of xxdk WASM. This should be called
// before it is updated.
func setOldWasmSemVersion(v string) {
oldVersions.Lock()
defer oldVersions.Unlock()
oldVersions.wasm = v
}
// setOldClientSemVersion sets the old version of xxdk client. This should be
// called before it is updated.
func setOldClientSemVersion(v string) {
oldVersions.Lock()
defer oldVersions.Unlock()
oldVersions.client = v
}
......@@ -10,10 +10,12 @@
package wasm
import (
"crypto/ed25519"
"encoding/base64"
"encoding/json"
"errors"
"gitlab.com/elixxir/client/v4/channels"
"gitlab.com/elixxir/crypto/message"
channelsDb "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/channels"
"gitlab.com/xx_network/primitives/id"
"sync"
......@@ -320,14 +322,23 @@ func LoadChannelsManager(_ js.Value, args []js.Value) any {
// - args[1] - Path to Javascript file that starts the worker (string).
// - args[2] - Bytes of a private identity ([channel.PrivateIdentity]) that is
// generated by [GenerateChannelIdentity] (Uint8Array).
// - args[3] - Function that takes in the same parameters as
// [indexedDb.MessageReceivedCallback]. On the Javascript side, the UUID is
// returned as an int and the channelID as a Uint8Array. The row in the
// database that was updated can be found using the UUID. The channel ID is
// provided so that the recipient can filter if they want to the processes
// the update now or not. An "update" bool is present which tells you if the
// row is new or if it is an edited old row.
// - args[4] - ID of [ChannelDbCipher] object in tracker (int). Create this
// - args[3] - The received message callback, which is called everytime a
// message is added or changed in the database. It is a function that takes
// in the same parameters as [indexedDb.MessageReceivedCallback]. On the
// Javascript side, the UUID is returned as an int and the channelID as a
// Uint8Array. The row in the database that was updated can be found using
// the UUID. The channel ID is provided so that the recipient can filter if
// they want to the processes the update now or not. An "update" bool is
// present which tells you if the row is new or if it is an edited old row.
// - args[4] - The deleted message callback, which is called everytime a
// message is deleted from the database. It is a function that takes in the
// same parameters as [indexedDb.DeletedMessageCallback]. On the Javascript
// side, the message ID is returned as a Uint8Array.
// - args[5] - The muted user callback, which is called everytime a user is
// muted or unmuted. It is a function that takes in the same parameters as
// [indexedDb.MutedUserCallback]. On the Javascript side, the channel ID and
// user public key are returned as Uint8Array.
// - args[6] - ID of [ChannelDbCipher] object in tracker (int). Create this
// object with [NewChannelsDatabaseCipher] and get its id with
// [ChannelDbCipher.GetID].
//
......@@ -340,15 +351,17 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any {
wasmJsPath := args[1].String()
privateIdentity := utils.CopyBytesToGo(args[2])
messageReceivedCB := args[3]
cipherID := args[4].Int()
deletedMessageCB := args[4]
mutedUserCB := args[5]
cipherID := args[6].Int()
cipher, err := bindings.GetChannelDbCipherTrackerFromID(cipherID)
if err != nil {
utils.Throw(utils.TypeError, err)
}
return newChannelsManagerWithIndexedDb(
cmixID, wasmJsPath, privateIdentity, messageReceivedCB, cipher)
return newChannelsManagerWithIndexedDb(cmixID, wasmJsPath, privateIdentity,
messageReceivedCB, deletedMessageCB, mutedUserCB, cipher)
}
// NewChannelsManagerWithIndexedDbUnsafe creates a new [ChannelsManager] from a
......@@ -369,35 +382,58 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any {
// - args[1] - Path to Javascript file that starts the worker (string).
// - args[2] - Bytes of a private identity ([channel.PrivateIdentity]) that is
// generated by [GenerateChannelIdentity] (Uint8Array).
// - args[3] - Function that takes in the same parameters as
// [indexedDb.MessageReceivedCallback]. On the Javascript side, the UUID is
// returned as an int and the channelID as a Uint8Array. The row in the
// database that was updated can be found using the UUID. The channel ID is
// provided so that the recipient can filter if they want to the processes
// the update now or not. An "update" bool is present which tells you if
// the row is new or if it is an edited old row
// - args[3] - The received message callback, which is called everytime a
// message is added or changed in the database. It is a function that takes
// in the same parameters as [indexedDb.MessageReceivedCallback]. On the
// Javascript side, the UUID is returned as an int and the channelID as a
// Uint8Array. The row in the database that was updated can be found using
// the UUID. The channel ID is provided so that the recipient can filter if
// they want to the processes the update now or not. An "update" bool is
// present which tells you if the row is new or if it is an edited old row.
// - args[4] - The deleted message callback, which is called everytime a
// message is deleted from the database. It is a function that takes in the
// same parameters as [indexedDb.DeletedMessageCallback]. On the Javascript
// side, the message ID is returned as a Uint8Array.
// - args[5] - The muted user callback, which is called everytime a user is
// muted or unmuted. It is a function that takes in the same parameters as
// [indexedDb.MutedUserCallback]. On the Javascript side, the channel ID and
// user public key are returned as Uint8Array.
//
// Returns a promise:
// - Resolves to a Javascript representation of the [ChannelsManager] object.
// - Rejected with an error if loading indexedDb or the manager fails.
// FIXME: package names in comments for indexedDb
func NewChannelsManagerWithIndexedDbUnsafe(_ js.Value, args []js.Value) any {
cmixID := args[0].Int()
wasmJsPath := args[1].String()
privateIdentity := utils.CopyBytesToGo(args[2])
messageReceivedCB := args[3]
deletedMessageCB := args[4]
mutedUserCB := args[5]
return newChannelsManagerWithIndexedDb(
cmixID, wasmJsPath, privateIdentity, messageReceivedCB, nil)
return newChannelsManagerWithIndexedDb(cmixID, wasmJsPath, privateIdentity,
messageReceivedCB, deletedMessageCB, mutedUserCB, nil)
}
func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string,
privateIdentity []byte, cb js.Value, cipher *bindings.ChannelDbCipher) any {
privateIdentity []byte, messageReceivedCB, deletedMessageCB, mutedUserCB js.Value,
cipher *bindings.ChannelDbCipher) any {
messageReceivedCB := func(uuid uint64, channelID *id.ID, update bool) {
cb.Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal()), update)
messageReceived := func(uuid uint64, channelID *id.ID, update bool) {
messageReceivedCB.Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal()), update)
}
model := channelsDb.NewWASMEventModelBuilder(wasmJsPath, cipher, messageReceivedCB)
deletedMessage := func(messageID message.ID) {
deletedMessageCB.Invoke(utils.CopyBytesToJS(messageID.Marshal()))
}
mutedUser := func(channelID *id.ID, pubKey ed25519.PublicKey, unmute bool) {
mutedUserCB.Invoke(utils.CopyBytesToJS(channelID.Marshal()),
utils.CopyBytesToJS(pubKey), unmute)
}
model := channelsDb.NewWASMEventModelBuilder(
wasmJsPath, cipher, messageReceived, deletedMessage, mutedUser)
promiseFn := func(resolve, reject func(args ...any) js.Value) {
cm, err := bindings.NewChannelsManagerGoEventModel(
......@@ -426,14 +462,23 @@ func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string,
// - args[1] - Path to Javascript file that starts the worker (string).
// - args[2] - The storage tag associated with the previously created channel
// manager and retrieved with [ChannelsManager.GetStorageTag] (string).
// - args[3] - Function that takes in the same parameters as
// [indexedDb.MessageReceivedCallback]. On the Javascript side, the UUID is
// returned as an int and the channelID as a Uint8Array. The row in the
// database that was updated can be found using the UUID. The channel ID is
// provided so that the recipient can filter if they want to the processes
// the update now or not. An "update" bool is present which tells you if the
// row is new or if it is an edited old row.
// - args[4] - ID of [ChannelDbCipher] object in tracker (int). Create this
// - args[3] - The received message callback, which is called everytime a
// message is added or changed in the database. It is a function that takes
// in the same parameters as [indexedDb.MessageReceivedCallback]. On the
// Javascript side, the UUID is returned as an int and the channelID as a
// Uint8Array. The row in the database that was updated can be found using
// the UUID. The channel ID is provided so that the recipient can filter if
// they want to the processes the update now or not. An "update" bool is
// present which tells you if the row is new or if it is an edited old row.
// - args[4] - The deleted message callback, which is called everytime a
// message is deleted from the database. It is a function that takes in the
// same parameters as [indexedDb.DeletedMessageCallback]. On the Javascript
// side, the message ID is returned as a Uint8Array.
// - args[5] - The muted user callback, which is called everytime a user is
// muted or unmuted. It is a function that takes in the same parameters as
// [indexedDb.MutedUserCallback]. On the Javascript side, the channel ID and
// user public key are returned as Uint8Array.
// - args[6] - ID of [ChannelDbCipher] object in tracker (int). Create this
// object with [NewChannelsDatabaseCipher] and get its id with
// [ChannelDbCipher.GetID].
//
......@@ -446,15 +491,17 @@ func LoadChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any {
wasmJsPath := args[1].String()
storageTag := args[2].String()
messageReceivedCB := args[3]
cipherID := args[4].Int()
deletedMessageCB := args[4]
mutedUserCB := args[5]
cipherID := args[6].Int()
cipher, err := bindings.GetChannelDbCipherTrackerFromID(cipherID)
if err != nil {
utils.Throw(utils.TypeError, err)
}
return loadChannelsManagerWithIndexedDb(
cmixID, wasmJsPath, storageTag, messageReceivedCB, cipher)
return loadChannelsManagerWithIndexedDb(cmixID, wasmJsPath, storageTag,
messageReceivedCB, deletedMessageCB, mutedUserCB, cipher)
}
// LoadChannelsManagerWithIndexedDbUnsafe loads an existing [ChannelsManager]
......@@ -473,13 +520,22 @@ func LoadChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any {
// - args[1] - Path to Javascript file that starts the worker (string).
// - args[2] - The storage tag associated with the previously created channel
// manager and retrieved with [ChannelsManager.GetStorageTag] (string).
// - args[3] - Function that takes in the same parameters as
// [indexedDb.MessageReceivedCallback]. On the Javascript side, the UUID is
// returned as an int and the channelID as a Uint8Array. The row in the
// database that was updated can be found using the UUID. The channel ID is
// provided so that the recipient can filter if they want to the processes
// the update now or not. An "update" bool is present which tells you if
// the row is new or if it is an edited old row
// - args[3] - The received message callback, which is called everytime a
// message is added or changed in the database. It is a function that takes
// in the same parameters as [indexedDb.MessageReceivedCallback]. On the
// Javascript side, the UUID is returned as an int and the channelID as a
// Uint8Array. The row in the database that was updated can be found using
// the UUID. The channel ID is provided so that the recipient can filter if
// they want to the processes the update now or not. An "update" bool is
// present which tells you if the row is new or if it is an edited old row.
// - args[4] - The deleted message callback, which is called everytime a
// message is deleted from the database. It is a function that takes in the
// same parameters as [indexedDb.DeletedMessageCallback]. On the Javascript
// side, the message ID is returned as a Uint8Array.
// - args[5] - The muted user callback, which is called everytime a user is
// muted or unmuted. It is a function that takes in the same parameters as
// [indexedDb.MutedUserCallback]. On the Javascript side, the channel ID and
// user public key are returned as Uint8Array.
//
// Returns a promise:
// - Resolves to a Javascript representation of the [ChannelsManager] object.
......@@ -489,19 +545,32 @@ func LoadChannelsManagerWithIndexedDbUnsafe(_ js.Value, args []js.Value) any {
wasmJsPath := args[1].String()
storageTag := args[2].String()
messageReceivedCB := args[3]
deletedMessageCB := args[3]
mutedUserCB := args[4]
return loadChannelsManagerWithIndexedDb(
cmixID, wasmJsPath, storageTag, messageReceivedCB, nil)
return loadChannelsManagerWithIndexedDb(cmixID, wasmJsPath, storageTag,
messageReceivedCB, deletedMessageCB, mutedUserCB, nil)
}
func loadChannelsManagerWithIndexedDb(cmixID int, wasmJsPath, storageTag string,
cb js.Value, cipher *bindings.ChannelDbCipher) any {
messageReceivedCB := func(uuid uint64, channelID *id.ID, updated bool) {
cb.Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal()), updated)
messageReceivedCB, deletedMessageCB, mutedUserCB js.Value,
cipher *bindings.ChannelDbCipher) any {
messageReceived := func(uuid uint64, channelID *id.ID, update bool) {
messageReceivedCB.Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal()), update)
}
deletedMessage := func(messageID message.ID) {
deletedMessageCB.Invoke(utils.CopyBytesToJS(messageID.Marshal()))
}
mutedUser := func(channelID *id.ID, pubKey ed25519.PublicKey, unmute bool) {
mutedUserCB.Invoke(utils.CopyBytesToJS(channelID.Marshal()),
utils.CopyBytesToJS(pubKey), unmute)
}
model := channelsDb.NewWASMEventModelBuilder(
wasmJsPath, cipher, messageReceivedCB)
wasmJsPath, cipher, messageReceived, deletedMessage, mutedUser)
promiseFn := func(resolve, reject func(args ...any) js.Value) {
cm, err := bindings.LoadChannelsManagerGoEventModel(
......@@ -879,14 +948,14 @@ func ValidForever(js.Value, []js.Value) any {
func (cm *ChannelsManager) SendGeneric(_ js.Value, args []js.Value) any {
marshalledChanId := utils.CopyBytesToGo(args[0])
messageType := args[1].Int()
message := utils.CopyBytesToGo(args[2])
msg := utils.CopyBytesToGo(args[2])
leaseTimeMS := int64(args[3].Int())
tracked := args[4].Bool()
cmixParamsJSON := utils.CopyBytesToGo(args[5])
promiseFn := func(resolve, reject func(args ...any) js.Value) {
sendReport, err := cm.api.SendGeneric(marshalledChanId, messageType,
message, leaseTimeMS, tracked, cmixParamsJSON)
msg, leaseTimeMS, tracked, cmixParamsJSON)
if err != nil {
reject(utils.JsTrace(err))
} else {
......@@ -922,13 +991,13 @@ func (cm *ChannelsManager) SendGeneric(_ js.Value, args []js.Value) any {
// - Rejected with an error if sending fails.
func (cm *ChannelsManager) SendMessage(_ js.Value, args []js.Value) any {
marshalledChanId := utils.CopyBytesToGo(args[0])
message := args[1].String()
msg := args[1].String()
leaseTimeMS := int64(args[2].Int())
cmixParamsJSON := utils.CopyBytesToGo(args[3])
promiseFn := func(resolve, reject func(args ...any) js.Value) {
sendReport, err := cm.api.SendMessage(
marshalledChanId, message, leaseTimeMS, cmixParamsJSON)
marshalledChanId, msg, leaseTimeMS, cmixParamsJSON)
if err != nil {
reject(utils.JsTrace(err))
} else {
......@@ -971,13 +1040,13 @@ func (cm *ChannelsManager) SendMessage(_ js.Value, args []js.Value) any {
// - Rejected with an error if sending fails.
func (cm *ChannelsManager) SendReply(_ js.Value, args []js.Value) any {
marshalledChanId := utils.CopyBytesToGo(args[0])
message := args[1].String()
msg := args[1].String()
messageToReactTo := utils.CopyBytesToGo(args[2])
leaseTimeMS := int64(args[3].Int())
cmixParamsJSON := utils.CopyBytesToGo(args[4])
promiseFn := func(resolve, reject func(args ...any) js.Value) {
sendReport, err := cm.api.SendReply(marshalledChanId, message,
sendReport, err := cm.api.SendReply(marshalledChanId, msg,
messageToReactTo, leaseTimeMS, cmixParamsJSON)
if err != nil {
reject(utils.JsTrace(err))
......@@ -1068,14 +1137,14 @@ func (cm *ChannelsManager) SendReaction(_ js.Value, args []js.Value) any {
func (cm *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any {
marshalledChanId := utils.CopyBytesToGo(args[0])
messageType := args[1].Int()
message := utils.CopyBytesToGo(args[2])
msg := utils.CopyBytesToGo(args[2])
leaseTimeMS := int64(args[3].Int())
tracked := args[4].Bool()
cmixParamsJSON := utils.CopyBytesToGo(args[5])
promiseFn := func(resolve, reject func(args ...any) js.Value) {
sendReport, err := cm.api.SendAdminGeneric(marshalledChanId,
messageType, message, leaseTimeMS, tracked, cmixParamsJSON)
messageType, msg, leaseTimeMS, tracked, cmixParamsJSON)
if err != nil {
reject(utils.JsTrace(err))
} else {
......@@ -1624,6 +1693,7 @@ func (emb *eventModelBuilder) Build(path string) bindings.EventModel {
updateFromMessageID: utils.WrapCB(emJs, "UpdateFromMessageID"),
getMessage: utils.WrapCB(emJs, "GetMessage"),
deleteMessage: utils.WrapCB(emJs, "DeleteMessage"),
muteUser: utils.WrapCB(emJs, "MuteUser"),
}
}
......@@ -1639,6 +1709,7 @@ type eventModel struct {
updateFromMessageID func(args ...any) js.Value
getMessage func(args ...any) js.Value
deleteMessage func(args ...any) js.Value
muteUser func(args ...any) js.Value
}
// JoinChannel is called whenever a channel is joined locally.
......@@ -1858,6 +1929,17 @@ func (em *eventModel) DeleteMessage(messageID []byte) error {
return nil
}
// MuteUser mutes the given user or unmutes them.
//
// Parameters:
// - channelID - The bytes of the [id.ID] of the channel the user is being
// muted in.
// - pubKey - The [ed25519.PublicKey] of the user that is muted or unmuted.
func (em *eventModel) MuteUser(channelID, pubkey []byte, unmute bool) {
em.muteUser(
utils.CopyBytesToJS(channelID), utils.CopyBytesToJS(pubkey), unmute)
}
// MessageAndError contains a message returned by eventModel.GetMessage or any
// possible error that occurs during lookup. Only one field should be present at
// a time; if an error occurs, ModelMessage should be empty.
......
......@@ -10,9 +10,12 @@
package wasm
import (
"encoding/json"
"syscall/js"
"gitlab.com/elixxir/client/v4/bindings"
"gitlab.com/elixxir/xxdk-wasm/storage"
"syscall/js"
"gitlab.com/elixxir/xxdk-wasm/utils"
)
// GetVersion returns the current xxDK WASM semantic version.
......@@ -49,3 +52,60 @@ func GetClientGitVersion(js.Value, []js.Value) any {
func GetClientDependencies(js.Value, []js.Value) any {
return bindings.GetDependencies()
}
// VersionInfo contains information about the current and old version of the
// API.
type VersionInfo struct {
Current string `json:"current"`
Updated bool `json:"updated"`
Old string `json:"old"`
}
// GetWasmSemanticVersion returns the current version of the WASM client, it's
// old version before being updated, and if it has been updated.
//
// Returns:
// - JSON of [VersionInfo] (Uint8Array).
// - Throws a TypeError if getting the version failed.
func GetWasmSemanticVersion(js.Value, []js.Value) any {
vi := VersionInfo{
Current: storage.SEMVER,
Updated: false,
Old: storage.GetOldWasmSemVersion(),
}
if vi.Current != vi.Old {
vi.Updated = true
}
data, err := json.Marshal(vi)
if err != nil {
utils.Throw(utils.TypeError, err)
}
return utils.CopyBytesToJS(data)
}
// GetXXDKSemanticVersion returns the current version of the xxdk client, it's
// old version before being updated, and if it has been updated.
//
// Returns:
// - JSON of [VersionInfo] (Uint8Array).
// - Throws a TypeError if getting the version failed.
func GetXXDKSemanticVersion(js.Value, []js.Value) any {
vi := VersionInfo{
Current: bindings.GetVersion(),
Updated: false,
Old: storage.GetOldClientSemVersion(),
}
if vi.Current != vi.Old {
vi.Updated = true
}
data, err := json.Marshal(vi)
if err != nil {
utils.Throw(utils.TypeError, err)
}
return utils.CopyBytesToJS(data)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment