diff --git a/README.md b/README.md index 2447a9ea598e036b56435984c15af482f6396da8..b080e856a7fdfe0f22328e5cd777a1d84450542d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ This repository contains the WebAssembly bindings for xxDK. It also includes examples and a test server to serve the compiled WebAssembly module. +**Note:** If you are updating the version of Go that this repository uses, you +need to ensure that you update the wasm_exec.js file as described +[below](#wasm_execjs). + ## Building The repository can only be compiled to a WebAssembly binary using `GOOS=js` and @@ -51,7 +55,7 @@ Navigate to http://localhost:9090 to see the webpage. the browser. It can be retrieved from Go using the following command. ```shell -$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" test/assets/ +$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" . ``` Note that this repository makes edits to `wasm_exec.js` and you must either use diff --git a/indexedDb/implementation.go b/indexedDb/implementation.go index 632bd1317f09a9ebfb17163ae8f690f9c9986350..6e6cc9158423b876f61bc8550688252d93c5b5f5 100644 --- a/indexedDb/implementation.go +++ b/indexedDb/implementation.go @@ -2,7 +2,7 @@ // Copyright © 2022 xx foundation // // // // Use of this source code is governed by a license that can be found in the // -// LICENSE file // +// LICENSE file. // //////////////////////////////////////////////////////////////////////////////// //go:build js && wasm @@ -28,16 +28,18 @@ import ( "gitlab.com/xx_network/primitives/id" ) -// dbTimeout is the global timeout for operations with the storage context.Contact +// dbTimeout is the global timeout for operations with the storage +// context.Contact. const dbTimeout = time.Second -// wasmModel implements [channels.EventModel] interface which uses the channels -// system passed an object which adheres to in order to get events on the channel. +// wasmModel implements [channels.EventModel] interface, which uses the channels +// system passed an object that adheres to in order to get events on the +// channel. type wasmModel struct { db *idb.Database } -// newContext builds a context for database operations +// newContext builds a context for database operations. func newContext() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), dbTimeout) } @@ -98,8 +100,7 @@ func (w *wasmModel) JoinChannel(channel *cryptoBroadcast.Channel) { "Adding Channel failed: %+v", err)) return } - jww.DEBUG.Printf("Successfully added channel: %s", - channel.ReceptionID.String()) + jww.DEBUG.Printf("Successfully added channel: %s", channel.ReceptionID) } // LeaveChannel is called whenever a channel is left locally. @@ -137,15 +138,17 @@ func (w *wasmModel) LeaveChannel(channelID *id.ID) { "Deleting Channel failed: %+v", err)) return } - jww.DEBUG.Printf("Successfully deleted channel: %s", channelID.String()) + jww.DEBUG.Printf("Successfully deleted channel: %s", channelID) } -// ReceiveMessage is called whenever a message is received on a given channel -// It may be called multiple times on the same message, it is incumbent on -// the user of the API to filter such called by message ID. -func (w *wasmModel) ReceiveMessage(channelID *id.ID, messageID cryptoChannel.MessageID, - senderUsername string, text string, timestamp time.Time, lease time.Duration, - _ rounds.Round, status channels.SentStatus) { +// ReceiveMessage is called whenever a message is received on a given channel. +// +// It may be called multiple times on the same message; it is incumbent on the +// user of the API to filter such called by message ID. +func (w *wasmModel) ReceiveMessage(channelID *id.ID, + messageID cryptoChannel.MessageID, senderUsername string, text string, + timestamp time.Time, lease time.Duration, _ rounds.Round, + status channels.SentStatus) { parentErr := errors.New("failed to ReceiveMessage") err := w.receiveHelper(buildMessage(channelID.Marshal(), messageID.Bytes(), @@ -155,14 +158,16 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID, messageID cryptoChannel.Mes } } -// ReceiveReply is called whenever a message is received which is a reply -// on a given channel. It may be called multiple times on the same message, -// it is incumbent on the user of the API to filter such called by message ID -// Messages may arrive our of order, so a reply in theory can arrive before -// the initial message, as a result it may be important to buffer replies. -func (w *wasmModel) ReceiveReply(channelID *id.ID, messageID cryptoChannel.MessageID, - replyTo cryptoChannel.MessageID, senderUsername string, text string, - timestamp time.Time, lease time.Duration, _ rounds.Round, status channels.SentStatus) { +// ReceiveReply is called whenever a message is received that is a reply on a +// given channel. It may be called multiple times on the same message; it is +// incumbent on the user of the API to filter such called by message ID. +// +// Messages may arrive our of order, so a reply, in theory, can arrive before +// the initial message. As a result, it may be important to buffer replies. +func (w *wasmModel) ReceiveReply(channelID *id.ID, + messageID cryptoChannel.MessageID, replyTo cryptoChannel.MessageID, + senderUsername string, text string, timestamp time.Time, + lease time.Duration, _ rounds.Round, status channels.SentStatus) { parentErr := errors.New("failed to ReceiveReply") err := w.receiveHelper(buildMessage(channelID.Marshal(), messageID.Bytes(), @@ -172,14 +177,16 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID, messageID cryptoChannel.Messa } } -// ReceiveReaction is called whenever a reaction to a message is received -// on a given channel. It may be called multiple times on the same reaction, -// it is incumbent on the user of the API to filter such called by message ID -// Messages may arrive our of order, so a reply in theory can arrive before -// the initial message, as a result it may be important to buffer reactions. -func (w *wasmModel) ReceiveReaction(channelID *id.ID, messageID cryptoChannel.MessageID, - reactionTo cryptoChannel.MessageID, senderUsername string, reaction string, - timestamp time.Time, lease time.Duration, _ rounds.Round, status channels.SentStatus) { +// ReceiveReaction is called whenever a reaction to a message is received on a +// given channel. It may be called multiple times on the same reaction; it is +// incumbent on the user of the API to filter such called by message ID. +// +// Messages may arrive our of order, so a reply, in theory, can arrive before +// the initial message. As a result, it may be important to buffer reactions. +func (w *wasmModel) ReceiveReaction(channelID *id.ID, + messageID cryptoChannel.MessageID, reactionTo cryptoChannel.MessageID, + senderUsername string, reaction string, timestamp time.Time, + lease time.Duration, _ rounds.Round, status channels.SentStatus) { parentErr := errors.New("failed to ReceiveReaction") err := w.receiveHelper(buildMessage(channelID.Marshal(), messageID.Bytes(), @@ -189,9 +196,9 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID, messageID cryptoChannel.Me } } -// UpdateSentStatus is called whenever the SentStatus of a message -// has changed -// TODO: Potential race condition due to separate get/update operations +// UpdateSentStatus is called whenever the [channels.SentStatus] of a message +// has changed. +// TODO: Potential race condition due to separate get/update operations. func (w *wasmModel) UpdateSentStatus(messageID cryptoChannel.MessageID, status channels.SentStatus) { parentErr := errors.New("failed to UpdateSentStatus") @@ -221,10 +228,10 @@ func (w *wasmModel) UpdateSentStatus(messageID cryptoChannel.MessageID, } // buildMessage is a private helper that converts typical [channels.EventModel] -// inputs into a basic Message structure for insertion into storage -func buildMessage(channelID []byte, messageID []byte, - parentId []byte, senderUsername string, text string, - timestamp time.Time, lease time.Duration, status channels.SentStatus) *Message { +// inputs into a basic Message structure for insertion into storage. +func buildMessage(channelID, messageID, parentId []byte, senderUsername, + text string, timestamp time.Time, lease time.Duration, + status channels.SentStatus) *Message { return &Message{ Id: messageID, SenderUsername: senderUsername, @@ -239,7 +246,7 @@ func buildMessage(channelID []byte, messageID []byte, } } -// receiveHelper is a private helper for receiving any sort of message +// receiveHelper is a private helper for receiving any sort of message. func (w *wasmModel) receiveHelper(newMessage *Message) error { // Convert to jsObject newMessageJson, err := json.Marshal(newMessage) @@ -274,12 +281,13 @@ func (w *wasmModel) receiveHelper(newMessage *Message) error { if err != nil { return errors.Errorf("Upserting Message failed: %+v", err) } - jww.DEBUG.Printf("Successfully stored message from %s", - newMessage.SenderUsername) + jww.DEBUG.Printf( + "Successfully stored message from %s", newMessage.SenderUsername) return nil } -// get is a generic private helper for getting values from the given [idb.ObjectStore]. +// get is a generic private helper for getting values from the given +// [idb.ObjectStore]. func (w *wasmModel) get(objectStoreName string, key js.Value) (string, error) { parentErr := errors.Errorf("failed to get %s/%s", objectStoreName, key) @@ -317,7 +325,8 @@ func (w *wasmModel) get(objectStoreName string, key js.Value) (string, error) { return resultStr, nil } -// dump given [idb.ObjectStore] contents to string slice for debugging purposes +// dump returns the given [idb.ObjectStore] contents to string slice for +// debugging purposes. func (w *wasmModel) dump(objectStoreName string) ([]string, error) { parentErr := errors.Errorf("failed to dump %s", objectStoreName) diff --git a/indexedDb/implementation_test.go b/indexedDb/implementation_test.go index a7b005abb782c0151bb0045d0eb9239c611ac947..a9efbcd182f56b77ddeab1127a5de2a2d58fe9be 100644 --- a/indexedDb/implementation_test.go +++ b/indexedDb/implementation_test.go @@ -2,7 +2,7 @@ // Copyright © 2022 xx foundation // // // // Use of this source code is governed by a license that can be found in the // -// LICENSE file // +// LICENSE file. // //////////////////////////////////////////////////////////////////////////////// package indexedDb @@ -24,7 +24,7 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -// Test UpdateSentStatus happy path and ensure fields don't change +// Test wasmModel.UpdateSentStatus happy path and ensure fields don't change. func TestWasmModel_UpdateSentStatus(t *testing.T) { testString := "test" testMsgId := channel.MakeMessageID([]byte(testString)) @@ -77,7 +77,7 @@ func TestWasmModel_UpdateSentStatus(t *testing.T) { } } -// Smoke test JoinChannel/LeaveChannel happy paths +// Smoke test wasmModel.JoinChannel/wasmModel.LeaveChannel happy paths. func TestWasmModel_JoinChannel_LeaveChannel(t *testing.T) { eventModel, err := newWasmModel("test") if err != nil { diff --git a/indexedDb/init.go b/indexedDb/init.go index f256b935111a330c30779eb697a1f6da4195dc84..fa82a6e29e76db0310e7db6b69049aca14e5d272 100644 --- a/indexedDb/init.go +++ b/indexedDb/init.go @@ -2,7 +2,7 @@ // Copyright © 2022 xx foundation // // // // Use of this source code is governed by a license that can be found in the // -// LICENSE file // +// LICENSE file. // //////////////////////////////////////////////////////////////////////////////// //go:build js && wasm @@ -20,19 +20,21 @@ import ( ) const ( - // databaseSuffix to be appended to the name of the database + // databaseSuffix is the suffix to be appended to the name of the database. databaseSuffix = "_messenger" - // currentVersion of the IndexDb runtime. Used for migration purposes. + + // currentVersion is the current version of the IndexDb runtime. Used for + // migration purposes. currentVersion uint = 1 ) -// NewWasmEventModel returns a [channels.EventModel] backed by a wasmModel +// NewWasmEventModel returns a [channels.EventModel] backed by a wasmModel. func NewWasmEventModel(username string) (channels.EventModel, error) { databaseName := username + databaseSuffix return newWasmModel(databaseName) } -// newWasmModel creates the given [idb.Database] and returns a wasmModel +// newWasmModel creates the given [idb.Database] and returns a wasmModel. func newWasmModel(databaseName string) (*wasmModel, error) { // Attempt to open database object ctx, cancel := newContext() @@ -40,13 +42,12 @@ func newWasmModel(databaseName string) (*wasmModel, error) { openRequest, _ := idb.Global().Open(ctx, databaseName, currentVersion, func(db *idb.Database, oldVersion, newVersion uint) error { if oldVersion == newVersion { - jww.INFO.Printf("IndexDb version is current: v%d", - newVersion) + jww.INFO.Printf("IndexDb version is current: v%d", newVersion) return nil } - jww.INFO.Printf("IndexDb upgrade required: v%d -> v%d", - oldVersion, newVersion) + jww.INFO.Printf( + "IndexDb upgrade required: v%d -> v%d", oldVersion, newVersion) if oldVersion == 0 && newVersion == 1 { return v1Upgrade(db) @@ -63,7 +64,9 @@ func newWasmModel(databaseName string) (*wasmModel, error) { } // v1Upgrade performs the v0 -> v1 database upgrade. -// This can never be changed without permanently breaking backwards compatibility. +// +// This can never be changed without permanently breaking backwards +// compatibility. func v1Upgrade(db *idb.Database) error { storeOpts := idb.ObjectStoreOptions{ KeyPath: js.ValueOf(pkeyName), diff --git a/indexedDb/model.go b/indexedDb/model.go index 9354e67a869c87f70824dc52fecc67a1058671d2..e8050d52fed2d4e4ab3762e812dd2b0375839cc6 100644 --- a/indexedDb/model.go +++ b/indexedDb/model.go @@ -2,7 +2,7 @@ // Copyright © 2022 xx foundation // // // // Use of this source code is governed by a license that can be found in the // -// LICENSE file // +// LICENSE file. // //////////////////////////////////////////////////////////////////////////////// //go:build js && wasm @@ -36,7 +36,9 @@ const ( ) // Message defines the IndexedDb representation of a single Message. +// // A Message belongs to one Channel. +// // A Message may belong to one Message (Parent). type Message struct { Id []byte `json:"id"` // Matches pkeyName @@ -51,7 +53,8 @@ type Message struct { Text string `json:"text"` } -// Channel defines the IndexedDb representation of a single Channel +// Channel defines the IndexedDb representation of a single Channel. +// // A Channel has many Message. type Channel struct { Id []byte `json:"id"` // Matches pkeyName diff --git a/test/index.html b/test/index.html index 0769a535b3dcb212d86f9c9e5a57fb8fc3eb5c21..28754e279ede06c80937343c02bd41b6e3a2f7d0 100644 --- a/test/index.html +++ b/test/index.html @@ -13,10 +13,10 @@ <script src="../wasm_exec.js"></script> <script> - const go = new Go(); - WebAssembly.instantiateStreaming(fetch("xxdk.wasm"), go.importObject).then((result) => { - go.run(result.instance); - }); + const go = new Go(); + WebAssembly.instantiateStreaming(fetch("xxdk.wasm"), go.importObject).then((result) => { + go.run(result.instance); + }); </script> </head> <body></body> diff --git a/utils/utils.go b/utils/utils.go index 15dcc579dbc323d99e6b20b74664ce779d0c7193..e1d3d1c4b2e8a72217848f7d1ac821d3699e7fb2 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -16,9 +16,20 @@ import ( ) var ( - Error = js.Global().Get("Error") - JSON = js.Global().Get("JSON") - Promise = js.Global().Get("Promise") + // Error is the Javascript Error object. It used to create new Javascript + // errors. + Error = js.Global().Get("Error") + + // JSON is the Javascript JSON object. It is used to perform JSON operations + // on the Javascript layer. + JSON = js.Global().Get("JSON") + + // Promise is the Javascript Promise object. It is used to generate new + // promises. + Promise = js.Global().Get("Promise") + + // Uint8Array is the Javascript Uint8Array object. It is used to create new + // Uint8Array. Uint8Array = js.Global().Get("Uint8Array") ) @@ -38,6 +49,10 @@ func WrapCB(parent js.Value, m string) func(args ...interface{}) js.Value { } } +// PromiseFn converts the Javascript Promise construct into Go. +// +// Call resolve with the return of the function on success. Call reject with an +// error on failure. type PromiseFn func(resolve, reject func(args ...interface{}) js.Value) // CreatePromise creates a Javascript promise to return the value of a blocking diff --git a/wasm/backup.go b/wasm/backup.go index ca3072c0105ffc87b170fe3d71aaeb21ea27bde9..cd4200b5dc2a25a61d68a38cdcc8f2d672a8406e 100644 --- a/wasm/backup.go +++ b/wasm/backup.go @@ -44,6 +44,10 @@ type updateBackupFunc struct { updateBackup func(args ...interface{}) js.Value } +// UpdateBackup is a function callback that returns new backups. +// +// Parameters: +// - encryptedBackup - returns the bytes of the encrypted backup (Uint8Array). func (ubf *updateBackupFunc) UpdateBackup(encryptedBackup []byte) { ubf.updateBackup(utils.CopyBytesToJS(encryptedBackup)) } diff --git a/wasm/broadcast.go b/wasm/broadcast.go index 9c14cec1414549eae1fee68872f68f34fa920e80..f87f43f69666e4f0c29099dcccb42b02a15c20ea 100644 --- a/wasm/broadcast.go +++ b/wasm/broadcast.go @@ -66,6 +66,13 @@ type broadcastListener struct { callback func(args ...interface{}) js.Value } +// Callback is used to listen for broadcast messages. +// +// Parameters: +// - payload - returns the JSON of [bindings.E2ESendReport], which can be +// passed into cmix.WaitForRoundResult to see if the send succeeded +// (Uint8Array). +// - err - returns an error on failure (Error). func (bl *broadcastListener) Callback(payload []byte, err error) { bl.callback(utils.CopyBytesToJS(payload), utils.JsTrace(err)) } diff --git a/wasm/channels.go b/wasm/channels.go index ca2682d13c23bcb966b70524a0c7be7dcd24f721..431df0eabb5e9db2145d335c3cd13a694ff67711 100644 --- a/wasm/channels.go +++ b/wasm/channels.go @@ -60,9 +60,6 @@ func (ch *ChannelsManager) GetID(js.Value, []js.Value) interface{} { } // NewChannelsManager constructs a ChannelsManager. -// FIXME: This is a work in progress and should not be used an event model is -// implemented in the style of the bindings layer's AuthCallbacks. Remove this -// note when that has been done. // // Parameters: // - args[0] - ID of ChannelsManager object in tracker (int). This can be @@ -438,6 +435,12 @@ type channelMessageReceptionCallback struct { callback func(args ...interface{}) js.Value } +// Callback returns the context for a channel message. +// +// Parameters: +// - receivedChannelMessageReport - returns the JSON of +// [bindings.ReceivedChannelMessageReport] (Uint8Array). +// - err - returns an error on failure (Error). func (cmrCB *channelMessageReceptionCallback) Callback( receivedChannelMessageReport []byte, err error) { cmrCB.callback(utils.CopyBytesToJS(receivedChannelMessageReport), diff --git a/wasm/cmix.go b/wasm/cmix.go index 3b5a050e8ffadf88fe8d23bea8ce3e985e48b013..52af87f78907127c0cbd4c1f8fb413f4dbcf00cc 100644 --- a/wasm/cmix.go +++ b/wasm/cmix.go @@ -30,9 +30,12 @@ func newCmixJS(api *bindings.Cmix) map[string]interface{} { "GetID": js.FuncOf(c.GetID), // identity.go - "MakeReceptionIdentity": js.FuncOf(c.MakeReceptionIdentity), - "MakeLegacyReceptionIdentity": js.FuncOf(c.MakeLegacyReceptionIdentity), - "GetReceptionRegistrationValidationSignature": js.FuncOf(c.GetReceptionRegistrationValidationSignature), + "MakeReceptionIdentity": js.FuncOf( + c.MakeReceptionIdentity), + "MakeLegacyReceptionIdentity": js.FuncOf( + c.MakeLegacyReceptionIdentity), + "GetReceptionRegistrationValidationSignature": js.FuncOf( + c.GetReceptionRegistrationValidationSignature), // follow.go "StartNetworkFollower": js.FuncOf(c.StartNetworkFollower), diff --git a/wasm/connect.go b/wasm/connect.go index 92e4bed661e8928884f3bdc31aef59a50a92dfe0..5e005925b03a2f22be831499464113e5d0817488 100644 --- a/wasm/connect.go +++ b/wasm/connect.go @@ -133,8 +133,17 @@ type listener struct { name func(args ...interface{}) js.Value } +// Hear is called to receive a message in the UI. +// +// Parameters: +// - item - returns the JSON of [bindings.Message] (Uint8Array). func (l *listener) Hear(item []byte) { l.hear(utils.CopyBytesToJS(item)) } -func (l *listener) Name() string { return l.name().String() } + +// Name returns a name; used for debugging. +// +// Returns: +// - string +func (l *listener) Name() string { return l.name().String() } // RegisterListener is used for E2E reception and allows for reading data sent // from the partner.Manager. diff --git a/wasm/delivery.go b/wasm/delivery.go index f6748f22681b9f665f5b02ec04aba8468dec8ef3..f65af1e933da6a6634bf9ee747e75bd3c552394c 100644 --- a/wasm/delivery.go +++ b/wasm/delivery.go @@ -20,6 +20,23 @@ type messageDeliveryCallback struct { eventCallback func(args ...interface{}) js.Value } +// EventCallback gets called on the determination if all events related to a +// message send were successful. +// +// If delivered == true, timedOut == false && roundResults != nil +// +// If delivered == false, roundResults == nil +// +// If timedOut == true, delivered == false && roundResults == nil +// +// Parameters: +// - delivered - Returns false if any rounds in the round map were +// unsuccessful. Returns true if ALL rounds were successful (boolean). +// - timedOut - Returns true if any of the rounds timed out while being +// monitored. Returns false if all rounds statuses were returned (boolean). +// - roundResults - rounds contains a mapping of all previously requested +// rounds to their respective round results. Marshalled bytes of +// map[id.Round]cmix.RoundResult (Uint8Array). func (mdc *messageDeliveryCallback) EventCallback( delivered, timedOut bool, roundResults []byte) { mdc.eventCallback(delivered, timedOut, utils.CopyBytesToJS(roundResults)) diff --git a/wasm/e2e.go b/wasm/e2e.go index ef88dd65b1dd0ea6d2b2694f6bd9d4295ddf392d..08c0ac9e4086cd34b1361297c01cfb6e079d7729 100644 --- a/wasm/e2e.go +++ b/wasm/e2e.go @@ -189,26 +189,23 @@ type authCallbacks struct { reset func(args ...interface{}) js.Value } -// newAuthCallbacks adds all the callbacks from the Javascript object. If a -// callback is not defined, it is skipped. +// newAuthCallbacks adds all the callbacks from the Javascript object. func newAuthCallbacks(value js.Value) *authCallbacks { - a := &authCallbacks{} - - if value.Get("Request").Type() == js.TypeFunction { - a.request = utils.WrapCB(value, "Request") - } - - if value.Get("Confirm").Type() == js.TypeFunction { - a.confirm = utils.WrapCB(value, "Confirm") + return &authCallbacks{ + request: utils.WrapCB(value, "Request"), + confirm: utils.WrapCB(value, "Confirm"), + reset: utils.WrapCB(value, "Reset"), } - - if value.Get("Reset").Type() == js.TypeFunction { - a.reset = utils.WrapCB(value, "Reset") - } - - return a } +// Request will be called when an auth Request message is processed. +// +// Parameters: +// - contact - returns the contact file of the sender. JSON of +// [contact.Contact] (Uint8Array). +// - receptionId - returns the ID of the sender. JSON of [id.ID] (Uint8Array). +// - ephemeralId - returns the ephemeral ID of the sender (int). +// - roundId - returns the ID of the round the request was sent on (int). func (a *authCallbacks) Request( contact, receptionId []byte, ephemeralId, roundId int64) { if a.request != nil { @@ -217,6 +214,14 @@ func (a *authCallbacks) Request( } } +// Confirm will be called when an auth Confirm message is processed. +// +// Parameters: +// - contact - returns the contact file of the sender. JSON of +// [contact.Contact] (Uint8Array). +// - receptionId - returns the ID of the sender. JSON of [id.ID] (Uint8Array). +// - ephemeralId - returns the ephemeral ID of the sender (int). +// - roundId - returns the ID of the round the confirmation was sent on (int). func (a *authCallbacks) Confirm( contact, receptionId []byte, ephemeralId, roundId int64) { if a.confirm != nil { @@ -225,6 +230,14 @@ func (a *authCallbacks) Confirm( } } +// Reset will be called when an auth Reset operation occurs. +// +// Parameters: +// - contact - returns the contact file of the sender. JSON of +// [contact.Contact] (Uint8Array). +// - receptionId - returns the ID of the sender. JSON of [id.ID] (Uint8Array). +// - ephemeralId - returns the ephemeral ID of the sender (int). +// - roundId - returns the ID of the round the reset was sent on (int). func (a *authCallbacks) Reset( contact, receptionId []byte, ephemeralId, roundId int64) { if a.reset != nil { diff --git a/wasm/e2eHandler.go b/wasm/e2eHandler.go index a186be2bac661ec9ec0dbfad164998c6bcf176c6..44e4cebec9931697d5000dd2ddb183bbfcd5e045 100644 --- a/wasm/e2eHandler.go +++ b/wasm/e2eHandler.go @@ -194,12 +194,21 @@ type processor struct { string func(args ...interface{}) js.Value } +// Process decrypts and hands off the message to its internal down stream +// message processing system. +// +// Parameters: +// - message - returns the message contents (Uint8Array). +// - receptionId - returns the ID of the sender. JSON of [id.ID] (Uint8Array). +// - ephemeralId - returns the ephemeral ID of the sender (int). +// - roundId - returns the ID of the round sent on (int). func (p *processor) Process( message, receptionId []byte, ephemeralId, roundId int64) { p.process(utils.CopyBytesToJS(message), utils.CopyBytesToJS(receptionId), ephemeralId, roundId) } +// String identifies this processor and is used for debugging. func (p *processor) String() string { return p.string().String() } @@ -221,7 +230,8 @@ func (p *processor) String() string { // Returns: // - Throws TypeError if registering the service fails func (e *E2e) AddService(_ js.Value, args []js.Value) interface{} { - p := &processor{utils.WrapCB(args[1], "Process"), utils.WrapCB(args[1], "String")} + p := &processor{ + utils.WrapCB(args[1], "Process"), utils.WrapCB(args[1], "String")} err := e.api.AddService(args[0].String(), p) if err != nil { diff --git a/wasm/fileTransfer.go b/wasm/fileTransfer.go index 24a1767b8b96151ba13c6f0aea3f0cca740ef9df..1ca91aa4600444440457faaf7ad58c1a9d537139 100644 --- a/wasm/fileTransfer.go +++ b/wasm/fileTransfer.go @@ -36,8 +36,10 @@ func newFileTransferJS(api *bindings.FileTransfer) map[string]interface{} { "CloseSend": js.FuncOf(ft.CloseSend), // Callback registration functions - "RegisterSentProgressCallback": js.FuncOf(ft.RegisterSentProgressCallback), - "RegisterReceivedProgressCallback": js.FuncOf(ft.RegisterReceivedProgressCallback), + "RegisterSentProgressCallback": js.FuncOf( + ft.RegisterSentProgressCallback), + "RegisterReceivedProgressCallback": js.FuncOf( + ft.RegisterReceivedProgressCallback), // Utility functions "MaxFileNameLen": js.FuncOf(ft.MaxFileNameLen), @@ -55,6 +57,12 @@ type receiveFileCallback struct { callback func(args ...interface{}) js.Value } +// Callback is called when a new file transfer is received. +// +// Parameters: +// - payload - returns the contents of the message. JSON of +// [bindings.ReceivedFile] (Uint8Array). +// - err - returns an error on failure (Error). func (rfc *receiveFileCallback) Callback(payload []byte, err error) { rfc.callback(utils.CopyBytesToJS(payload), utils.JsTrace(err)) } @@ -65,6 +73,15 @@ type fileTransferSentProgressCallback struct { callback func(args ...interface{}) js.Value } +// Callback is called when a new file transfer is received. +// +// Parameters: +// - payload - returns the contents of the message. JSON of [bindings.Progress] +// (Uint8Array). +// - t - returns a tracker that allows the lookup of the status of any file +// part. It is a Javascript object that matches the functions on +// FilePartTracker. +// - err - returns an error on failure (Error). func (spc *fileTransferSentProgressCallback) Callback( payload []byte, t *bindings.FilePartTracker, err error) { spc.callback(utils.CopyBytesToJS(payload), newFilePartTrackerJS(t), @@ -77,6 +94,15 @@ type fileTransferReceiveProgressCallback struct { callback func(args ...interface{}) js.Value } +// Callback is called when a file part is sent or an error occurs. +// +// Parameters: +// - payload - returns the contents of the message. JSON of [bindings.Progress] +// (Uint8Array). +// - t - returns a tracker that allows the lookup of the status of any file +// part. It is a Javascript object that matches the functions on +// FilePartTracker. +// - err - returns an error on failure (Error). func (rpc *fileTransferReceiveProgressCallback) Callback( payload []byte, t *bindings.FilePartTracker, err error) { rpc.callback(utils.CopyBytesToJS(payload), newFilePartTrackerJS(t), diff --git a/wasm/follow.go b/wasm/follow.go index c4d6cbf46bc6533d6ed99dd293f88d6e8d51cc5f..c1e11b3ba21869c7e9c3bce923de4b6dc4bd5c71 100644 --- a/wasm/follow.go +++ b/wasm/follow.go @@ -160,6 +160,11 @@ type networkHealthCallback struct { callback func(args ...interface{}) js.Value } +// Callback receives notification if network health changes. +// +// Parameters: +// - health - returns true if the network is healthy and false otherwise +// (boolean). func (nhc *networkHealthCallback) Callback(health bool) { nhc.callback(health) } // AddHealthCallback adds a callback that gets called whenever the network @@ -190,6 +195,7 @@ type clientError struct { report func(args ...interface{}) js.Value } +// Report handles errors from the network follower threads. func (ce *clientError) Report(source, message, trace string) { ce.report(source, message, trace) } @@ -202,7 +208,8 @@ func (ce *clientError) Report(source, message, trace string) { // - args[0] - Javascript object that has functions that implement the // [bindings.ClientError] interface. func (c *Cmix) RegisterClientErrorCallback(_ js.Value, args []js.Value) interface{} { - c.api.RegisterClientErrorCallback(&clientError{utils.WrapCB(args[0], "Report")}) + c.api.RegisterClientErrorCallback( + &clientError{utils.WrapCB(args[0], "Report")}) return nil } @@ -212,6 +219,38 @@ type trackServicesCallback struct { callback func(args ...interface{}) js.Value } +// Callback is the callback for [Cmix.TrackServices]. This will pass to the user +// a JSON-marshalled list of backend services. If there was an error retrieving +// or marshalling the service list, there is an error for the second parameter, +// which will be non-null. +// +// Parameters: +// - marshalData - returns the JSON of [message.ServiceList] (Uint8Array). +// - err - returns an error on failure (Error). +// +// Example JSON: +// [ +// { +// "Id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", // bytes of id.ID encoded as base64 string +// "Services": [ +// { +// "Identifier": "AQID", // bytes encoded as base64 string +// "Tag": "TestTag 1", // string +// "Metadata": "BAUG" // bytes encoded as base64 string +// } +// ] +// }, +// { +// "Id": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", +// "Services": [ +// { +// "Identifier": "AQID", +// "Tag": "TestTag 2", +// "Metadata": "BAUG" +// } +// ] +// }, +// ] func (tsc *trackServicesCallback) Callback(marshalData []byte, err error) { tsc.callback(utils.CopyBytesToJS(marshalData), utils.JsTrace(err)) } diff --git a/wasm/group.go b/wasm/group.go index 12f8f6d688fa8bb537f364a15cdd3ba5a1cd0043..81708c452dfba0f92a307f58a46a9814a551560f 100644 --- a/wasm/group.go +++ b/wasm/group.go @@ -353,6 +353,10 @@ type groupRequest struct { callback func(args ...interface{}) js.Value } +// Callback is called when a group request is received. +// +// Parameters: +// - g - returns the JSON of [bindings.Group] (Uint8Array) func (gr *groupRequest) Callback(g *bindings.Group) { gr.callback(newGroupJS(g)) } @@ -360,17 +364,29 @@ func (gr *groupRequest) Callback(g *bindings.Group) { // groupChatProcessor wraps Javascript callbacks to adhere to the // [bindings.GroupChatProcessor] interface. type groupChatProcessor struct { - callback func(args ...interface{}) js.Value - string func(args ...interface{}) js.Value + process func(args ...interface{}) js.Value + string func(args ...interface{}) js.Value } +// Process decrypts and hands off the message to its internal down stream +// message processing system. +// +// Parameters: +// - decryptedMessage - returns the JSON of [bindings.GroupChatMessage] +// (Uint8Array). +// - msg - returns the marshalled bytes of [format.Message] (Uint8Array). +// - receptionId - returns the ID of the sender. JSON of [id.ID] (Uint8Array). +// - ephemeralId - returns the ephemeral ID of the sender (int). +// - roundId - returns the ID of the round sent on (int). +// - err - returns an error on failure (Error). func (gcp *groupChatProcessor) Process(decryptedMessage, msg, receptionId []byte, ephemeralId, roundId int64, err error) { - gcp.callback(utils.CopyBytesToJS(decryptedMessage), + gcp.process(utils.CopyBytesToJS(decryptedMessage), utils.CopyBytesToJS(msg), utils.CopyBytesToJS(receptionId), ephemeralId, roundId, utils.JsTrace(err)) } +// String returns a name identifying this processor. Used for debugging. func (gcp *groupChatProcessor) String() string { return gcp.string().String() } diff --git a/wasm/logging.go b/wasm/logging.go index 2f636d1b7ecccd62334bd621ec450ca08832cc3a..504c2a618910edb7c5c657195798699fbf5debf3 100644 --- a/wasm/logging.go +++ b/wasm/logging.go @@ -138,6 +138,10 @@ type logWriter struct { log func(args ...interface{}) js.Value } +// Log returns a log message to pass to the log writer. +// +// Parameters: +// - s - log message (string). func (lw *logWriter) Log(s string) { lw.log(s) } // RegisterLogWriter registers a callback on which logs are written. @@ -251,7 +255,9 @@ type LogFile struct { b *circbuf.Buffer } -func NewLogFile(name string, threshold jww.Threshold, maxSize int) (*LogFile, error) { +// NewLogFile initialises a new LogFile for log writing. +func NewLogFile( + name string, threshold jww.Threshold, maxSize int) (*LogFile, error) { // Create new buffer of the specified size b, err := circbuf.NewBuffer(int64(maxSize)) if err != nil { diff --git a/wasm/restlikeSingle.go b/wasm/restlikeSingle.go index c446da67dcbf127076ba5c50f085026a1e29f17d..4c4c0584883424c3a751325863636af1443c14b5 100644 --- a/wasm/restlikeSingle.go +++ b/wasm/restlikeSingle.go @@ -21,6 +21,11 @@ type restlikeCallback struct { callback func(args ...interface{}) js.Value } +// Callback returns the response from an asynchronous restlike request. +// +// Parameters: +// - payload - JSON of [restlike.Message] (Uint8Array). +// - err - returns an error on failure (Error). func (rlc *restlikeCallback) Callback(payload []byte, err error) { rlc.callback(utils.CopyBytesToJS(payload), utils.JsTrace(err)) } diff --git a/wasm/single.go b/wasm/single.go index f14509967745f601499901bff6c7ed3052467d0e..dc10f071e4b0d6ca847dadfc5ff8bdb0bd3fd7b7 100644 --- a/wasm/single.go +++ b/wasm/single.go @@ -103,6 +103,7 @@ func newStopperJS(api bindings.Stopper) map[string]interface{} { return stopperMap } +// Stop stops the registered listener. func (s *Stopper) Stop(js.Value, []js.Value) interface{} { s.api.Stop() return nil @@ -118,6 +119,13 @@ type singleUseCallback struct { callback func(args ...interface{}) js.Value } +// Callback is called when single-use messages are received. +// +// Parameters: +// - callbackReport - JSON of [bindings.SingleUseCallbackReport], which can be +// passed into Cmix.WaitForRoundResult to see if the send succeeded +// (Uint8Array). +// - err - returns an error on failure (Error). func (suc *singleUseCallback) Callback(callbackReport []byte, err error) { suc.callback(utils.CopyBytesToJS(callbackReport), utils.JsTrace(err)) } @@ -128,6 +136,13 @@ type singleUseResponse struct { callback func(args ...interface{}) js.Value } +// Callback returns the response to a single-use message. +// +// Parameters: +// - callbackReport - JSON of [bindings.SingleUseCallbackReport], which can be +// passed into Cmix.WaitForRoundResult to see if the send succeeded +// (Uint8Array). +// - err - returns an error on failure (Error). func (sur *singleUseResponse) Callback(responseReport []byte, err error) { sur.callback(utils.CopyBytesToJS(responseReport), utils.JsTrace(err)) } diff --git a/wasm/ud.go b/wasm/ud.go index 570419544ff518b22096e87ab8a5e4176c426306..d9fe247d5ca5d5f0f44489071fc47905072392b6 100644 --- a/wasm/ud.go +++ b/wasm/ud.go @@ -56,6 +56,10 @@ type udNetworkStatus struct { udNetworkStatus func(args ...interface{}) js.Value } +// UdNetworkStatus returns the status of UD. +// +// Returns: +// - UD status (int). func (uns *udNetworkStatus) UdNetworkStatus() int { return uns.udNetworkStatus().Int() } @@ -158,8 +162,9 @@ func NewUdManagerFromBackup(_ js.Value, args []js.Value) interface{} { contactFile := utils.CopyBytesToGo(args[6]) address := args[7].String() - api, err := bindings.NewUdManagerFromBackup(e2eID, follower, usernameFactJson, emailFactJson, - phoneFactJson, cert, contactFile, address) + api, err := bindings.NewUdManagerFromBackup( + e2eID, follower, usernameFactJson, emailFactJson, phoneFactJson, cert, + contactFile, address) if err != nil { utils.Throw(utils.TypeError, err) return nil @@ -285,6 +290,13 @@ type udLookupCallback struct { callback func(args ...interface{}) js.Value } +// Callback is called by LookupUD to return the contact that matches the passed +// in ID. +// +// Parameters: +// - contactBytes - JSON of [contact.Contact] returned from the lookup, or nil +// if an error occurs (Uint8Array). +// - err - returns an error on failure (Error). func (ulc *udLookupCallback) Callback(contactBytes []byte, err error) { ulc.callback(utils.CopyBytesToJS(contactBytes), utils.JsTrace(err)) } @@ -335,6 +347,20 @@ type udSearchCallback struct { callback func(args ...interface{}) js.Value } +// Callback is called by SearchUD to return a list of [contact.Contact] objects +// that match the list of facts passed into SearchUD. +// +// Parameters: +// - contactListJSON - JSON of an array of [contact.Contact], or nil if an +// error occurs (Uint8Array). +// - err - returns any error that occurred in the search (Error). +// +// JSON Example: +// { +// "<xxc(2)F8dL9EC6gy+RMJuk3R+Au6eGExo02Wfio5cacjBcJRwDEgB7Ugdw/BAr6RkCABkWAFV1c2VybmFtZTA7c4LzV05sG+DMt+rFB0NIJg==xxc>", +// "<xxc(2)eMhAi/pYkW5jCmvKE5ZaTglQb+fTo1D8NxVitr5CCFADEgB7Ugdw/BAr6RoCABkWAFV1c2VybmFtZTE7fElAa7z3IcrYrrkwNjMS2w==xxc>", +// "<xxc(2)d7RJTu61Vy1lDThDMn8rYIiKSe1uXA/RCvvcIhq5Yg4DEgB7Ugdw/BAr6RsCABkWAFV1c2VybmFtZTI7N3XWrxIUpR29atpFMkcR6A==xxc>" +// } func (usc *udSearchCallback) Callback(contactListJSON []byte, err error) { usc.callback(utils.CopyBytesToJS(contactListJSON), utils.JsTrace(err)) } diff --git a/wasm_exec.js b/wasm_exec.js index bba4a84051b5fb6bf284df03d21556eb56500062..c613dfc656f2799b6b3c922f59003cd3347454a7 100644 --- a/wasm_exec.js +++ b/wasm_exec.js @@ -1,10 +1,3 @@ -/* - * Copyright © 2020 xx network SEZC /// - * /// - * Use of this source code is governed by a license that can be found in the /// - * LICENSE file /// - */ - // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.