diff --git a/go.mod b/go.mod index 55fa3b9d967a383db414693e960113256ec565e5..4c53c0884890d316e85428a4d09b80f0efb09060 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ require ( github.com/spf13/cobra v1.7.0 github.com/spf13/jwalterweatherman v1.1.0 github.com/stretchr/testify v1.8.2 - gitlab.com/elixxir/client/v4 v4.6.4-0.20230526193945-9f195a236f77 - gitlab.com/elixxir/crypto v0.0.7-0.20230526183834-62f8f49617bc + gitlab.com/elixxir/client/v4 v4.6.4-0.20230601191127-0a0562f6a839 + gitlab.com/elixxir/crypto v0.0.7-0.20230601185515-3813919cfa93 gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c gitlab.com/elixxir/wasm-utils v0.0.0-20230522231408-a43b2c1481b2 gitlab.com/xx_network/crypto v0.0.5-0.20230214003943-8a09396e95dd diff --git a/go.sum b/go.sum index b3aa49e12dccd8ce395670f167ca59d718d29bca..2fd9c15519d43abf9144f48877dc8d39dc1317bf 100644 --- a/go.sum +++ b/go.sum @@ -517,16 +517,40 @@ gitlab.com/elixxir/client/v4 v4.6.4-0.20230525191042-3795029e4315 h1:rOgY9KPwq0w gitlab.com/elixxir/client/v4 v4.6.4-0.20230525191042-3795029e4315/go.mod h1:1+FU4spF6kwSA84AnFq0i6j4jsAICuvVfp6ACh00K0U= gitlab.com/elixxir/client/v4 v4.6.4-0.20230526074923-c0fb2a45c312 h1:yUyz1L/rzodZxUU45CeH7mfMfmKAs706+s2j2ZGUSwE= gitlab.com/elixxir/client/v4 v4.6.4-0.20230526074923-c0fb2a45c312/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= -gitlab.com/elixxir/client/v4 v4.6.4-0.20230526185452-5da5d4f474f6 h1:qAIeh68suM7rLJ5RHt1AvZoYmehIwPLGeDzm6SMc0R4= -gitlab.com/elixxir/client/v4 v4.6.4-0.20230526185452-5da5d4f474f6/go.mod h1:0fEqbELJdwTNRsrvgecZbGsJSX2TqHUst/LSBKo/cL0= -gitlab.com/elixxir/client/v4 v4.6.4-0.20230526193945-9f195a236f77 h1:qCxO7ZuUGXh54iCi8hlzl3OBBI+B1MzngCZAWCv+S9c= -gitlab.com/elixxir/client/v4 v4.6.4-0.20230526193945-9f195a236f77/go.mod h1:0fEqbELJdwTNRsrvgecZbGsJSX2TqHUst/LSBKo/cL0= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530165750-f6ea41bc69e4 h1:dgq4fwLdVzsPGdk1E7vLZI1gWk/QB/K7Rntg+DrxAjY= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530165750-f6ea41bc69e4/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530170051-243baab3da48 h1:2HP8w4HOlqjg0FcvSnhMmpwUa1pcU0WbvWMOUNiy/hE= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530170051-243baab3da48/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530182422-d12ab437257f h1:8TJwqKjeD0eZSvWIlPwjgIwfgdzcHhTzGwaiUJCwwuI= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530182422-d12ab437257f/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530201605-ba087da90ba2 h1:sxAgLmG2RLarBuXtcH8g5ZcQbAF9PmS3wrnlwZVFrLA= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530201605-ba087da90ba2/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530211720-a1bc89986df8 h1:XTklpI9leJYgZ4bYZLQUOzzgoxlYUz7xDmcl2Fy7knc= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530211720-a1bc89986df8/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530220505-726d2194d278 h1:etC7c2JeKbykuSHIm8jvb3cpMUdJGlyMsBQbImXlIK8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530220505-726d2194d278/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530222715-a0c0ea0de57f h1:67k1pJg8w6bGfDLex3/e4rdm8Cb2m43qjrryKjVo/UE= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230530222715-a0c0ea0de57f/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531180314-040f2bf4bc9f h1:KJQjb0WfOtrJo1vKGeISwlmdQTwtV3CmCg4nbP6bzlM= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531180314-040f2bf4bc9f/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531193105-0f398d814565 h1:kBbMa8AdCD/0KaLY7jIMk8yWsrRYSMb4zrdGRT4xZ6w= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531193105-0f398d814565/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531195028-ad25aee27c19 h1:OLZTJAqRm1hqGeeHs+aYZ9v3ojgiv+6qykC8+9pFBVM= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531195028-ad25aee27c19/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531195851-a65797612a21 h1:u4H7ITaOwO4aQoSJCo8zpfRpenaqgHuvjqF3GAe8RrE= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531195851-a65797612a21/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531212217-e21b55fbf23c h1:6OTyW9U/ntZ41Xry+8qDkOH4LoxhlyWTwKpAxi2fvZY= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531212217-e21b55fbf23c/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531224642-b24cd3f5e4a4 h1:YacWU7IJUfixfZyckdXEWPwhix7sq+STK+8Vz8DzVO4= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230531224642-b24cd3f5e4a4/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230601191127-0a0562f6a839 h1:PfeNQArnqe0nlSDCHx8GILA5jI87XNYsC+/H8URteFY= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230601191127-0a0562f6a839/go.mod h1:BSxUKi3xOPJfQgUBUc+uWDOXa18umYsDj3A1K3IwBEE= gitlab.com/elixxir/comms v0.0.4-0.20230519211512-4a998f4b0938 h1:f27+QUFiGWrprKm+fstOg3ABkYLpWcZi3+8Lf5eDnqY= gitlab.com/elixxir/comms v0.0.4-0.20230519211512-4a998f4b0938/go.mod h1:z+qW0D9VpY5QKTd7wRlb5SK4kBNqLYsa4DXBcUXue9Q= gitlab.com/elixxir/crypto v0.0.7-0.20230522162218-45433d877235 h1:0BySdXTzRWxzH8k5RiNNMmmn2lpuQWLVcDDA/7ehyqc= gitlab.com/elixxir/crypto v0.0.7-0.20230522162218-45433d877235/go.mod h1:IYInxKr5Q7EH3oNhg1QX1/sTTRNi7L0JkcyfdRegoio= -gitlab.com/elixxir/crypto v0.0.7-0.20230526183834-62f8f49617bc h1:Rl8q37axi4XVuuDfXP+bYc9iAcVb3O9jyYWuQTV5+Z8= -gitlab.com/elixxir/crypto v0.0.7-0.20230526183834-62f8f49617bc/go.mod h1:IYInxKr5Q7EH3oNhg1QX1/sTTRNi7L0JkcyfdRegoio= +gitlab.com/elixxir/crypto v0.0.7-0.20230601185515-3813919cfa93 h1:9uwoqqEk8virGua/fjk8M7CHQFT2uY7pBU8TjMSPwiA= +gitlab.com/elixxir/crypto v0.0.7-0.20230601185515-3813919cfa93/go.mod h1:IYInxKr5Q7EH3oNhg1QX1/sTTRNi7L0JkcyfdRegoio= gitlab.com/elixxir/ekv v0.3.1-0.20230525165450-f444c687504b h1:hf28yepO93tCacx1bUAh8vVFkBUEuBaJhOjifBxEQK4= gitlab.com/elixxir/ekv v0.3.1-0.20230525165450-f444c687504b/go.mod h1:EMaUQrsOxvEPQ0/8V/PSkGqFmEC2axBG/uqY0oW2uJM= gitlab.com/elixxir/ekv v0.3.1-0.20230525213559-f9da13f4fce1 h1:8XBo6QQBXXGCTrgXHFuqPL21mROLKLAoO3X9xR5TwA0= diff --git a/main.go b/main.go index 267bb55bb812d1950c412a51337464cd35f39b36..9bf2a059bab4555283629321ebf398fd387da399 100644 --- a/main.go +++ b/main.go @@ -156,6 +156,8 @@ func setGlobals() { // wasm/cmix.go js.Global().Set("NewCmix", js.FuncOf(wasm.NewCmix)) + js.Global().Set("NewSynchronizedCmix", + js.FuncOf(wasm.NewSynchronizedCmix)) js.Global().Set("LoadCmix", js.FuncOf(wasm.LoadCmix)) js.Global().Set("LoadSynchronizedCmix", js.FuncOf(wasm.LoadSynchronizedCmix)) diff --git a/wasm/cmix.go b/wasm/cmix.go index be7ad6d31f2052b6f9750703611b4789cff35009..909a8b29d20105f4535205793496fbbf1f9ab14c 100644 --- a/wasm/cmix.go +++ b/wasm/cmix.go @@ -10,6 +10,8 @@ package wasm import ( + "fmt" + "sync/atomic" "syscall/js" "gitlab.com/elixxir/client/v4/bindings" @@ -17,6 +19,8 @@ import ( "gitlab.com/elixxir/wasm-utils/utils" ) +var initializing atomic.Bool + // Cmix wraps the [bindings.Cmix] object so its methods can be wrapped to be // Javascript compatible. type Cmix struct { @@ -110,6 +114,40 @@ func NewCmix(_ js.Value, args []js.Value) any { return utils.CreatePromise(promiseFn) } +// NewSynchronizedCmix clones a cMix from remote storage. +// +// Users of this function should delete the storage directory on error. +// +// Parameters: +// - args[0] - NDF JSON ([ndf.NetworkDefinition]) (string). +// - args[1] - Storage directory path (string). +// - args[2] - Password used for storage (Uint8Array). +// - args[3] - Javascript [RemoteStore] implementation. +// +// Returns a promise: +// - Resolves on success. +// - Rejected with an error if creating a new cMix client fails. +func NewSynchronizedCmix(_ js.Value, args []js.Value) any { + initializing.Store(true) + ndfJSON := args[0].String() + storageDir := args[1].String() + password := utils.CopyBytesToGo(args[2]) + rs := newRemoteStore(args[3]) + + promiseFn := func(resolve, reject func(args ...any) js.Value) { + err := bindings.NewSynchronizedCmix(ndfJSON, storageDir, + password, rs) + if err != nil { + reject(exception.NewTrace(err)) + } else { + initializing.Store(false) + resolve() + } + } + + return utils.CreatePromise(promiseFn) +} + // LoadCmix will load an existing user storage from the storageDir using the // password. This will fail if the user storage does not exist or the password // is incorrect. @@ -164,6 +202,10 @@ func LoadSynchronizedCmix(_ js.Value, args []js.Value) any { cmixParamsJSON := utils.CopyBytesToGo(args[3]) promiseFn := func(resolve, reject func(args ...any) js.Value) { + if initializing.Load() { + reject(exception.NewTrace(fmt.Errorf( + "cannot Load when New is running"))) + } net, err := bindings.LoadSynchronizedCmix(storageDir, password, rs, cmixParamsJSON) if err != nil { diff --git a/wasm/collective.go b/wasm/collective.go index e99f03aefab09cde52cde0107193033e6bb3ae16..5bd0fa145fd214752475bc1eaa9601dc881297e5 100644 --- a/wasm/collective.go +++ b/wasm/collective.go @@ -385,6 +385,7 @@ func (r *RemoteKV) GetMapElement(_ js.Value, args []js.Value) any { // - args[0] - the key string // - args[1] - the version int // - args[2] - the [KeyChangedByRemoteCallback] javascript callback +// - args[3] - set the localEvents flag to true or false (optional) // // Returns a promise with an error if any or the json of the existing // [versioned.Object], e.g.: @@ -396,12 +397,17 @@ func (r *RemoteKV) ListenOnRemoteKey(_ js.Value, args []js.Value) any { version := int64(args[1].Int()) cb := newKeyChangedByRemoteCallback(args[2]) + localEvents := true + if len(args) > 3 && !args[3].IsUndefined() { + localEvents = args[3].Bool() + } + promiseFn := func(resolve, reject func(args ...any) js.Value) { - deleted, err := r.api.ListenOnRemoteKey(key, version, cb) + err := r.api.ListenOnRemoteKey(key, version, cb, localEvents) if err != nil { reject(exception.NewTrace(err)) } else { - resolve(utils.CopyBytesToJS(deleted)) + resolve() } } @@ -415,6 +421,7 @@ func (r *RemoteKV) ListenOnRemoteKey(_ js.Value, args []js.Value) any { // - args[0] - the mapName string // - args[1] - the version int // - args[2] - the [MapChangedByRemoteCallback] javascript callback +// - args[3] - set the localEvents flag to true or false (optional) // // Returns a promise with an error if any or the json of the existing // the [map[string]versioned.Object] JSON value, e.g.: @@ -426,12 +433,17 @@ func (r *RemoteKV) ListenOnRemoteMap(_ js.Value, args []js.Value) any { version := int64(args[1].Int()) cb := newMapChangedByRemoteCallback(args[2]) + localEvents := true + if len(args) > 3 && !args[3].IsUndefined() { + localEvents = args[3].Bool() + } + promiseFn := func(resolve, reject func(args ...any) js.Value) { - deleted, err := r.api.ListenOnRemoteMap(mapName, version, cb) + err := r.api.ListenOnRemoteMap(mapName, version, cb, localEvents) if err != nil { reject(exception.NewTrace(err)) } else { - resolve(utils.CopyBytesToJS(deleted)) + resolve() } } @@ -473,13 +485,11 @@ func newRemoteStore(arg js.Value) *RemoteStore { // - The file data (Uint8Array). // - Catches any thrown errors (of type Error) and returns it as an error. func (rsCB *RemoteStore) Read(path string) ([]byte, error) { - - fn := func() js.Value { return rsCB.read(path) } - v, err := exception.RunAndCatch(fn) - if err != nil { - return nil, err + v, awaitErr := utils.Await(rsCB.read(path)) + if awaitErr != nil { + return nil, js.Error{Value: awaitErr[0]} } - return utils.CopyBytesToGo(v), err + return utils.CopyBytesToGo(v[0]), nil } // Write implements [bindings.RemoteStore.Write] @@ -491,9 +501,11 @@ func (rsCB *RemoteStore) Read(path string) ([]byte, error) { // Returns: // - Catches any thrown errors (of type Error) and returns it as an error. func (rsCB *RemoteStore) Write(path string, data []byte) error { - fn := func() js.Value { return rsCB.write(path, utils.CopyBytesToJS(data)) } - _, err := exception.RunAndCatch(fn) - return err + _, awaitErr := utils.Await(rsCB.write(path, utils.CopyBytesToJS(data))) + if awaitErr != nil { + return js.Error{Value: awaitErr[0]} + } + return nil } // GetLastModified implements [bindings.RemoteStore.GetLastModified] @@ -536,12 +548,11 @@ func (rsCB *RemoteStore) GetLastWrite() ([]byte, error) { // - JSON of []string (Uint8Array). // - Catches any thrown errors (of type Error) and returns it as an error. func (rsCB *RemoteStore) ReadDir(path string) ([]byte, error) { - fn := func() js.Value { return rsCB.readDir(path) } - v, err := exception.RunAndCatch(fn) - if err != nil { - return nil, err + v, awaitErr := utils.Await(rsCB.readDir(path)) + if awaitErr != nil { + return nil, js.Error{Value: awaitErr[0]} } - return utils.CopyBytesToGo(v), err + return utils.CopyBytesToGo(v[0]), nil } ////////////////////////////////////////////////////////////////////////////////