From 0118a76e5e2329dadc024d080426505f4bf88747 Mon Sep 17 00:00:00 2001 From: "Richard T. Carback III" <rick.carback@gmail.com> Date: Mon, 22 May 2023 23:36:41 +0000 Subject: [PATCH] Updats for Notifications --- go.mod | 2 +- go.sum | 2 + indexedDb/impl/channels/callbacks.go | 7 + indexedDb/impl/channels/implementation.go | 1 - .../impl/channels/implementation_test.go | 4 + indexedDb/worker/channels/tags.go | 9 +- main.go | 2 + wasm/channels.go | 243 ++++++++++++------ wasm/cmix.go | 3 +- wasm/collective.go | 35 +-- wasm/e2eHandler.go | 19 +- wasm/follow.go | 61 ++++- wasm/notifications.go | 12 +- 13 files changed, 278 insertions(+), 122 deletions(-) diff --git a/go.mod b/go.mod index 0015cceb..52e77d9c 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( gitlab.com/elixxir/bloomfilter v0.0.0-20230322223210-fa84f6842de8 // indirect gitlab.com/elixxir/comms v0.0.4-0.20230519211512-4a998f4b0938 // indirect gitlab.com/elixxir/ekv v0.3.1-0.20230504190918-f5e96603c2e0 // indirect - gitlab.com/elixxir/wasm-utils v0.0.0-20230519212008-29635852d8c7 // indirect + gitlab.com/elixxir/wasm-utils v0.0.0-20230522231408-a43b2c1481b2 // indirect gitlab.com/xx_network/comms v0.0.4-0.20230214180029-5387fb85736d // indirect gitlab.com/xx_network/ring v0.0.3-0.20220902183151-a7d3b15bc981 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect diff --git a/go.sum b/go.sum index 82582a0c..5fd785d4 100644 --- a/go.sum +++ b/go.sum @@ -551,6 +551,8 @@ gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c h1:muG8ff95wo gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c/go.mod h1:phun4PLkHJA6wcL4JIhhxZztrmCyJHWPNppBP3DUD2Y= gitlab.com/elixxir/wasm-utils v0.0.0-20230519212008-29635852d8c7 h1:3pimSfFr0uy3OhOMM9IHXZBeG2xJX0nor2yph9xx3oM= gitlab.com/elixxir/wasm-utils v0.0.0-20230519212008-29635852d8c7/go.mod h1:wB7Vh/7LWUm8wYRBSd+6lxfpk4CnDaHTkLCIVKfL2TA= +gitlab.com/elixxir/wasm-utils v0.0.0-20230522231408-a43b2c1481b2 h1:GQb350yPBkWRkPRgNSVFF0ZZDOAlXWIKQBI/1Ff6biU= +gitlab.com/elixxir/wasm-utils v0.0.0-20230522231408-a43b2c1481b2/go.mod h1:wB7Vh/7LWUm8wYRBSd+6lxfpk4CnDaHTkLCIVKfL2TA= gitlab.com/xx_network/comms v0.0.4-0.20230214180029-5387fb85736d h1:AZf2h0fxyO1KxhZPP9//jG3Swb2BcuKbxtNXJgooLss= gitlab.com/xx_network/comms v0.0.4-0.20230214180029-5387fb85736d/go.mod h1:8cwPyH6G8C4qf/U5KDghn1ksOh79MrNqthjKDrfvbXY= gitlab.com/xx_network/crypto v0.0.5-0.20230214003943-8a09396e95dd h1:IleH6U5D/c2zF6YL/z3cBKqBPnI5ApNMCtU7ia4t228= diff --git a/indexedDb/impl/channels/callbacks.go b/indexedDb/impl/channels/callbacks.go index 6fc2235b..2550dbb9 100644 --- a/indexedDb/impl/channels/callbacks.go +++ b/indexedDb/impl/channels/callbacks.go @@ -79,6 +79,13 @@ func (m *manager) newWASMEventModelCB(data []byte) ([]byte, error) { return []byte{}, nil } +// NotificationUpdate implements [bindings.ChannelUICallbacks.NotificationUpdate +func (m *manager) NotificationUpdate(notificationFilterListJSON, + changedNotificationStatesJSON, deletedNotificationStatesJSON []byte, + maxState int) { + jww.FATAL.Panicf("unimplemented") +} + // MessageReceived implements [bindings.ChannelUICallbacks.MessageReceived]. func (m *manager) MessageReceived(uuid int64, channelID []byte, update bool) { // Package parameters for sending diff --git a/indexedDb/impl/channels/implementation.go b/indexedDb/impl/channels/implementation.go index b7aa1f71..04d7fb7e 100644 --- a/indexedDb/impl/channels/implementation.go +++ b/indexedDb/impl/channels/implementation.go @@ -29,7 +29,6 @@ import ( "gitlab.com/elixxir/crypto/message" "gitlab.com/elixxir/wasm-utils/utils" "gitlab.com/elixxir/xxdk-wasm/indexedDb/impl" - wChannels "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/channels" "gitlab.com/xx_network/primitives/id" ) diff --git a/indexedDb/impl/channels/implementation_test.go b/indexedDb/impl/channels/implementation_test.go index d13f725d..7de828ef 100644 --- a/indexedDb/impl/channels/implementation_test.go +++ b/indexedDb/impl/channels/implementation_test.go @@ -50,6 +50,10 @@ func (c *dummyCbs) MessageDeleted(messageId []byte) {} func (c *dummyCbs) NicknameUpdate(channelIdBytes []byte, nickname string, exists bool) { } +func (c *dummyCbs) NotificationUpdate(notificationFilterListJSON, + changedNotificationStatesJSON, deletedNotificationStatesJSON []byte, + maxState int) { +} // Happy path test for receiving, updating, getting, and deleting a File. func TestWasmModel_ReceiveFile(t *testing.T) { diff --git a/indexedDb/worker/channels/tags.go b/indexedDb/worker/channels/tags.go index d3555e54..01991128 100644 --- a/indexedDb/worker/channels/tags.go +++ b/indexedDb/worker/channels/tags.go @@ -14,10 +14,11 @@ 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 ( - NewWASMEventModelTag worker.Tag = "NewWASMEventModel" - MessageReceivedCallbackTag worker.Tag = "MessageReceivedCallback" - DeletedMessageCallbackTag worker.Tag = "DeletedMessageCallback" - MutedUserCallbackTag worker.Tag = "MutedUserCallback" + NewWASMEventModelTag worker.Tag = "NewWASMEventModel" + NotificationUpdateCallbackTag worker.Tag = "NotificationUpdateCallback" + MessageReceivedCallbackTag worker.Tag = "MessageReceivedCallback" + DeletedMessageCallbackTag worker.Tag = "DeletedMessageCallback" + MutedUserCallbackTag worker.Tag = "MutedUserCallback" JoinChannelTag worker.Tag = "JoinChannel" LeaveChannelTag worker.Tag = "LeaveChannel" diff --git a/main.go b/main.go index 07b25c75..4171227e 100644 --- a/main.go +++ b/main.go @@ -136,6 +136,8 @@ func setGlobals() { js.Global().Set("CheckNoMessageErr", js.FuncOf(wasm.CheckNoMessageErr)) js.Global().Set("NewChannelsDatabaseCipher", js.FuncOf(wasm.NewChannelsDatabaseCipher)) + js.Global().Set("GetNotificationReportsForMe", + js.FuncOf(wasm.GetNotificationReportsForMe)) // wasm/dm.go js.Global().Set("InitChannelsFileTransfer", diff --git a/wasm/channels.go b/wasm/channels.go index 71e27547..e7f3449f 100644 --- a/wasm/channels.go +++ b/wasm/channels.go @@ -17,16 +17,11 @@ import ( "syscall/js" "gitlab.com/elixxir/client/v4/channels" - "gitlab.com/elixxir/primitives/notifications" channelsDb "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/channels" "gitlab.com/elixxir/client/v4/bindings" - "gitlab.com/elixxir/client/v4/channels" - "gitlab.com/elixxir/crypto/message" "gitlab.com/elixxir/wasm-utils/exception" "gitlab.com/elixxir/wasm-utils/utils" - channelsDb "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/channels" - "gitlab.com/xx_network/primitives/id" ) //////////////////////////////////////////////////////////////////////////////// @@ -83,6 +78,11 @@ func newChannelsManagerJS(api *bindings.ChannelsManager) map[string]any { // Channel Receiving Logic and Callback Registration "RegisterReceiveHandler": js.FuncOf(cm.RegisterReceiveHandler), + + // Notifications + "SetMobileNotificationsLevel": js.FuncOf( + cm.SetMobileNotificationsLevel), + "GetNotificationLevel": js.FuncOf(cm.GetNotificationLevel), } return channelsManagerMap @@ -258,27 +258,34 @@ func GetPublicChannelIdentityFromPrivate(_ js.Value, args []js.Value) any { // Parameters: // - args[0] - ID of [Cmix] object in tracker (int). This can be retrieved // using [Cmix.GetID]. -// - args[1] - Bytes of a private identity ([channel.PrivateIdentity]) that is +// - args[1] - ID of [bindings.Notifications] object in tracker (int). Can be +// retrieved using [Notifications.GetID]. +// - args[2] - Bytes of a private identity ([channel.PrivateIdentity]) that is // generated by [GenerateChannelIdentity] (Uint8Array). -// - args[2] - JSON of an array of integers of [channels.ExtensionBuilder] +// - args[3] - JSON of an array of integers of [channels.ExtensionBuilder] // IDs. The ID can be retrieved from an object with an extension builder // (e.g., [ChannelsFileTransfer.GetExtensionBuilderID]). Leave empty if not // using extension builders. Example: `[2,11,5]` (Uint8Array). -// - args[3] - A function that initialises and returns a Javascript object +// - args[4] - A function that initialises and returns a Javascript object // that matches the [bindings.EventModel] interface. The function must match // the Build function in [bindings.EventModelBuilder]. +// - args[4] - A callback object which implements the +// [bindings.ChannelUICallbacks] javascript functions. // // Returns: // - Javascript representation of the [ChannelsManager] object. // - Throws a TypeError if creating the manager fails. func NewChannelsManager(_ js.Value, args []js.Value) any { cmixId := args[0].Int() - privateIdentity := utils.CopyBytesToGo(args[1]) - extensionBuilderIDsJSON := utils.CopyBytesToGo(args[2]) - em := newEventModelBuilder(args[3]) + notificationsId := args[1].Int() + privateIdentity := utils.CopyBytesToGo(args[2]) + extensionBuilderIDsJSON := utils.CopyBytesToGo(args[3]) + em := newEventModelBuilder(args[4]) + channelCbs := newChannelUI(args[5]) cm, err := bindings.NewChannelsManager( - cmixId, privateIdentity, extensionBuilderIDsJSON, em, nil) + cmixId, privateIdentity, extensionBuilderIDsJSON, em, + notificationsId, channelCbs) if err != nil { exception.ThrowTrace(err) return nil @@ -298,22 +305,27 @@ func NewChannelsManager(_ js.Value, args []js.Value) any { // Parameters: // - args[0] - ID of [Cmix] object in tracker (int). This can be retrieved // using [Cmix.GetID]. -// - args[1] - The storage tag associated with the previously created channel +// - args[1] - ID of [bindings.Notifications] object in tracker (int). Can be +// retrieved using [Notifications.GetID]. +// - args[2] - The storage tag associated with the previously created channel // manager and retrieved with [ChannelsManager.GetStorageTag] (string). -// - args[2] - A function that initialises and returns a Javascript object +// - args[3] - A function that initialises and returns a Javascript object // that matches the [bindings.EventModel] interface. The function must match // the Build function in [bindings.EventModelBuilder]. -// - args[3] - A callback object which implements the +// - args[4] - A callback object which implements the // [bindings.ChannelUICallbacks] javascript functions. // // Returns: // - Javascript representation of the [ChannelsManager] object. // - Throws a TypeError if loading the manager fails. func LoadChannelsManager(_ js.Value, args []js.Value) any { - em := newEventModelBuilder(args[2]) - cUI := newChannelUI(args[3]) - cm, err := bindings.LoadChannelsManager(args[0].Int(), args[1].String(), - em, cUI) + cMixID := args[0].Int() + notificationsID := args[1].Int() + storageTag := args[2].String() + em := newEventModelBuilder(args[3]) + cUI := newChannelUI(args[4]) + cm, err := bindings.LoadChannelsManager(cMixID, storageTag, em, + notificationsID, cUI) if err != nil { exception.ThrowTrace(err) return nil @@ -336,16 +348,18 @@ func LoadChannelsManager(_ js.Value, args []js.Value) any { // Parameters: // - args[0] - ID of [Cmix] object in tracker (int). This can be retrieved // using [Cmix.GetID]. -// - args[1] - Path to Javascript file that starts the worker (string). -// - args[2] - Bytes of a private identity ([channel.PrivateIdentity]) that is +// - args[1] - ID of [bindings.Notifications] object in tracker (int). Can be +// retrieved using [Notifications.GetID]. +// - args[2] - Path to Javascript file that starts the worker (string). +// - args[3] - Bytes of a private identity ([channel.PrivateIdentity]) that is // generated by [GenerateChannelIdentity] (Uint8Array). -// - args[3] - JSON of an array of integers of [channels.ExtensionBuilder] +// - args[4] - JSON of an array of integers of [channels.ExtensionBuilder] // IDs. The ID can be retrieved from an object with an extension builder // (e.g., [ChannelsFileTransfer.GetExtensionBuilderID]). Leave empty if not // using extension builders. Example: `[2,11,5]` (Uint8Array). -// - args[4] - A callback object which implements the +// - args[5] - A callback object which implements the // [bindings.ChannelUICallbacks] javascript functions. -// - args[5] - ID of [ChannelDbCipher] object in tracker (int). Create this +// - args[6] - ID of [ChannelDbCipher] object in tracker (int). Create this // object with [NewChannelsDatabaseCipher] and get its id with // [ChannelDbCipher.GetID]. // @@ -355,18 +369,20 @@ func LoadChannelsManager(_ js.Value, args []js.Value) any { // - Throws a TypeError if the cipher ID does not correspond to a cipher. func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any { cmixID := args[0].Int() - wasmJsPath := args[1].String() - privateIdentity := utils.CopyBytesToGo(args[2]) - extensionBuilderIDsJSON := utils.CopyBytesToGo(args[3]) - channelCbs := newChannelUI(args[4]) - cipherID := args[5].Int() + notificationsID := args[1].Int() + wasmJsPath := args[2].String() + privateIdentity := utils.CopyBytesToGo(args[3]) + extensionBuilderIDsJSON := utils.CopyBytesToGo(args[4]) + channelCbs := newChannelUI(args[5]) + cipherID := args[6].Int() cipher, err := bindings.GetChannelDbCipherTrackerFromID(cipherID) if err != nil { exception.ThrowTrace(err) } - return newChannelsManagerWithIndexedDb(cmixID, wasmJsPath, privateIdentity, + return newChannelsManagerWithIndexedDb(cmixID, notificationsID, + wasmJsPath, privateIdentity, extensionBuilderIDsJSON, channelCbs, cipher) } @@ -385,14 +401,16 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any { // Parameters: // - args[0] - ID of [Cmix] object in tracker (int). This can be retrieved // using [Cmix.GetID]. -// - args[1] - Path to Javascript file that starts the worker (string). -// - args[2] - Bytes of a private identity ([channel.PrivateIdentity]) that is +// - args[1] - ID of [bindings.Notifications] object in tracker (int). Can be +// retrieved using [Notifications.GetID]. +// - args[2] - Path to Javascript file that starts the worker (string). +// - args[3] - Bytes of a private identity ([channel.PrivateIdentity]) that is // generated by [GenerateChannelIdentity] (Uint8Array). -// - args[3] - JSON of an array of integers of [channels.ExtensionBuilder] +// - args[4] - JSON of an array of integers of [channels.ExtensionBuilder] // IDs. The ID can be retrieved from an object with an extension builder // (e.g., [ChannelsFileTransfer.GetExtensionBuilderID]). Leave empty if not // using extension builders. Example: `[2,11,5]` (Uint8Array). -// - args[4] - A callback object which implements the +// - args[5] - A callback object which implements the // [bindings.ChannelUICallbacks] javascript functions. // // Returns a promise: @@ -402,17 +420,19 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any { // FIXME: package names in comments for indexedDb func NewChannelsManagerWithIndexedDbUnsafe(_ js.Value, args []js.Value) any { cmixID := args[0].Int() - wasmJsPath := args[1].String() - privateIdentity := utils.CopyBytesToGo(args[2]) - extensionBuilderIDsJSON := utils.CopyBytesToGo(args[3]) - channelsCbs := newChannelUI(args[4]) - - return newChannelsManagerWithIndexedDb(cmixID, wasmJsPath, privateIdentity, + notificationsID := args[1].Int() + wasmJsPath := args[2].String() + privateIdentity := utils.CopyBytesToGo(args[3]) + extensionBuilderIDsJSON := utils.CopyBytesToGo(args[4]) + channelsCbs := newChannelUI(args[5]) + + return newChannelsManagerWithIndexedDb(cmixID, notificationsID, + wasmJsPath, privateIdentity, extensionBuilderIDsJSON, channelsCbs, nil) } -func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string, - privateIdentity, extensionBuilderIDsJSON []byte, +func newChannelsManagerWithIndexedDb(cmixID, notificationsID int, + wasmJsPath string, privateIdentity, extensionBuilderIDsJSON []byte, channelsCbs bindings.ChannelUICallbacks, cipher *bindings.ChannelDbCipher) any { @@ -421,7 +441,8 @@ func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string, promiseFn := func(resolve, reject func(args ...any) js.Value) { cm, err := bindings.NewChannelsManagerGoEventModel( - cmixID, privateIdentity, extensionBuilderIDsJSON, model, channelsCbs) + cmixID, privateIdentity, extensionBuilderIDsJSON, model, + notificationsID, channelsCbs) if err != nil { reject(exception.NewTrace(err)) } else { @@ -443,12 +464,14 @@ func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string, // Parameters: // - args[0] - ID of [Cmix] object in tracker (int). This can be retrieved // using [Cmix.GetID]. -// - args[1] - Path to Javascript file that starts the worker (string). -// - args[2] - The storage tag associated with the previously created channel +// - args[1] - ID of [bindings.Notifications] object in tracker (int). Can be +// retrieved using [Notifications.GetID]. +// - args[2] - Path to Javascript file that starts the worker (string). +// - args[3] - The storage tag associated with the previously created channel // manager and retrieved with [ChannelsManager.GetStorageTag] (string). -// - args[3] - A callback object which implements the +// - args[4] - A callback object which implements the // [bindings.ChannelUICallbacks] javascript functions. -// - args[4] - ID of [ChannelDbCipher] object in tracker (int). Create this +// - args[5] - ID of [ChannelDbCipher] object in tracker (int). Create this // object with [NewChannelsDatabaseCipher] and get its id with // [ChannelDbCipher.GetID]. // @@ -458,17 +481,19 @@ func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string, // - Throws a TypeError if the cipher ID does not correspond to a cipher. func LoadChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any { cmixID := args[0].Int() - wasmJsPath := args[1].String() - storageTag := args[2].String() - channelsCbs := newChannelUI(args[3]) - cipherID := args[4].Int() + notificationsID := args[1].Int() + wasmJsPath := args[2].String() + storageTag := args[3].String() + channelsCbs := newChannelUI(args[4]) + cipherID := args[5].Int() cipher, err := bindings.GetChannelDbCipherTrackerFromID(cipherID) if err != nil { exception.ThrowTrace(err) } - return loadChannelsManagerWithIndexedDb(cmixID, wasmJsPath, storageTag, + return loadChannelsManagerWithIndexedDb(cmixID, notificationsID, + wasmJsPath, storageTag, channelsCbs, cipher) } @@ -485,10 +510,12 @@ func LoadChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any { // Parameters: // - args[0] - ID of [Cmix] object in tracker (int). This can be retrieved // using [Cmix.GetID]. -// - args[1] - Path to Javascript file that starts the worker (string). -// - args[2] - The storage tag associated with the previously created channel +// - args[1] - ID of [bindings.Notifications] object in tracker (int). Can be +// retrieved using [Notifications.GetID]. +// - args[2] - Path to Javascript file that starts the worker (string). +// - args[3] - The storage tag associated with the previously created channel // manager and retrieved with [ChannelsManager.GetStorageTag] (string). -// - args[3] - A callback object which implements the +// - args[4] - A callback object which implements the // [bindings.ChannelUICallbacks] javascript functions. // // Returns a promise: @@ -496,15 +523,18 @@ func LoadChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any { // - Rejected with an error if loading indexedDb or the manager fails. func LoadChannelsManagerWithIndexedDbUnsafe(_ js.Value, args []js.Value) any { cmixID := args[0].Int() - wasmJsPath := args[1].String() - storageTag := args[2].String() - cUI := newChannelUI(args[3]) + notificationsID := args[1].Int() + wasmJsPath := args[2].String() + storageTag := args[3].String() + cUI := newChannelUI(args[4]) - return loadChannelsManagerWithIndexedDb(cmixID, wasmJsPath, storageTag, + return loadChannelsManagerWithIndexedDb(cmixID, notificationsID, + wasmJsPath, storageTag, cUI, nil) } -func loadChannelsManagerWithIndexedDb(cmixID int, wasmJsPath, storageTag string, +func loadChannelsManagerWithIndexedDb(cmixID, notificationsID int, + wasmJsPath, storageTag string, channelsCbs bindings.ChannelUICallbacks, cipher *bindings.ChannelDbCipher) any { @@ -513,7 +543,8 @@ func loadChannelsManagerWithIndexedDb(cmixID int, wasmJsPath, storageTag string, promiseFn := func(resolve, reject func(args ...any) js.Value) { cm, err := bindings.LoadChannelsManagerGoEventModel( - cmixID, storageTag, model, nil, channelsCbs) + cmixID, storageTag, model, nil, notificationsID, + channelsCbs) if err != nil { reject(exception.NewTrace(err)) } else { @@ -943,6 +974,9 @@ func ValidForever(js.Value, []js.Value) any { // to the user should be tracked while all actions should not be (boolean). // - args[5] - JSON of [xxdk.CMIXParams]. If left empty // [bindings.GetDefaultCMixParams] will be used internally (Uint8Array). +// - args[6] - pingBytes - An array of public keys of users that +// should receive mobile notifications for the message (JSON of +// []Uint8Array list). // // Returns a promise: // - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array). @@ -954,10 +988,16 @@ func (cm *ChannelsManager) SendGeneric(_ js.Value, args []js.Value) any { leaseTimeMS := int64(args[3].Int()) tracked := args[4].Bool() cmixParamsJSON := utils.CopyBytesToGo(args[5]) + var pingBytes [][]byte promiseFn := func(resolve, reject func(args ...any) js.Value) { - sendReport, err := cm.api.SendGeneric(marshalledChanId, messageType, - msg, leaseTimeMS, tracked, cmixParamsJSON) + err := json.Unmarshal(utils.CopyBytesToGo(args[6]), pingBytes) + if err != nil { + reject(exception.NewTrace(err)) + } + sendReport, err := cm.api.SendGeneric(marshalledChanId, + messageType, msg, leaseTimeMS, tracked, + cmixParamsJSON, pingBytes) if err != nil { reject(exception.NewTrace(err)) } else { @@ -987,6 +1027,9 @@ func (cm *ChannelsManager) SendGeneric(_ js.Value, args []js.Value) any { // be enumerated here. Use [ValidForever] to last the max message life. // - args[3] - JSON of [xxdk.CMIXParams]. If left empty // [bindings.GetDefaultCMixParams] will be used internally (Uint8Array). +// - args[4] - pingBytes - An array of public keys of users that +// should receive mobile notifications for the message (JSON of +// []Uint8Array list). // // Returns a promise: // - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array). @@ -996,10 +1039,16 @@ func (cm *ChannelsManager) SendMessage(_ js.Value, args []js.Value) any { msg := args[1].String() leaseTimeMS := int64(args[2].Int()) cmixParamsJSON := utils.CopyBytesToGo(args[3]) + var pingBytes [][]byte promiseFn := func(resolve, reject func(args ...any) js.Value) { + err := json.Unmarshal(utils.CopyBytesToGo(args[6]), pingBytes) + if err != nil { + reject(exception.NewTrace(err)) + } sendReport, err := cm.api.SendMessage( - marshalledChanId, msg, leaseTimeMS, cmixParamsJSON) + marshalledChanId, msg, leaseTimeMS, cmixParamsJSON, + pingBytes) if err != nil { reject(exception.NewTrace(err)) } else { @@ -1036,6 +1085,9 @@ func (cm *ChannelsManager) SendMessage(_ js.Value, args []js.Value) any { // be enumerated here. Use [ValidForever] to last the max message life. // - args[4] - JSON of [xxdk.CMIXParams]. If left empty // [bindings.GetDefaultCMixParams] will be used internally (Uint8Array). +// - args[6] - pingBytes - An array of public keys of users that +// should receive mobile notifications for the message (JSON of +// []Uint8Array list). // // Returns a promise: // - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array). @@ -1046,10 +1098,16 @@ func (cm *ChannelsManager) SendReply(_ js.Value, args []js.Value) any { messageToReactTo := utils.CopyBytesToGo(args[2]) leaseTimeMS := int64(args[3].Int()) cmixParamsJSON := utils.CopyBytesToGo(args[4]) + var pingBytes [][]byte promiseFn := func(resolve, reject func(args ...any) js.Value) { + err := json.Unmarshal(utils.CopyBytesToGo(args[6]), pingBytes) + if err != nil { + reject(exception.NewTrace(err)) + } sendReport, err := cm.api.SendReply(marshalledChanId, msg, - messageToReactTo, leaseTimeMS, cmixParamsJSON) + messageToReactTo, leaseTimeMS, cmixParamsJSON, + pingBytes) if err != nil { reject(exception.NewTrace(err)) } else { @@ -1082,20 +1140,26 @@ func (cm *ChannelsManager) SendReply(_ js.Value, args []js.Value) any { // be enumerated here. Use [ValidForever] to last the max message life. // - args[4] - JSON of [xxdk.CMIXParams]. If left empty // [bindings.GetDefaultCMixParams] will be used internally (Uint8Array). +// - args[5] - pingBytes - An array of public keys of users that +// should receive mobile notifications for the message (JSON of +// []Uint8Array list). // // Returns a promise: // - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array). // - Rejected with an error if sending fails. func (cm *ChannelsManager) SendReaction(_ js.Value, args []js.Value) any { - var ( - marshalledChanId = utils.CopyBytesToGo(args[0]) - reaction = args[1].String() - messageToReactTo = utils.CopyBytesToGo(args[2]) - leaseTimeMS = int64(args[3].Int()) - cmixParamsJSON = utils.CopyBytesToGo(args[4]) - ) + marshalledChanId := utils.CopyBytesToGo(args[0]) + reaction := args[1].String() + messageToReactTo := utils.CopyBytesToGo(args[2]) + leaseTimeMS := int64(args[3].Int()) + cmixParamsJSON := utils.CopyBytesToGo(args[4]) + var pingBytes [][]byte promiseFn := func(resolve, reject func(args ...any) js.Value) { + err := json.Unmarshal(utils.CopyBytesToGo(args[6]), pingBytes) + if err != nil { + reject(exception.NewTrace(err)) + } sendReport, err := cm.api.SendReaction(marshalledChanId, reaction, messageToReactTo, leaseTimeMS, cmixParamsJSON) if err != nil { @@ -1480,7 +1544,7 @@ func (cm *ChannelsManager) GetNotificationLevel(_ js.Value, level, err := cm.api.GetNotificationLevel(channelIDBytes) if err != nil { - utils.Throw(utils.TypeError, err) + exception.ThrowTrace(err) return nil } @@ -1511,7 +1575,7 @@ func (cm *ChannelsManager) SetMobileNotificationsLevel(_ js.Value, err := cm.api.SetMobileNotificationsLevel(channelIDBytes, level, status, push) if err != nil { - utils.Throw(utils.TypeError, err) + exception.ThrowTrace(err) } return nil } @@ -1535,7 +1599,7 @@ func GetNotificationReportsForMe(_ js.Value, args []js.Value) any { nrs, err := bindings.GetNotificationReportsForMe(notificationFilterJSON, notificationDataJSON) if err != nil { - utils.Throw(utils.TypeError, err) + exception.ThrowTrace(err) return nil } @@ -2278,20 +2342,33 @@ func (c *ChannelDbCipher) UnmarshalJSON(_ js.Value, args []js.Value) any { // channelUI callbacks implementation struct. func newChannelUI(cbImpl js.Value) *channelUI { return &channelUI{ - messageReceived: utils.WrapCB(cbImpl, "MessageReceived"), - userMuted: utils.WrapCB(cbImpl, "UserMuted"), - messageDeleted: utils.WrapCB(cbImpl, "MessageDeleted"), - nicknameUpdate: utils.WrapCB(cbImpl, "NicknameUpdate"), + notificationUpdate: utils.WrapCB(cbImpl, "NotificationUpdate"), + messageReceived: utils.WrapCB(cbImpl, "MessageReceived"), + userMuted: utils.WrapCB(cbImpl, "UserMuted"), + messageDeleted: utils.WrapCB(cbImpl, "MessageDeleted"), + nicknameUpdate: utils.WrapCB(cbImpl, "NicknameUpdate"), } } // eventModel wraps Javascript callbacks to adhere to the // [bindings.ChannelUICallbacks] interface. type channelUI struct { - messageReceived func(args ...any) js.Value - userMuted func(args ...any) js.Value - messageDeleted func(args ...any) js.Value - nicknameUpdate func(args ...any) js.Value + notificationUpdate func(args ...any) js.Value + messageReceived func(args ...any) js.Value + userMuted func(args ...any) js.Value + messageDeleted func(args ...any) js.Value + nicknameUpdate func(args ...any) js.Value +} + +// NotificationUpdate implements +// [bindings.ChannelUICallbacks.NotificationUpdate]. +func (c *channelUI) NotificationUpdate(notificationFilterListJSON, + changedNotificationStatesJSON, deletedNotificationStatesJSON []byte, + maxState int) { + c.notificationUpdate(notificationFilterListJSON, + changedNotificationStatesJSON, + deletedNotificationStatesJSON, + maxState) } // MessageReceived implements [bindings.ChannelUICallbacks.MessageReceived]. diff --git a/wasm/cmix.go b/wasm/cmix.go index 3b735f4e..be7ad6d3 100644 --- a/wasm/cmix.go +++ b/wasm/cmix.go @@ -15,7 +15,6 @@ import ( "gitlab.com/elixxir/client/v4/bindings" "gitlab.com/elixxir/wasm-utils/exception" "gitlab.com/elixxir/wasm-utils/utils" - "syscall/js" ) // Cmix wraps the [bindings.Cmix] object so its methods can be wrapped to be @@ -168,7 +167,7 @@ func LoadSynchronizedCmix(_ js.Value, args []js.Value) any { net, err := bindings.LoadSynchronizedCmix(storageDir, password, rs, cmixParamsJSON) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve(newCmixJS(net)) } diff --git a/wasm/collective.go b/wasm/collective.go index 5b35b3d4..3ce0c125 100644 --- a/wasm/collective.go +++ b/wasm/collective.go @@ -13,6 +13,7 @@ import ( "syscall/js" "gitlab.com/elixxir/client/v4/bindings" + "gitlab.com/elixxir/wasm-utils/exception" "gitlab.com/elixxir/wasm-utils/utils" ) @@ -72,7 +73,7 @@ func (r *RemoteKV) Get(_ js.Value, args []js.Value) any { promiseFn := func(resolve, reject func(args ...any) js.Value) { value, err := r.api.Get(key, version) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve(utils.CopyBytesToJS(value)) } @@ -97,7 +98,7 @@ func (r *RemoteKV) Delete(_ js.Value, args []js.Value) any { promiseFn := func(resolve, reject func(args ...any) js.Value) { err := r.api.Delete(key, version) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve() } @@ -128,7 +129,7 @@ func (r *RemoteKV) Set(_ js.Value, args []js.Value) any { promiseFn := func(resolve, reject func(args ...any) js.Value) { err := r.api.Set(key, value) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve() } @@ -178,7 +179,7 @@ func (r *RemoteKV) Prefix(_ js.Value, args []js.Value) any { newAPI, err := r.api.Prefix(prefix) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve(newRemoteKvJS(newAPI)) } @@ -193,7 +194,7 @@ func (r *RemoteKV) Root(_ js.Value, args []js.Value) any { newAPI, err := r.api.Root() if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve(newRemoteKvJS(newAPI)) } @@ -260,7 +261,7 @@ func (r *RemoteKV) StoreMapElement(_ js.Value, args []js.Value) any { promiseFn := func(resolve, reject func(args ...any) js.Value) { err := r.api.StoreMapElement(mapName, elementKey, val, version) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve() } @@ -291,7 +292,7 @@ func (r *RemoteKV) StoreMap(_ js.Value, args []js.Value) any { promiseFn := func(resolve, reject func(args ...any) js.Value) { err := r.api.StoreMap(mapName, val, version) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve() } @@ -321,7 +322,7 @@ func (r *RemoteKV) DeleteMapElement(_ js.Value, args []js.Value) any { deleted, err := r.api.DeleteMapElement(mapName, elementKey, version) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve(utils.CopyBytesToJS(deleted)) } @@ -350,7 +351,7 @@ func (r *RemoteKV) GetMap(_ js.Value, args []js.Value) any { promiseFn := func(resolve, reject func(args ...any) js.Value) { mapJSON, err := r.api.GetMap(mapName, version) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve(utils.CopyBytesToJS(mapJSON)) } @@ -381,7 +382,7 @@ func (r *RemoteKV) GetMapElement(_ js.Value, args []js.Value) any { deleted, err := r.api.GetMapElement(mapName, elementKey, version) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve(utils.CopyBytesToJS(deleted)) } @@ -411,7 +412,7 @@ func (r *RemoteKV) ListenOnRemoteKey(_ js.Value, args []js.Value) any { promiseFn := func(resolve, reject func(args ...any) js.Value) { deleted, err := r.api.ListenOnRemoteKey(key, version, cb) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve(utils.CopyBytesToJS(deleted)) } @@ -441,7 +442,7 @@ func (r *RemoteKV) ListenOnRemoteMap(_ js.Value, args []js.Value) any { promiseFn := func(resolve, reject func(args ...any) js.Value) { deleted, err := r.api.ListenOnRemoteMap(mapName, version, cb) if err != nil { - reject(utils.JsTrace(err)) + reject(exception.NewTrace(err)) } else { resolve(utils.CopyBytesToJS(deleted)) } @@ -487,7 +488,7 @@ func newRemoteStore(arg js.Value) *RemoteStore { func (rsCB *RemoteStore) Read(path string) ([]byte, error) { fn := func() js.Value { return rsCB.read(path) } - v, err := utils.RunAndCatch(fn) + v, err := exception.RunAndCatch(fn) if err != nil { return nil, err } @@ -504,7 +505,7 @@ func (rsCB *RemoteStore) Read(path string) ([]byte, error) { // - 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 := utils.RunAndCatch(fn) + _, err := exception.RunAndCatch(fn) return err } @@ -518,7 +519,7 @@ func (rsCB *RemoteStore) Write(path string, data []byte) error { // - Catches any thrown errors (of type Error) and returns it as an error. func (rsCB *RemoteStore) GetLastModified(path string) ([]byte, error) { fn := func() js.Value { return rsCB.getLastModified(path) } - v, err := utils.RunAndCatch(fn) + v, err := exception.RunAndCatch(fn) if err != nil { return nil, err } @@ -532,7 +533,7 @@ func (rsCB *RemoteStore) GetLastModified(path string) ([]byte, error) { // - Catches any thrown errors (of type Error) and returns it as an error. func (rsCB *RemoteStore) GetLastWrite() ([]byte, error) { fn := func() js.Value { return rsCB.getLastWrite() } - v, err := utils.RunAndCatch(fn) + v, err := exception.RunAndCatch(fn) if err != nil { return nil, err } @@ -549,7 +550,7 @@ func (rsCB *RemoteStore) GetLastWrite() ([]byte, error) { // - 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 := utils.RunAndCatch(fn) + v, err := exception.RunAndCatch(fn) if err != nil { return nil, err } diff --git a/wasm/e2eHandler.go b/wasm/e2eHandler.go index 7f3b5966..fd107b0b 100644 --- a/wasm/e2eHandler.go +++ b/wasm/e2eHandler.go @@ -10,9 +10,10 @@ package wasm import ( + "syscall/js" + "gitlab.com/elixxir/wasm-utils/exception" "gitlab.com/elixxir/wasm-utils/utils" - "syscall/js" ) // GetReceptionID returns the marshalled default IDs. @@ -200,13 +201,19 @@ type processor struct { // // Parameters: // - message - Returns the message contents (Uint8Array). +// - tags - a byte array representing the tags on the message (Uint8Array) +// - metadata - other arbitrary metadata (Uint8Array) // - receptionId - Returns the marshalled bytes of the sender's [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), +func (p *processor) Process(message, tags, metadata, receptionId []byte, + ephemeralId int64, roundId int64) { + + p.process(utils.CopyBytesToJS(message), + utils.CopyBytesToJS(tags), + utils.CopyBytesToJS(metadata), + utils.CopyBytesToJS(receptionId), ephemeralId, roundId) } @@ -233,7 +240,9 @@ func (p *processor) String() string { // - Throws TypeError if registering the service fails. func (e *E2e) AddService(_ js.Value, args []js.Value) any { p := &processor{ - utils.WrapCB(args[1], "Process"), utils.WrapCB(args[1], "String")} + 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/follow.go b/wasm/follow.go index b215bf54..a0218835 100644 --- a/wasm/follow.go +++ b/wasm/follow.go @@ -10,10 +10,11 @@ package wasm import ( + "syscall/js" + "gitlab.com/elixxir/wasm-utils/exception" "gitlab.com/elixxir/wasm-utils/utils" "gitlab.com/elixxir/xxdk-wasm/storage" - "syscall/js" ) // StartNetworkFollower kicks off the tracking of the network. It starts long- @@ -381,6 +382,53 @@ func (tsc *trackServicesCallback) Callback(marshalData []byte, err error) { tsc.callback(utils.CopyBytesToJS(marshalData), exception.NewTrace(err)) } +// trackServicesCallback adheres to the [bindings.TrackServicesCallback] +// interface. +type trackCompressedServicesCallback struct { + callback func(args ...any) js.Value +} + +// Callback is the callback for [Cmix.TrackCompressedServices]. 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.CompressedServiceList] (Uint8Array). +// - err - Returns an error on failure (Error). +// +// Example JSON: +// +// { +// "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD": [ +// { +// "Identifier": null, +// "Tags": ["test"], +// "Metadata": null +// } +// ], +// "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD": [ +// { +// "Identifier": null, +// "Tags": ["test"], +// "Metadata": null +// } +// ], +// "AAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD": [ +// { +// "Identifier": null, +// "Tags": ["test"], +// "Metadata": null +// } +// ] +// } +func (tcsc *trackCompressedServicesCallback) Callback(marshalData []byte, + err error) { + tcsc.callback(utils.CopyBytesToJS(marshalData), exception.NewTrace(err)) +} + // TrackServicesWithIdentity will return via a callback the list of services the // backend keeps track of for the provided identity. This may be passed into // other bindings call which may need context on the available services for this @@ -389,13 +437,20 @@ func (tsc *trackServicesCallback) Callback(marshalData []byte, err error) { // Parameters: // - args[0] - ID of [E2e] object in tracker (int). // - args[1] - Javascript object that has functions that implement the -// [bindings.ClientError] interface. +// [bindings.TrackServicesCallback] interface. +// - args[1] - Javascript object that has functions that implement the +// [bindings.TrackCompressedServicesCallback] interface. // // Returns: // - Throws TypeError if the [E2e] ID is invalid. func (c *Cmix) TrackServicesWithIdentity(_ js.Value, args []js.Value) any { err := c.api.TrackServicesWithIdentity(args[0].Int(), - &trackServicesCallback{utils.WrapCB(args[0], "Callback")}) + &trackServicesCallback{ + utils.WrapCB(args[0], "Callback"), + }, + &trackCompressedServicesCallback{ + utils.WrapCB(args[0], "Callback"), + }) if err != nil { exception.ThrowTrace(err) return nil diff --git a/wasm/notifications.go b/wasm/notifications.go index 39ee8d08..2a488729 100644 --- a/wasm/notifications.go +++ b/wasm/notifications.go @@ -14,7 +14,7 @@ import ( "gitlab.com/elixxir/client/v4/bindings" "gitlab.com/elixxir/client/v4/notifications" - "gitlab.com/elixxir/wasm-utils/utils" + "gitlab.com/elixxir/wasm-utils/exception" ) type Notifications struct { @@ -46,7 +46,7 @@ func LoadNotifications(_ js.Value, args []js.Value) any { cMixID := args[0].Int() api, err := bindings.LoadNotifications(cMixID) if err != nil { - utils.Throw(utils.TypeError, err) + exception.ThrowTrace(err) return nil } @@ -64,7 +64,7 @@ func LoadNotificationsDummy(_ js.Value, args []js.Value) any { cMixID := args[0].Int() api, err := bindings.LoadNotificationsDummy(cMixID) if err != nil { - utils.Throw(utils.TypeError, err) + exception.ThrowTrace(err) return nil } @@ -89,7 +89,7 @@ func (n *Notifications) AddToken(_ js.Value, args []js.Value) any { err := n.api.AddToken(newToken, app) if err != nil { - utils.Throw(utils.TypeError, err) + exception.ThrowTrace(err) } return nil @@ -101,7 +101,7 @@ func (n *Notifications) AddToken(_ js.Value, args []js.Value) any { func (n *Notifications) RemoveToken(_ js.Value, args []js.Value) any { err := n.api.RemoveToken() if err != nil { - utils.Throw(utils.TypeError, err) + exception.ThrowTrace(err) } return nil } @@ -117,7 +117,7 @@ func (n *Notifications) SetMaxState(_ js.Value, args []js.Value) any { err := n.api.SetMaxState(notifications.NotificationState(maxState)) if err != nil { - utils.Throw(utils.TypeError, err) + exception.ThrowTrace(err) } return nil -- GitLab