diff --git a/indexedDb/impl/state/callbacks.go b/indexedDb/impl/state/callbacks.go new file mode 100644 index 0000000000000000000000000000000000000000..a3cf8baf2278bf355d9b23a48a2994f6d2325e97 --- /dev/null +++ b/indexedDb/impl/state/callbacks.go @@ -0,0 +1,76 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 xx foundation // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file. // +//////////////////////////////////////////////////////////////////////////////// + +//go:build js && wasm + +package main + +import ( + "encoding/json" + "github.com/pkg/errors" + + "gitlab.com/elixxir/client/v4/storage/utility" + wDm "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/dm" + stateWorker "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/state" + "gitlab.com/elixxir/xxdk-wasm/worker" +) + +// manager handles the message callbacks, which is used to +// send information between the model and the main thread. +type manager struct { + wtm *worker.ThreadManager + model utility.WebState +} + +// registerCallbacks registers all the reception callbacks to manage messages +// from the main thread. +func (m *manager) registerCallbacks() { + m.wtm.RegisterCallback(stateWorker.NewStateTag, m.newStateCB) + m.wtm.RegisterCallback(stateWorker.SetTag, m.setCB) + m.wtm.RegisterCallback(stateWorker.GetTag, m.getCB) +} + +// newStateCB is the callback for NewState. Returns an empty +// slice on success or an error message on failure. +func (m *manager) newStateCB(data []byte) ([]byte, error) { + var msg wDm.NewWASMEventModelMessage + err := json.Unmarshal(data, &msg) + if err != nil { + return []byte{}, errors.Errorf( + "failed to JSON unmarshal %T from main thread: %+v", msg, err) + } + + m.model, err = NewState(msg.DatabaseName) + if err != nil { + return []byte(err.Error()), nil + } + + return []byte{}, nil +} + +// setCB is the callback for stateModel.Set. +// Returns nil on error or the resulting byte data on success. +func (m *manager) setCB(data []byte) ([]byte, error) { + var msg stateWorker.TransferMessage + err := json.Unmarshal(data, &msg) + if err != nil { + return nil, errors.Errorf( + "failed to JSON unmarshal %T from main thread: %+v", msg, err) + } + + return nil, m.model.Set(msg.Key, msg.Value) +} + +// getCB is the callback for stateModel.Get. +// Returns nil on error or the resulting byte data on success. +func (m *manager) getCB(data []byte) ([]byte, error) { + result, err := m.model.Get(string(data)) + if err != nil { + return nil, err + } + return json.Marshal(result) +} diff --git a/indexedDb/impl/state/main.go b/indexedDb/impl/state/main.go new file mode 100644 index 0000000000000000000000000000000000000000..719b9969852c2ba946d6365367050878b0dd7b81 --- /dev/null +++ b/indexedDb/impl/state/main.go @@ -0,0 +1,80 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 xx foundation // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file. // +//////////////////////////////////////////////////////////////////////////////// + +//go:build js && wasm + +package main + +import ( + "fmt" + "os" + "syscall/js" + + "github.com/spf13/cobra" + jww "github.com/spf13/jwalterweatherman" + + "gitlab.com/elixxir/xxdk-wasm/logging" + "gitlab.com/elixxir/xxdk-wasm/worker" +) + +// SEMVER is the current semantic version of the xxDK web worker. +const SEMVER = "0.1.0" + +func main() { + // Set to os.Args because the default is os.Args[1:] and in WASM, args start + // at 0, not 1. + channelsCmd.SetArgs(os.Args) + + err := channelsCmd.Execute() + if err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +var channelsCmd = &cobra.Command{ + Use: "stateIndexedDbWorker", + Short: "IndexedDb database for state.", + Example: "const go = new Go();\ngo.argv = [\"--logLevel=1\"]", + Run: func(cmd *cobra.Command, args []string) { + // Start logger first to capture all logging events + err := logging.EnableLogging(logLevel, -1, 0, "", "") + if err != nil { + fmt.Printf("Failed to intialize logging: %+v", err) + os.Exit(1) + } + + jww.INFO.Printf("xxDK state web worker version: v%s", SEMVER) + + jww.INFO.Print("[WW] Starting xxDK WebAssembly State Database Worker.") + m := &manager{ + wtm: worker.NewThreadManager("StateIndexedDbWorker", true), + } + m.registerCallbacks() + m.wtm.SignalReady() + + // Indicate to the Javascript caller that the WASM is ready by resolving + // a promise created by the caller. + js.Global().Get("onWasmInitialized").Invoke() + + <-make(chan bool) + fmt.Println("[WW] Closing xxDK WebAssembly State Database Worker.") + os.Exit(0) + }, +} + +var ( + logLevel jww.Threshold +) + +func init() { + // Initialize all startup flags + channelsCmd.Flags().IntVarP((*int)(&logLevel), "logLevel", "l", 2, + "Sets the log level output when outputting to the Javascript console. "+ + "0 = TRACE, 1 = DEBUG, 2 = INFO, 3 = WARN, 4 = ERROR, "+ + "5 = CRITICAL, 6 = FATAL, -1 = disabled.") +} diff --git a/indexedDb/worker/state/tags.go b/indexedDb/worker/state/tags.go new file mode 100644 index 0000000000000000000000000000000000000000..0f6327d9f54509735fd6e6a1d7de57e3b8015a04 --- /dev/null +++ b/indexedDb/worker/state/tags.go @@ -0,0 +1,20 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 xx foundation // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file. // +//////////////////////////////////////////////////////////////////////////////// + +//go:build js && wasm + +package dm + +import "gitlab.com/elixxir/xxdk-wasm/worker" + +// List of tags that can be used when sending a message or registering a handler +// to receive a message. +const ( + NewStateTag worker.Tag = "NewState" + SetTag worker.Tag = "Set" + GetTag worker.Tag = "Get" +)