From e2c2fbbb33c0559d3b52645e24ddf99f99d07628 Mon Sep 17 00:00:00 2001 From: Jono Wenger <jono@elixxir.io> Date: Tue, 16 Aug 2022 16:39:41 -0700 Subject: [PATCH] Implement single.go --- main.go | 4 ++ wasm/e2e.go | 2 +- wasm/e2e_test.go | 1 - wasm/single.go | 128 ++++++++++++++++++++++++++++++++++++++++++++ wasm/single_test.go | 39 ++++++++++++++ 5 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 wasm/single.go create mode 100644 wasm/single_test.go diff --git a/main.go b/main.go index 23fa7127..d53e5c47 100644 --- a/main.go +++ b/main.go @@ -104,6 +104,10 @@ func main() { js.Global().Set("AsyncRequestRestLike", js.FuncOf(wasm.AsyncRequestRestLike)) + // bindings/single.go + js.Global().Set("TransmitSingleUse", js.FuncOf(wasm.TransmitSingleUse)) + js.Global().Set("Listen", js.FuncOf(wasm.Listen)) + <-make(chan bool) os.Exit(0) } diff --git a/wasm/e2e.go b/wasm/e2e.go index 46196fdf..de160033 100644 --- a/wasm/e2e.go +++ b/wasm/e2e.go @@ -83,7 +83,7 @@ func (e *E2e) GetID(js.Value, []js.Value) interface{} { // - args[0] - ID of Cmix object in tracker (int). // - args[1] - Javascript object that has functions that implement the // [bindings.AuthCallbacks] interface. -// - args[2] - JSON of the [xxdk.ReceptionIdentity] object (Uint8Array). +// - args[2] - JSON of the [xxdk.ReceptionIdentity] (Uint8Array). // - args[3] - JSON of [xxdk.E2EParams] (Uint8Array). // // Returns: diff --git a/wasm/e2e_test.go b/wasm/e2e_test.go index ef6323ac..6d652c95 100644 --- a/wasm/e2e_test.go +++ b/wasm/e2e_test.go @@ -6,7 +6,6 @@ //////////////////////////////////////////////////////////////////////////////// //go:build js && wasm -// +build js,wasm package wasm diff --git a/wasm/single.go b/wasm/single.go new file mode 100644 index 00000000..7b664ca4 --- /dev/null +++ b/wasm/single.go @@ -0,0 +1,128 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +//go:build js && wasm + +package wasm + +import ( + "gitlab.com/elixxir/client/bindings" + "syscall/js" +) + +//////////////////////////////////////////////////////////////////////////////// +// Public Wrapper Methods // +//////////////////////////////////////////////////////////////////////////////// + +// TransmitSingleUse transmits payload to recipient via single-use. +// +// Parameters: +// - args[0] - ID of E2e object in tracker (int). +// - args[1] - JSON of recipient [contact.Contact] (Uint8Array). +// - args[2] - tag that identifies the single-use message (string). +// - args[3] - message contents (Uint8Array). +// - args[4] - JSON of [single.RequestParams] (Uint8Array). +// - args[5] - the callback that will be called when a response is received. It +// is a Javascript object that has functions that implement the +// [bindings.SingleUseResponse] interface. +// +// Returns: +// - JSON [bindings.SingleUseSendReport], which can be passed into +// Cmix.WaitForRoundResult to see if the send succeeded (Uint8Array). +// - Throws a TypeError if transmission fails. +func TransmitSingleUse(_ js.Value, args []js.Value) interface{} { + e2eID := args[0].Int() + recipient := CopyBytesToGo(args[1]) + tag := args[2].String() + payload := CopyBytesToGo(args[3]) + paramsJSON := CopyBytesToGo(args[4]) + responseCB := &singleUseResponse{args[5].Get("Callback").Invoke} + + report, err := bindings.TransmitSingleUse( + e2eID, recipient, tag, payload, paramsJSON, responseCB) + if err != nil { + Throw(TypeError, err.Error()) + return nil + } + + return CopyBytesToJS(report) +} + +// Listen starts a single-use listener on a given tag using the passed in E2e +// object and SingleUseCallback func. +// +// Parameters: +// - args[0] - ID of E2e object in tracker (int). +// - args[1] - tag that identifies the single-use message (string). +// - args[2] - the callback that will be called when a response is received. It +// is a Javascript object that has functions that implement the +// [bindings.SingleUseCallback] interface. +// +// Returns: +// - Javascript representation of the Stopper object, an interface containing a +// function used to stop the listener. +// - Throws a TypeError if listening fails. +func Listen(_ js.Value, args []js.Value) interface{} { + cb := &singleUseCallback{args[2].Get("Callback").Invoke} + api, err := bindings.Listen(args[0].Int(), args[1].String(), cb) + if err != nil { + Throw(TypeError, err.Error()) + return nil + } + + return newStopperJS(api) +} + +//////////////////////////////////////////////////////////////////////////////// +// Function Types // +//////////////////////////////////////////////////////////////////////////////// + +// Stopper wraps the [bindings.Stopper] interface so its methods can be wrapped +// to be Javascript compatible. +type Stopper struct { + api bindings.Stopper +} + +// newStopperJS creates a new Javascript compatible object +// (map[string]interface{}) that matches the Stopper structure. +func newStopperJS(api bindings.Stopper) map[string]interface{} { + s := Stopper{api} + stopperMap := map[string]interface{}{ + "Stop": js.FuncOf(s.Stop), + } + + return stopperMap +} + +func (s *Stopper) Stop(js.Value, []js.Value) interface{} { + s.api.Stop() + return nil +} + +//////////////////////////////////////////////////////////////////////////////// +// Callback Wrappers // +//////////////////////////////////////////////////////////////////////////////// + +// singleUseCallback wraps Javascript callbacks to adhere to the +// [bindings.SingleUseCallback] interface. +type singleUseCallback struct { + callback func(args ...interface{}) js.Value +} + +func (suc *singleUseCallback) Callback(callbackReport []byte, err error) { + suc.callback(CopyBytesToJS(callbackReport), err.Error()) +} + +// singleUseResponse wraps Javascript callbacks to adhere to the +// [bindings.SingleUseResponse] interface. +type singleUseResponse struct { + callback func(args ...interface{}) js.Value +} + +func (sur *singleUseResponse) Callback(responseReport []byte, err error) { + sur.callback(CopyBytesToJS(responseReport), err.Error()) +} diff --git a/wasm/single_test.go b/wasm/single_test.go new file mode 100644 index 00000000..3bdd9933 --- /dev/null +++ b/wasm/single_test.go @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +//go:build js && wasm + +package wasm + +import ( + "reflect" + "testing" +) + +// Tests that the map representing Stopper returned by newStopperJS contains all +// of the methods on Stopper. +func Test_newStopperJS(t *testing.T) { + stopperType := reflect.TypeOf(&Stopper{}) + + s := newStopperJS(&stopper{}) + if len(s) != stopperType.NumMethod() { + t.Errorf("Stopper JS object does not have all methods."+ + "\nexpected: %d\nreceived: %d", stopperType.NumMethod(), len(s)) + } + + for i := 0; i < stopperType.NumMethod(); i++ { + method := stopperType.Method(i) + + if _, exists := s[method.Name]; !exists { + t.Errorf("Method %s does not exist.", method.Name) + } + } +} + +type stopper struct{} + +func (s *stopper) Stop() {} -- GitLab