diff --git a/README.md b/README.md index 87ac6d17986684565ddae99f0406643f6f2b4545..56c5fce1c5abd0b2976ccb64aefa9e62793dadf6 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,47 @@ # xxdk-WASM -WebAssembly bindings for xxDK. +This repository contains the WebAssembly bindings for xxDK. It also includes a +test server to serve the compiled WebAssembly module. ## Building +The repository can only be compiled to a WebAssembly binary using `GOOS=js` and +`GOARCH=wasm`. + ```shell $ GOOS=js GOARCH=wasm go build -o xxdk.wasm ``` -### Running Tests - -To run unit tests, you need to first install -[wasmbrowsertest](https://github.com/agnivade/wasmbrowsertest). +### Running Unit Tests -`wasm/wasm_js.s` contains commands only recognized by the Go WebAssembly -compiler and thus cause compile errors when running tests. It needs to be -excluded when running tests. +Because the bindings use `syscall/js`, tests cannot only be run in a browser. To +automate this process first install +[wasmbrowsertest](https://github.com/agnivade/wasmbrowsertest). Then, tests can +be run using the following command. ```shell -$ GOOS=js GOARCH=wasm go test +$ GOOS=js GOARCH=wasm go test ./... ``` +Note, this will fail because `wasm/wasm_js.s` contains commands only recognized +by the Go WebAssembly compiler and for some reason not recognized by the test +runner. To get tests to run, temporarily delete the body of `wasm/wasm_js.s` +during testing. + ## Testing -The `test` directory contains a website and server to run the compiled -WebAssembly module. `assets` contains the website and `server` contains a small -Go HTTP server. +The `test` directory contains `assets`, a simple web page to run the Javascript, +and `server`, which runs a simple Go HTTP server to deliver the webpage. + +To run the server, first compile the bindings and save them to the `assets` +directory. Then run the server ```shell $ GOOS=js GOARCH=wasm go build -o test/assets/xxdk.wasm $ go run test/server/main.go ``` -### `wasm_exec.js` +## `wasm_exec.js` `wasm_exec.js` is provided by Go and is used to import the WebAssembly module in the browser. It can be retrieved from Go using the following command. diff --git a/wasm/backup.go b/wasm/backup.go index 33a3edcf4ce134f7bf968b377966e447891ce403..94ebaad4f140e0f6775bcb29efd70747f3227908 100644 --- a/wasm/backup.go +++ b/wasm/backup.go @@ -51,9 +51,9 @@ func (ubf *updateBackupFunc) UpdateBackup(encryptedBackup []byte) { // Client functions // //////////////////////////////////////////////////////////////////////////////// -// NewCmixFromBackup initializes a new e2e storage from an encrypted -// backup. Users of this function should delete the storage directory on error. -// Users of this function should call LoadCmix as normal once this call succeeds. +// NewCmixFromBackup initializes a new e2e storage from an encrypted backup. +// Users of this function should delete the storage directory on error. Users of +// this function should call LoadCmix as normal once this call succeeds. // // Parameters: // - args[0] - JSON of the NDF (string). diff --git a/wasm/broadcast.go b/wasm/broadcast.go index 65152f1b054fa02840e43141d29f03cf0e863cff..2efc02512db1b988e81d89be53d839ce78894257 100644 --- a/wasm/broadcast.go +++ b/wasm/broadcast.go @@ -14,6 +14,8 @@ import ( "syscall/js" ) +// Channel wraps the [bindings.Channel] object so its methods can be wrapped to +// be Javascript compatible. type Channel struct { api *bindings.Channel } diff --git a/wasm/delivery.go b/wasm/delivery.go index 8bf3dcbe79a272cb2cd206e2457042bca78de1fe..603d692273c4a044bc3b5676576c4c691981fb3f 100644 --- a/wasm/delivery.go +++ b/wasm/delivery.go @@ -24,9 +24,10 @@ func (mdc *messageDeliveryCallback) EventCallback( mdc.eventCallback(delivered, timedOut, CopyBytesToJS(roundResults)) } -// WaitForRoundResult allows the caller to get notified if the rounds a message was sent in successfully completed. Under the hood, this uses an API -// that uses the internal round data, network historical round lookup, and -// waiting on network events to determine what has (or will) occur. +// WaitForRoundResult allows the caller to get notified if the rounds a message +// was sent in successfully completed. Under the hood, this uses an API that +// uses the internal round data, network historical round lookup, and waiting on +// network events to determine what has (or will) occur. // // This function takes the marshaled send report to ensure a memory leak does // not occur as a result of both sides of the bindings holding a reference to diff --git a/wasm/dummy.go b/wasm/dummy.go index 449facb27aa4a872bd99b25de5a81295fe08b098..33b9b8118b7478d0d958d4fe50a473459bc9aae6 100644 --- a/wasm/dummy.go +++ b/wasm/dummy.go @@ -33,11 +33,11 @@ func newDummyTrafficJS(newDT *bindings.DummyTraffic) map[string]interface{} { } // NewDummyTrafficManager creates a DummyTraffic manager and initialises the -// dummy traffic sending thread. Note that the manager does not start sending dummy -// traffic until `True` is passed into DummyTraffic.SetStatus. The time duration -// between each sending operation and the amount of messages sent each interval -// are randomly generated values with bounds defined by the -// given parameters below. +// dummy traffic sending thread. Note that the manager does not start sending +// dummy traffic until true is passed into DummyTraffic.SetStatus. The time +// duration between each sending operation and the amount of messages sent each +// interval are randomly generated values with bounds defined by the given +// parameters below. // // Parameters: // - args[0] - a Cmix object ID in the tracker (int). @@ -45,9 +45,9 @@ func newDummyTrafficJS(newDT *bindings.DummyTraffic) map[string]interface{} { // sending cycle (int). // - args[2] - the average duration, in milliseconds, to wait between sends // (int). -// - args[3] - the upper bound of the interval between sending cycles, -// in milliseconds (int). Sends occur every average send (args[2]) +/- a -// random duration with an upper bound of args[3]. +// - args[3] - the upper bound of the interval between sending cycles, in +// milliseconds. Sends occur every average send (args[2]) +/- a random +// duration with an upper bound of args[3] (int). // // Returns: // - Javascript representation of the DummyTraffic object. @@ -71,8 +71,8 @@ func NewDummyTrafficManager(_ js.Value, args []js.Value) interface{} { // once that operation has completed. // // Parameters: -// - args[0] - Input should be true if you want to send dummy messages and false -// if you want to pause dummy messages (boolean). +// - args[0] - Input should be true if you want to send dummy messages and +// false if you want to pause dummy messages (boolean). // // Returns: // - Throws a TypeError if the DummyTraffic.SetStatus is called too frequently, diff --git a/wasm/e2e.go b/wasm/e2e.go index b0f79041b943bfeca08d0726a6a90d8897f06ee7..cc28db341524fa17fb1914fdc54970b6efcac7d7 100644 --- a/wasm/e2e.go +++ b/wasm/e2e.go @@ -111,7 +111,7 @@ func Login(_ js.Value, args []js.Value) interface{} { // // Parameters: // - args[0] - ID of Cmix object in tracker (int). -// - args[1] - Javascript object that has functions that implement the. +// - args[1] - Javascript object that has functions that implement the // [bindings.AuthCallbacks] interface. // - args[2] - JSON of the [xxdk.ReceptionIdentity] object (Uint8Array). // - args[3] - JSON of [xxdk.E2EParams] (Uint8Array). @@ -210,19 +210,22 @@ func newAuthCallbacks(value js.Value) *authCallbacks { return a } -func (a *authCallbacks) Request(contact, receptionId []byte, ephemeralId, roundId int64) { +func (a *authCallbacks) Request( + contact, receptionId []byte, ephemeralId, roundId int64) { if a.request != nil { a.request(contact, receptionId, ephemeralId, roundId) } } -func (a *authCallbacks) Confirm(contact, receptionId []byte, ephemeralId, roundId int64) { +func (a *authCallbacks) Confirm( + contact, receptionId []byte, ephemeralId, roundId int64) { if a.confirm != nil { a.confirm(contact, receptionId, ephemeralId, roundId) } } -func (a *authCallbacks) Reset(contact, receptionId []byte, ephemeralId, roundId int64) { +func (a *authCallbacks) Reset( + contact, receptionId []byte, ephemeralId, roundId int64) { if a.reset != nil { a.reset(contact, receptionId, ephemeralId, roundId) } diff --git a/wasm/group.go b/wasm/group.go index d75c10a5624a4b9235930b9564be5d602e16f220..4fd74d2142ad141047ac978a9c98f52421fb247a 100644 --- a/wasm/group.go +++ b/wasm/group.go @@ -32,6 +32,7 @@ func newGroupChatJS(api *bindings.GroupChat) map[string]interface{} { "MakeGroup": js.FuncOf(gc.MakeGroup), "ResendRequest": js.FuncOf(gc.ResendRequest), "JoinGroup": js.FuncOf(gc.JoinGroup), + "LeaveGroup": js.FuncOf(gc.LeaveGroup), "Send": js.FuncOf(gc.Send), "GetGroups": js.FuncOf(gc.GetGroups), "GetGroup": js.FuncOf(gc.GetGroup), diff --git a/wasm/utils.go b/wasm/utils.go index 7b0e32df9b70b854ec1263ee9a307447ff47022d..ea4695626442060f48e0ea30f75f988c8d7bc4d1 100644 --- a/wasm/utils.go +++ b/wasm/utils.go @@ -14,18 +14,23 @@ import ( "syscall/js" ) +// CopyBytesToGo copies the Uint8Array stored in the js.Value to []byte. This is +// a wrapper for js.CopyBytesToGo to make it more convenient. func CopyBytesToGo(src js.Value) []byte { b := make([]byte, src.Length()) js.CopyBytesToGo(b, src) return b } +// CopyBytesToJS copies the []byte to a Uint8Array stored in a js.Value. This is +// a wrapper for js.CopyBytesToJS to make it more convenient. func CopyBytesToJS(src []byte) js.Value { dst := js.Global().Get("Uint8Array").New(len(src)) js.CopyBytesToJS(dst, src) return dst } +// JsonToJS converts a marshalled JSON bytes to a Javascript object. func JsonToJS(src []byte) js.Value { var inInterface map[string]interface{} err := json.Unmarshal(src, &inInterface) @@ -37,9 +42,12 @@ func JsonToJS(src []byte) js.Value { return js.ValueOf(inInterface) } -// Throw function stub to throws Javascript exceptions. +// Throw function stub to throws Javascript exceptions. The exception must be +// one of the defined Exception below. Any other error types will result in an +// error. func Throw(exception Exception, message string) +// Exception are the possible Javascript error types that can be thrown. type Exception string const (