diff --git a/go.mod b/go.mod index 714cc010e7b4b04dd4e674d0bd3290506f7dfdab..8c3011f6a1fee6109fe81eb8e968b0bb548b80b7 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.7.0 github.com/spf13/jwalterweatherman v1.1.0 - gitlab.com/elixxir/client/v4 v4.6.4-0.20230523215224-750d3d1707fd - gitlab.com/elixxir/crypto v0.0.7-0.20230522162218-45433d877235 + gitlab.com/elixxir/client/v4 v4.6.4-0.20230523181720-70dea644d559 + gitlab.com/elixxir/crypto v0.0.7-0.20230522190154-5cbcf67f4b39 gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c gitlab.com/elixxir/wasm-utils v0.0.0-20230522231408-a43b2c1481b2 gitlab.com/xx_network/crypto v0.0.5-0.20230214003943-8a09396e95dd @@ -59,6 +59,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-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 3d373783de8a69f614d0a278747f6839aac5bea7..e596cd0c8a1470a0cd2488f065f69f95ff262519 100644 --- a/go.sum +++ b/go.sum @@ -405,16 +405,50 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= gitlab.com/elixxir/bloomfilter v0.0.0-20230322223210-fa84f6842de8 h1:uAFCyBkXprQoPkcDDfxXtaMyL5x+xSGrAWzR907xROQ= gitlab.com/elixxir/bloomfilter v0.0.0-20230322223210-fa84f6842de8/go.mod h1:1X8gRIAPDisS3W6Vtr/ymiUmZMJUIwDV1o5DEOo/pzw= -gitlab.com/elixxir/client/v4 v4.6.4-0.20230523215224-750d3d1707fd h1:ZF/3GcYFMe0KJt8zF1IhCK9YCgBpn3f+cTLqJKWFh+M= -gitlab.com/elixxir/client/v4 v4.6.4-0.20230523215224-750d3d1707fd/go.mod h1:HgAbm91+FJ5NZ+tO9J1YoAcOOeH3n6ctu0AARQPHr5I= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230413171204-002612660098 h1:bdwXgEa0i9KpLiKQdhv6MEWAYLt3MsbNuIzFanVpWLY= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230413171204-002612660098/go.mod h1:G+lN+LvQPGcm5BQnrhnqT1xiRIAzH3OffAM+5oI9SUg= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230425190953-cd51598e9245 h1:pBwoSYD+BFIr5Wyc+PQhqm+fZGsRSNXCpF0z1cQQzK8= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230425190953-cd51598e9245/go.mod h1:G+lN+LvQPGcm5BQnrhnqT1xiRIAzH3OffAM+5oI9SUg= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230511215110-b43e18a47875 h1:u9DlU8xAk0rTvguhWK+6D/MfLHdR+jlDTfGJjiszJDE= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230511215110-b43e18a47875/go.mod h1:dLKU2zSWrZLk/fomAtt1DFGgpTHQAfPdxdXNp3EtRZU= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230512234533-17b97e5a36cc h1:f5lwmwejXTerTUjro9d5Ws1mKGD6ChXHMaBMhB3OhgA= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230512234533-17b97e5a36cc/go.mod h1:dLKU2zSWrZLk/fomAtt1DFGgpTHQAfPdxdXNp3EtRZU= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230515171506-7294c8dd22fa h1:HCt2CMRWlT19OYQkC2xcU2+Saa1ZcH2y4IQeqg3NcX0= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230515171506-7294c8dd22fa/go.mod h1:dLKU2zSWrZLk/fomAtt1DFGgpTHQAfPdxdXNp3EtRZU= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230516202225-832a99a19553 h1:jdEpGIKNmFHMVmqIOnXFUeWObmReM0IOMov4eqD8OY8= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230516202225-832a99a19553/go.mod h1:dLKU2zSWrZLk/fomAtt1DFGgpTHQAfPdxdXNp3EtRZU= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230519185423-524554d6cfd1 h1:Uksd5R1Hk3j7RJqWDyanmD8fOQTL2bBfH0/F8vC6ysI= +gitlab.com/elixxir/client/v4 v4.6.2-0.20230519185423-524554d6cfd1/go.mod h1:dLKU2zSWrZLk/fomAtt1DFGgpTHQAfPdxdXNp3EtRZU= +gitlab.com/elixxir/client/v4 v4.6.3 h1:oUsm5cn2Vnfqz+xwGYKrqFkPNN3sDAyp00EPGhUIA5E= +gitlab.com/elixxir/client/v4 v4.6.3/go.mod h1:G+lN+LvQPGcm5BQnrhnqT1xiRIAzH3OffAM+5oI9SUg= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230519223444-1d981a1d95aa h1:PJylTJ4ol3p3Si9cipFmhhWo0YD4VXMrbHQODJ9ACKE= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230519223444-1d981a1d95aa/go.mod h1:rDC4sLKgj5kuuiJRp8bD1M7r0mlb0ib7q8q1Euct9/k= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230522204511-a198ba2e5749 h1:mFhb9/TDAtmvuDtBL70vvQCwg7OGSWcCLxXcqcfG3rQ= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230522204511-a198ba2e5749/go.mod h1:rDC4sLKgj5kuuiJRp8bD1M7r0mlb0ib7q8q1Euct9/k= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230522213235-dc7d3feb05b9 h1:/g+OA8nsI0LwY1NgR7WPOAztengA2UqrY7xXZarmwgk= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230522213235-dc7d3feb05b9/go.mod h1:trGefpFqH2+kx4/uEV+yyiEWpGq3AhRMnuBQDhDQKMM= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230523165030-737b5db25f0d h1:amrJ1WHTJd9+EArwgoq4XUwHu09hFwxYNtTc3S7W7ew= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230523165030-737b5db25f0d/go.mod h1:trGefpFqH2+kx4/uEV+yyiEWpGq3AhRMnuBQDhDQKMM= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230523181720-70dea644d559 h1:F1/+kAVnCqsxHeAiX7S0wYDGF0VhfNMEGoZZayyvt2w= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230523181720-70dea644d559/go.mod h1:trGefpFqH2+kx4/uEV+yyiEWpGq3AhRMnuBQDhDQKMM= +gitlab.com/elixxir/comms v0.0.4-0.20230310205528-f06faa0d2f0b h1:8AVK93UEs/aufoqtFgyMVt9gf0oJ8F4pA60ZvEVvG+s= +gitlab.com/elixxir/comms v0.0.4-0.20230310205528-f06faa0d2f0b/go.mod h1:z+qW0D9VpY5QKTd7wRlb5SK4kBNqLYsa4DXBcUXue9Q= gitlab.com/elixxir/comms v0.0.4-0.20230519211512-4a998f4b0938 h1:f27+QUFiGWrprKm+fstOg3ABkYLpWcZi3+8Lf5eDnqY= gitlab.com/elixxir/comms v0.0.4-0.20230519211512-4a998f4b0938/go.mod h1:z+qW0D9VpY5QKTd7wRlb5SK4kBNqLYsa4DXBcUXue9Q= -gitlab.com/elixxir/crypto v0.0.7-0.20230522162218-45433d877235 h1:0BySdXTzRWxzH8k5RiNNMmmn2lpuQWLVcDDA/7ehyqc= -gitlab.com/elixxir/crypto v0.0.7-0.20230522162218-45433d877235/go.mod h1:IYInxKr5Q7EH3oNhg1QX1/sTTRNi7L0JkcyfdRegoio= +gitlab.com/elixxir/crypto v0.0.7-0.20230413162806-a99ec4bfea32 h1:Had0F7rMPgJJ2BUZoFNgeJq33md9RpV15nvd08Uxdzc= +gitlab.com/elixxir/crypto v0.0.7-0.20230413162806-a99ec4bfea32/go.mod h1:/SLOlvkYVVJf6IU+vEjMLnS7cjjcoTlPV45g6tv6INc= +gitlab.com/elixxir/crypto v0.0.7-0.20230519214355-b10a9f95d395 h1:aOoL0oyocmLUbCBXgF52QhtBXvAi+eXM1d0DrDsFkIg= +gitlab.com/elixxir/crypto v0.0.7-0.20230519214355-b10a9f95d395/go.mod h1:IYInxKr5Q7EH3oNhg1QX1/sTTRNi7L0JkcyfdRegoio= +gitlab.com/elixxir/crypto v0.0.7-0.20230522190154-5cbcf67f4b39 h1:cU8066kdJRH88GUetdoYfT4ATg+uzSyquhHbVcbxw7Q= +gitlab.com/elixxir/crypto v0.0.7-0.20230522190154-5cbcf67f4b39/go.mod h1:IYInxKr5Q7EH3oNhg1QX1/sTTRNi7L0JkcyfdRegoio= +gitlab.com/elixxir/ekv v0.2.1 h1:dtwbt6KmAXG2Tik5d60iDz2fLhoFBgWwST03p7T+9Is= +gitlab.com/elixxir/ekv v0.2.1/go.mod h1:USLD7xeDnuZEavygdrgzNEwZXeLQJK/w1a+htpN+JEU= gitlab.com/elixxir/ekv v0.3.1-0.20230504190918-f5e96603c2e0 h1:4d2vg4Sh3N5mR1ta152cg6ybPWHYqsPtkEyJKaDYGnw= gitlab.com/elixxir/ekv v0.3.1-0.20230504190918-f5e96603c2e0/go.mod h1:EMaUQrsOxvEPQ0/8V/PSkGqFmEC2axBG/uqY0oW2uJM= gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c h1:muG8ff95woeVVwQoJHCEclxBFB22lc7EixPylEkYDRU= 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= diff --git a/indexedDb/impl/channels/callbacks.go b/indexedDb/impl/channels/callbacks.go index e41bf1dd0f95fc7b7073e7b79b129f6c74b348ad..1d541bf5f23280bfc41d45d6b64f05e2ff4c6684 100644 --- a/indexedDb/impl/channels/callbacks.go +++ b/indexedDb/impl/channels/callbacks.go @@ -15,6 +15,7 @@ import ( "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/client/v4/bindings" "gitlab.com/elixxir/client/v4/channels" "gitlab.com/elixxir/client/v4/cmix/rounds" cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast" @@ -81,25 +82,25 @@ func (m *manager) newWASMEventModelCB(data []byte) ([]byte, error) { // EventUpdate implements [bindings.ChannelUICallbacks.EventUpdate]. func (m *manager) EventUpdate(eventType int64, jsonData []byte) { - // Package parameters for sending - msg := &wChannels.EventUpdateCallbackMessage{ - EventType: eventType, - JsonData: jsonData, + var callbackTag worker.Tag + isValid := false + switch eventType { + case bindings.MessageReceived: + callbackTag = wChannels.MessageReceivedCallbackTag + isValid = true + case bindings.MessageDeleted: + callbackTag = wChannels.DeletedMessageCallbackTag + isValid = true + case bindings.UserMuted: + callbackTag = wChannels.MutedUserCallbackTag + isValid = true + default: + jww.ERROR.Printf("invalid indexedDB EventUpdate type %d: %+v)", + eventType, jsonData) + } + if isValid { + m.wtm.SendMessage(callbackTag, jsonData) } - data, err := json.Marshal(msg) - if err != nil { - jww.ERROR.Printf("Could not JSON marshal %T: %+v", msg, err) - return - } - - // Send it to the main thread - m.wtm.SendMessage(wChannels.EventUpdateCallbackTag, data) -} - -// NicknameUpdate implements [bindings.ChannelUICallbacks.NicknameUpdate] -func (m *manager) NicknameUpdate(channelIdBytes []byte, nickname string, - exists bool) { - jww.FATAL.Panicf("unimplemented") } // joinChannelCB is the callback for wasmModel.JoinChannel. Always returns nil; diff --git a/indexedDb/impl/channels/implementation.go b/indexedDb/impl/channels/implementation.go index f043c60be8b1c2b91931a466c1153ee2680ce07c..013d4e9a720f02b14b4efa1bfe3e159f0b277c26 100644 --- a/indexedDb/impl/channels/implementation.go +++ b/indexedDb/impl/channels/implementation.go @@ -172,11 +172,7 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID, messageID message.ID, return 0 } - go w.eventUpdate(bindings.MessageReceived, bindings.MessageReceivedJson{ - Uuid: int64(uuid), - ChannelID: channelID, - Update: false, - }) + w.sendReceiveMessageUpdate(uuid, channelID, false) return uuid } @@ -215,11 +211,7 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID, messageID, return 0 } - go w.eventUpdate(bindings.MessageReceived, bindings.MessageReceivedJson{ - Uuid: int64(uuid), - ChannelID: channelID, - Update: false, - }) + w.sendReceiveMessageUpdate(uuid, channelID, false) return uuid } @@ -257,12 +249,7 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID, messageID, jww.ERROR.Printf("Failed to receive reaction: %+v", err) return 0 } - - go w.eventUpdate(bindings.MessageReceived, bindings.MessageReceivedJson{ - Uuid: int64(uuid), - ChannelID: channelID, - Update: false, - }) + w.sendReceiveMessageUpdate(uuid, channelID, false) return uuid } @@ -409,18 +396,7 @@ func (w *wasmModel) updateMessage(currentMsg *Message, messageID *message.ID, if err != nil { return 0, err } - - channelID, err := id.Unmarshal(currentMsg.ChannelID) - if err != nil { - return 0, err - } - - go w.eventUpdate(bindings.MessageReceived, bindings.MessageReceivedJson{ - Uuid: int64(uuid), - ChannelID: channelID, - Update: true, - }) - + w.sendReceiveMessageUpdate(uuid, (*id.ID)(currentMsg.ChannelID), true) return uuid, nil } @@ -517,21 +493,48 @@ func (w *wasmModel) DeleteMessage(messageID message.ID) error { return err } - go w.eventUpdate(bindings.MessageDeleted, - bindings.MessageDeletedJson{MessageID: messageID}) - + eventData, err := json.Marshal(bindings.MessageDeletedJson{ + MessageID: messageID, + }) + if err != nil { + jww.WARN.Printf("couldn't marshal MessageDeleted: %s, %+v", + messageID, err) + } else { + go w.cbs.EventUpdate(bindings.MessageDeleted, eventData) + } return nil } // MuteUser is called whenever a user is muted or unmuted. func (w *wasmModel) MuteUser( channelID *id.ID, pubKey ed25519.PublicKey, unmute bool) { - - go w.eventUpdate(bindings.UserMuted, bindings.UserMutedJson{ + eventData, err := json.Marshal(bindings.UserMutedJson{ ChannelID: channelID, PubKey: pubKey, Unmute: unmute, }) + if err != nil { + jww.WARN.Printf("couldn't marshal UserMuted: %s, %+v", + pubKey, err) + } else { + go w.cbs.EventUpdate(bindings.UserMuted, eventData) + } +} + +func (w *wasmModel) sendReceiveMessageUpdate(uuid uint64, channelID *id.ID, + update bool) { + eventMsg := bindings.MessageReceivedJson{ + Uuid: int64(uuid), + ChannelID: channelID, + Update: update, + } + eventData, err := json.Marshal(eventMsg) + if err != nil { + jww.WARN.Printf("couldn't marshal MessageReceive: %v, %+v", + eventMsg, err) + } else { + go w.cbs.EventUpdate(bindings.MessageReceived, eventData) + } } // valueToMessage is a helper for converting js.Value to Message. diff --git a/indexedDb/impl/channels/implementation_test.go b/indexedDb/impl/channels/implementation_test.go index cdf17e6f2e63e9990af5acc02f6852ee0459528f..1a8c87f0792a71ab6274e4e82f7ef075bd17e5f7 100644 --- a/indexedDb/impl/channels/implementation_test.go +++ b/indexedDb/impl/channels/implementation_test.go @@ -43,7 +43,8 @@ func TestMain(m *testing.M) { } type dummyCbs struct{} -func (c *dummyCbs) EventUpdate(int64, []byte) {} + +func (c *dummyCbs) EventUpdate(eventType int64, dataJson []byte) {} // Happy path test for receiving, updating, getting, and deleting a File. func TestWasmModel_ReceiveFile(t *testing.T) { diff --git a/indexedDb/worker/channels/init.go b/indexedDb/worker/channels/init.go index e8a8f9419ff25da299bcb3f868b01ab4b1e048d5..dd0dd99d474299327a12aff8712ced83f9ba46e5 100644 --- a/indexedDb/worker/channels/init.go +++ b/indexedDb/worker/channels/init.go @@ -27,8 +27,10 @@ import ( // databaseSuffix is the suffix to be appended to the name of the database. const databaseSuffix = "_speakeasy" -// EventUpdate is called any time an event occurs. -type EventUpdate func(eventType int64, jsonData []byte) +// eventUpdateCallback is the [bindings.ChannelUICallback] callback function +// it has a type ([bindings.NickNameUpdate] to [bindings.MessageDeleted] +// and json data that is the callback information. +type eventUpdateCallback func(eventType int64, jsonData []byte) // NewWASMEventModelBuilder returns an EventModelBuilder which allows // the channel manager to define the path but the callback is the same @@ -62,10 +64,18 @@ func NewWASMEventModel(path, wasmJsPath string, encryption cryptoChannel.Cipher, return nil, err } - // Register handler to manage messages for the EventUpdate - wm.RegisterCallback(EventUpdateCallbackTag, + // Register handler to manage messages for the MessageReceivedCallback + wm.RegisterCallback(MessageReceivedCallbackTag, messageReceivedCallbackHandler(channelCbs.EventUpdate)) + // Register handler to manage messages for the DeletedMessageCallback + wm.RegisterCallback(DeletedMessageCallbackTag, + deletedMessageCallbackHandler(channelCbs.EventUpdate)) + + // Register handler to manage messages for the MutedUserCallback + wm.RegisterCallback(MutedUserCallbackTag, + mutedUserCallbackHandler(channelCbs.EventUpdate)) + // Store the database name err = storage.StoreIndexedDb(databaseName) if err != nil { @@ -120,17 +130,25 @@ type EventUpdateCallbackMessage struct { // messageReceivedCallbackHandler returns a handler to manage messages for the // MessageReceivedCallback. -func messageReceivedCallbackHandler(cb EventUpdate) func(data []byte) { +func messageReceivedCallbackHandler(cb eventUpdateCallback) func(data []byte) { return func(data []byte) { - var msg EventUpdateCallbackMessage - err := json.Unmarshal(data, &msg) - if err != nil { - jww.ERROR.Printf( - "Failed to JSON unmarshal %T from worker: %+v", msg, err) - return - } + cb(bindings.MessageReceived, data) + } +} - cb(msg.EventType, msg.JsonData) +// deletedMessageCallbackHandler returns a handler to manage messages for the +// DeletedMessageCallback. +func deletedMessageCallbackHandler(cb eventUpdateCallback) func(data []byte) { + return func(data []byte) { + cb(bindings.MessageDeleted, data) + } +} + +// mutedUserCallbackHandler returns a handler to manage messages for the +// MutedUserCallback. +func mutedUserCallbackHandler(cb eventUpdateCallback) func(data []byte) { + return func(data []byte) { + cb(bindings.UserMuted, data) } } diff --git a/indexedDb/worker/channels/tags.go b/indexedDb/worker/channels/tags.go index f21c91653547cfe37158d514ef482c468084d800..019911288e4cdc2c78ad352d7813094e31aeee99 100644 --- a/indexedDb/worker/channels/tags.go +++ b/indexedDb/worker/channels/tags.go @@ -14,8 +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" - EventUpdateCallbackTag worker.Tag = "EventUpdateCallback" + 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 bf8ab4ae1251c5ccf8413efdbc1daf94bb014b7b..267bb55bb812d1950c412a51337464cd35f39b36 100644 --- a/main.go +++ b/main.go @@ -100,6 +100,11 @@ func setGlobals() { js.Global().Set("InitializeBackup", js.FuncOf(wasm.InitializeBackup)) js.Global().Set("ResumeBackup", js.FuncOf(wasm.ResumeBackup)) + // wasm/notifications.go + js.Global().Set("LoadNotifications", js.FuncOf(wasm.LoadNotifications)) + js.Global().Set("LoadNotificationsDummy", + js.FuncOf(wasm.LoadNotificationsDummy)) + // wasm/channels.go js.Global().Set("GenerateChannelIdentity", js.FuncOf(wasm.GenerateChannelIdentity)) @@ -133,6 +138,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 a21c9a42a1486ab84937c525028daa8c3d291817..f7aa105d2b27763cdef1f69126812be92594f67b 100644 --- a/wasm/channels.go +++ b/wasm/channels.go @@ -17,10 +17,8 @@ import ( "syscall/js" "gitlab.com/elixxir/client/v4/bindings" - "gitlab.com/elixxir/client/v4/channels" "gitlab.com/elixxir/wasm-utils/exception" "gitlab.com/elixxir/wasm-utils/utils" - channelsDb "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/channels" ) //////////////////////////////////////////////////////////////////////////////// @@ -80,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 @@ -255,35 +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] - 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] - 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] - ID of [Notifications] object in tracker. This can be retrieved -// using [Notifications.GetID] (int). -// - args[5] - A Javascript object that implements the function on -// [bindings.ChannelUICallbacks]. It is a callback that informs the UI about -// various events. The entire interface can be nil, but if defined, each -// method must be implemented. +// - 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 an error if creating the manager fails. func NewChannelsManager(_ js.Value, args []js.Value) any { cmixId := args[0].Int() - privateIdentity := utils.CopyBytesToGo(args[1]) - em := newEventModelBuilder(args[2]) + notificationsId := args[1].Int() + privateIdentity := utils.CopyBytesToGo(args[2]) extensionBuilderIDsJSON := utils.CopyBytesToGo(args[3]) - notificationsID := args[4].Int() - cUI := newChannelUI(args[5]) + em := newEventModelBuilder(args[4]) + channelCbs := newChannelUI(args[5]) cm, err := bindings.NewChannelsManager( - cmixId, privateIdentity, em, extensionBuilderIDsJSON, notificationsID, cUI) + cmixId, privateIdentity, extensionBuilderIDsJSON, em, + notificationsId, channelCbs) if err != nil { exception.ThrowTrace(err) return nil @@ -303,34 +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 initializes 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] - 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]`. -// - args[4] - ID of [Notifications] object in tracker. This can be retrieved -// using [Notifications.GetID] (int). -// - args[5] - A Javascript object that implements the function on -// [bindings.ChannelUICallbacks]. It is a callback that informs the UI about -// various events. The entire interface can be nil, but if defined, each -// method must be implemented. +// - args[4] - A callback object which implements the +// [bindings.ChannelUICallbacks] javascript functions. // // Returns: // - Javascript representation of the [ChannelsManager] object. // - Throws an error if loading the manager fails. func LoadChannelsManager(_ js.Value, args []js.Value) any { - cmixID := args[0].Int() - storageTag := args[1].String() - em := newEventModelBuilder(args[2]) - extensionBuilderIDsJSON := utils.CopyBytesToGo(args[3]) - notificationsID := args[4].Int() - cUI := newChannelUI(args[5]) - cm, err := bindings.LoadChannelsManager( - cmixID, storageTag, em, extensionBuilderIDsJSON, notificationsID, 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 @@ -353,19 +348,17 @@ 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] - ID of [Notifications] object in tracker. This can be retrieved -// using [Notifications.GetID] (int). -// - args[5] - A Javascript object that implements the function on -// [bindings.ChannelUICallbacks]. It is a callback that informs the UI about -// various events. The entire interface can be nil, but if defined, each -// method must be implemented. +// - args[5] - A callback object which implements the +// [bindings.ChannelUICallbacks] javascript functions. // - args[6] - ID of [ChannelDbCipher] object in tracker (int). Create this // object with [NewChannelsDatabaseCipher] and get its id with // [ChannelDbCipher.GetID]. @@ -376,11 +369,11 @@ func LoadChannelsManager(_ js.Value, args []js.Value) any { // - Throws an error 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]) - notificationsID := args[4].Int() - cUI := newChannelUI(args[5]) + 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) @@ -388,8 +381,9 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any { exception.ThrowTrace(err) } - return newChannelsManagerWithIndexedDb(cmixID, wasmJsPath, privateIdentity, - extensionBuilderIDsJSON, notificationsID, cUI, cipher) + return newChannelsManagerWithIndexedDb(cmixID, notificationsID, + wasmJsPath, privateIdentity, + extensionBuilderIDsJSON, channelCbs, cipher) } // NewChannelsManagerWithIndexedDbUnsafe creates a new [ChannelsManager] from a @@ -407,19 +401,17 @@ 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] - ID of [Notifications] object in tracker. This can be retrieved -// using [Notifications.GetID] (int). -// - args[5] - A Javascript object that implements the function on -// [bindings.ChannelUICallbacks]. It is a callback that informs the UI about -// various events. The entire interface can be nil, but if defined, each -// method must be implemented. +// - args[5] - A callback object which implements the +// [bindings.ChannelUICallbacks] javascript functions. // // Returns a promise: // - Resolves to a Javascript representation of the [ChannelsManager] object. @@ -428,18 +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]) - notificationsID := args[4].Int() - cUI := newChannelUI(args[5]) + 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, wasmJsPath, privateIdentity, - extensionBuilderIDsJSON, notificationsID, cUI, nil) + return newChannelsManagerWithIndexedDb(cmixID, notificationsID, + wasmJsPath, privateIdentity, + extensionBuilderIDsJSON, channelsCbs, nil) } -func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string, - privateIdentity, extensionBuilderIDsJSON []byte, notificationsID int, +func newChannelsManagerWithIndexedDb(cmixID, notificationsID int, + wasmJsPath string, privateIdentity, extensionBuilderIDsJSON []byte, channelsCbs bindings.ChannelUICallbacks, cipher *bindings.ChannelDbCipher) any { @@ -447,9 +440,9 @@ func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string, wasmJsPath, cipher, channelsCbs) promiseFn := func(resolve, reject func(args ...any) js.Value) { - cm, err := bindings.NewChannelsManagerGoEventModel(cmixID, - privateIdentity, extensionBuilderIDsJSON, model, notificationsID, - channelsCbs) + cm, err := bindings.NewChannelsManagerGoEventModel( + cmixID, privateIdentity, extensionBuilderIDsJSON, model, + notificationsID, channelsCbs) if err != nil { reject(exception.NewTrace(err)) } else { @@ -471,20 +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] - 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] - ID of [Notifications] object in tracker. This can be retrieved -// using [Notifications.GetID] (int). -// - args[5] - A Javascript object that implements the function on -// [bindings.ChannelUICallbacks]. It is a callback that informs the UI about -// various events. The entire interface can be nil, but if defined, each -// method must be implemented. -// - args[6] - ID of [ChannelDbCipher] object in tracker (int). Create this +// - args[4] - A callback object which implements the +// [bindings.ChannelUICallbacks] javascript functions. +// - args[5] - ID of [ChannelDbCipher] object in tracker (int). Create this // object with [NewChannelsDatabaseCipher] and get its id with // [ChannelDbCipher.GetID]. // @@ -494,20 +481,20 @@ func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string, // - Throws an error 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() - extensionBuilderIDsJSON := utils.CopyBytesToGo(args[3]) - notificationsID := args[4].Int() - channelsCbs := newChannelUI(args[5]) - cipherID := args[6].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, - extensionBuilderIDsJSON, notificationsID, channelsCbs, cipher) + return loadChannelsManagerWithIndexedDb(cmixID, notificationsID, + wasmJsPath, storageTag, + channelsCbs, cipher) } // LoadChannelsManagerWithIndexedDbUnsafe loads an existing [ChannelsManager] @@ -523,37 +510,32 @@ 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] - 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] - ID of [Notifications] object in tracker. This can be retrieved -// using [Notifications.GetID] (int). -// - args[5] - A Javascript object that implements the function on -// [bindings.ChannelUICallbacks]. It is a callback that informs the UI about -// various events. The entire interface can be nil, but if defined, each -// method must be implemented. +// - args[4] - A callback object which implements the +// [bindings.ChannelUICallbacks] javascript functions. // // Returns a promise: // - Resolves to a Javascript representation of the [ChannelsManager] object. // - 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() - extensionBuilderIDsJSON := utils.CopyBytesToGo(args[3]) - notificationsID := args[4].Int() - cUI := newChannelUI(args[5]) + notificationsID := args[1].Int() + wasmJsPath := args[2].String() + storageTag := args[3].String() + cUI := newChannelUI(args[4]) - return loadChannelsManagerWithIndexedDb(cmixID, wasmJsPath, storageTag, - extensionBuilderIDsJSON, notificationsID, cUI, nil) + return loadChannelsManagerWithIndexedDb(cmixID, notificationsID, + wasmJsPath, storageTag, + cUI, nil) } -func loadChannelsManagerWithIndexedDb(cmixID int, wasmJsPath, storageTag string, - extensionBuilderIDsJSON []byte, notificationsID int, channelsCbs bindings.ChannelUICallbacks, +func loadChannelsManagerWithIndexedDb(cmixID, notificationsID int, + wasmJsPath, storageTag string, + channelsCbs bindings.ChannelUICallbacks, cipher *bindings.ChannelDbCipher) any { model := channelsDb.NewWASMEventModelBuilder( @@ -561,7 +543,7 @@ func loadChannelsManagerWithIndexedDb(cmixID int, wasmJsPath, storageTag string, promiseFn := func(resolve, reject func(args ...any) js.Value) { cm, err := bindings.LoadChannelsManagerGoEventModel( - cmixID, storageTag, model, extensionBuilderIDsJSON, notificationsID, + cmixID, storageTag, model, nil, notificationsID, channelsCbs) if err != nil { reject(exception.NewTrace(err)) @@ -992,16 +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] - JSON of a slice of public keys of users that should receive -// mobile notifications for the message. -// -// Example slice of public keys: -// -// [ -// "FgJMvgSsY4rrKkS/jSe+vFOJOs5qSSyOUSW7UtF9/KU=", -// "fPqcHtrJ398PAC35QyWXEU9PHzz8Z4BKQTCxSvpSygw=", -// "JnjCgh7g/+hNiI9VPKW01aRSxGOFmNulNCymy3ImXAo=" -// ] +// - 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). @@ -1013,11 +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]) - pingsJSON := utils.CopyBytesToGo(args[6]) + var pingBytes [][]byte promiseFn := func(resolve, reject func(args ...any) js.Value) { - sendReport, err := cm.api.SendGeneric(marshalledChanId, messageType, - msg, leaseTimeMS, tracked, cmixParamsJSON, pingsJSON) + 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 { @@ -1047,16 +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] - JSON of a slice of public keys of users that should receive -// mobile notifications for the message. -// -// Example slice of public keys: -// -// [ -// "FgJMvgSsY4rrKkS/jSe+vFOJOs5qSSyOUSW7UtF9/KU=", -// "fPqcHtrJ398PAC35QyWXEU9PHzz8Z4BKQTCxSvpSygw=", -// "JnjCgh7g/+hNiI9VPKW01aRSxGOFmNulNCymy3ImXAo=" -// ] +// - 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). @@ -1066,11 +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]) - pingsJSON := 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.SendMessage( - marshalledChanId, msg, leaseTimeMS, cmixParamsJSON, pingsJSON) + marshalledChanId, msg, leaseTimeMS, cmixParamsJSON, + pingBytes) if err != nil { reject(exception.NewTrace(err)) } else { @@ -1107,16 +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[5] - JSON of a slice of public keys of users that should receive -// mobile notifications for the message. -// -// Example slice of public keys: -// -// [ -// "FgJMvgSsY4rrKkS/jSe+vFOJOs5qSSyOUSW7UtF9/KU=", -// "fPqcHtrJ398PAC35QyWXEU9PHzz8Z4BKQTCxSvpSygw=", -// "JnjCgh7g/+hNiI9VPKW01aRSxGOFmNulNCymy3ImXAo=" -// ] +// - 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). @@ -1127,11 +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]) - pingsJSON := utils.CopyBytesToGo(args[5]) + 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, pingsJSON) + messageToReactTo, leaseTimeMS, cmixParamsJSON, + pingBytes) if err != nil { reject(exception.NewTrace(err)) } else { @@ -1164,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 { @@ -1585,17 +1567,18 @@ func (cm *ChannelsManager) GetMutedUsers(_ js.Value, args []js.Value) any { // Notifications // //////////////////////////////////////////////////////////////////////////////// -// GetNotificationLevel returns the [channels.NotificationLevel] for the given -// channel. +// GetNotificationLevel implements +// [bindings.ChannelsManager.GetNotificationLevel] // // Parameters: -// - args[0] - The marshalled bytes of the channel's [id.ID] (Uint8Array). +// - args[0] - channelIDBytes - The marshalled bytes of the +// channel's [id.ID] (Uint8Array) // // Returns: -// - The [channels.NotificationLevel] for the channel (int). -// - Throws an error if the channel ID cannot be unmarshalled or the channel -// cannot be found. -func (cm *ChannelsManager) GetNotificationLevel(_ js.Value, args []js.Value) any { +// - int - The [channels.NotificationLevel] for the channel. +// throws an error if there is an issue +func (cm *ChannelsManager) GetNotificationLevel(_ js.Value, + args []js.Value) any { channelIDBytes := utils.CopyBytesToGo(args[0]) level, err := cm.api.GetNotificationLevel(channelIDBytes) @@ -1607,116 +1590,59 @@ func (cm *ChannelsManager) GetNotificationLevel(_ js.Value, args []js.Value) any return level } -// SetMobileNotificationsLevel sets the notification level for the given -// channel. The [channels.NotificationLevel] dictates the type of notifications -// received and the status controls weather the notification is push or in-app. -// If muted, both the level and status must be set to mute. -// -// To use push notifications, a token must be registered with the notification -// manager. Note, when enabling push notifications, information may be shared -// with third parties (i.e., Firebase and Google's Palantir) and may represent a -// security risk to the user. +// SetMobileNotificationsLevel implements +// [bindings.ChannelsManager.SetMobileNotificationsLevel] // // Parameters: -// - args[0] - The marshalled bytes of the channel's [id.ID] (Uint8Array). -// - args[1] - The [channels.NotificationLevel] to set for the channel (int). -// - args[2] - The [notifications.NotificationState] to set for the channel -// (int). -// -// Returns: -// - Throws an error if setting the notification level fails. -func (cm *ChannelsManager) SetMobileNotificationsLevel(_ js.Value, args []js.Value) any { +// - args[0] - channelIDBytes - The marshaled bytes of the channel's [id.ID] +// (Uint8Array). +// - args[1] - level - The [channels.NotificationLevel] to set for +// the channel. +// - args[2] - status - The [notifications.NotificationState] to set +// for the channel. +// - args[3] - push - True to enable push notifications and false to +// only have in-app notifications. +// +// Returns nothing or throws an error +func (cm *ChannelsManager) SetMobileNotificationsLevel(_ js.Value, + args []js.Value) any { channelIDBytes := utils.CopyBytesToGo(args[0]) level := args[1].Int() status := args[2].Int() + push := args[3].Bool() - err := cm.api.SetMobileNotificationsLevel(channelIDBytes, level, status) + err := cm.api.SetMobileNotificationsLevel(channelIDBytes, level, + status, push) if err != nil { exception.ThrowTrace(err) - return nil } - return nil } -// GetNotificationReportsForMe checks the notification data against the filter -// list to determine which notifications belong to the user. A list of -// notification reports is returned detailing all notifications for the user. +// GetNotificationReportsForMe implements +// [bindings.GetNotificationsReportsForMe] // // Parameters: -// - notificationFilterJSON - JSON of a slice of [channels.NotificationFilter]. -// - notificationDataJSON - JSON of a slice of [notifications.Data]. -// -// Example JSON of a slice of [channels.NotificationFilter]: -// [ -// -// { -// "identifier": "O8NUg0KaDo18ybTKajXM/sgqEYS37+lewPhGV/2sMAUDYXN5bUlkZW50aWZpZXI=", -// "channelID": "O8NUg0KaDo18ybTKajXM/sgqEYS37+lewPhGV/2sMAUD", -// "tags": ["6de69009a93d53793ee344e8fb48fae194eaf51861d3cc51c7348c337d13aedf-usrping"], -// "allowLists": { -// "allowWithTags": {}, -// "allowWithoutTags": {"102":{}, "2":{}} -// } -// }, -// { -// "identifier": "O8NUg0KaDo18ybTKajXM/sgqEYS37+lewPhGV/2sMAUDc3ltSWRlbnRpZmllcg==", -// "channelID": "O8NUg0KaDo18ybTKajXM/sgqEYS37+lewPhGV/2sMAUD", -// "tags": ["6de69009a93d53793ee344e8fb48fae194eaf51861d3cc51c7348c337d13aedf-usrping"], -// "allowLists": { -// "allowWithTags": {}, -// "allowWithoutTags": {"1":{}, "40000":{}} -// } -// }, -// { -// "identifier": "jCRgFRQvzzKOb8DJ0fqCRLgr9kiHN9LpqHXVhyHhhlQDYXN5bUlkZW50aWZpZXI=", -// "channelID": "jCRgFRQvzzKOb8DJ0fqCRLgr9kiHN9LpqHXVhyHhhlQD", -// "tags": ["6de69009a93d53793ee344e8fb48fae194eaf51861d3cc51c7348c337d13aedf-usrping"], -// "allowLists": { -// "allowWithTags": {}, -// "allowWithoutTags": {"102":{}, "2":{}} -// } -// } -// ] -// -// Example JSON of a slice of [notifications.Data]: -// -// [ -// { -// "EphemeralID": -6475, -// "RoundID": 875, -// "IdentityFP": "jWG/UuxRjD80HEo0WX3KYIag5LCfgaWKAg==", -// "MessageHash": "hDGE46QWa3d70y5nJTLbEaVmrFJHOyp2" -// }, -// { -// "EphemeralID": -2563, -// "RoundID": 875, -// "IdentityFP": "gL4nhCGKPNBm6YZ7KC0v4JThw65N9bRLTQ==", -// "MessageHash": "WcS4vGrSWDK8Kj7JYOkMo8kSh1Xti94V" -// }, -// { -// "EphemeralID": -13247, -// "RoundID": 875, -// "IdentityFP": "qV3uD++VWPhD2rRMmvrP9j8hp+jpFSsUHg==", -// "MessageHash": "VX6Tw7N48j7U2rRXYle20mFZi0If4CB1" -// } -// ] +// - args[0] - notificationFilterJSON - JSON of a slice of +// [channels.NotificationFilter] (Uint8Array). +// - args[1] - notificationDataJSON - JSON of a slice of +// [notifications.Data] (Uint8Array). // // Returns: -// - The JSON of a slice of [channels.NotificationReport] (Uint8Array). -// - Throws an error if getting the report fails. +// - []byte - JSON of a slice of [channels.NotificationReport]. +// Throws an error if one occurs func GetNotificationReportsForMe(_ js.Value, args []js.Value) any { notificationFilterJSON := utils.CopyBytesToGo(args[0]) notificationDataJSON := utils.CopyBytesToGo(args[1]) - report, err := bindings.GetNotificationReportsForMe( - notificationFilterJSON, notificationDataJSON) + nrs, err := bindings.GetNotificationReportsForMe(notificationFilterJSON, + notificationDataJSON) if err != nil { exception.ThrowTrace(err) return nil } - return utils.CopyBytesToJS(report) + return utils.CopyBytesToJS(nrs) } //////////////////////////////////////////////////////////////////////////////// @@ -2465,6 +2391,8 @@ type channelUI struct { eventUpdate func(args ...any) js.Value } -func (c *channelUI) EventUpdate(eventType int64, jsonData []byte) { - c.eventUpdate(int(eventType), utils.CopyBytesToJS(jsonData)) +// EventUpdate implements +// [bindings.ChannelUICallbacks.EventUpdate]. +func (c *channelUI) EventUpdate(eventType int64, dataJson []byte) { + c.eventUpdate(eventType, utils.CopyBytesToJS(dataJson)) } diff --git a/wasm/collective.go b/wasm/collective.go index 932926d34d878bb042628125d271f9ce5b2a8dee..294fda36577133ee6da47e0615583770640b7410 100644 --- a/wasm/collective.go +++ b/wasm/collective.go @@ -14,6 +14,7 @@ import ( "syscall/js" "gitlab.com/elixxir/client/v4/bindings" + "gitlab.com/elixxir/wasm-utils/exception" "gitlab.com/elixxir/wasm-utils/utils" ) diff --git a/wasm/e2eHandler.go b/wasm/e2eHandler.go index ae3eb14c01991606c764022b9983c788bf36b81f..fd107b0b1390a9ec759e0cdfaf0a6544ee97d3e6 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,16 +201,19 @@ type processor struct { // // Parameters: // - message - Returns the message contents (Uint8Array). -// - tags - (Uint8Array). -// - metadata - (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, tags, metadata, receptionId []byte, - ephemeralId, roundId int64) { - p.process(utils.CopyBytesToJS(message), utils.CopyBytesToJS(tags), - utils.CopyBytesToJS(metadata), utils.CopyBytesToJS(receptionId), + ephemeralId int64, roundId int64) { + + p.process(utils.CopyBytesToJS(message), + utils.CopyBytesToJS(tags), + utils.CopyBytesToJS(metadata), + utils.CopyBytesToJS(receptionId), ephemeralId, roundId) } @@ -236,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 992596fc2cf80d543febdcd6facec9b658479f11..cfc49d4241bb0b87eb184685b4f521daa7105f03 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,21 +382,22 @@ func (tsc *trackServicesCallback) Callback(marshalData []byte, err error) { tsc.callback(utils.CopyBytesToJS(marshalData), exception.NewTrace(err)) } -// trackCompressedServicesCallback adheres to the -// [bindings.TrackCompressedServicesCallback] interface. +// trackServicesCallback adheres to the [bindings.TrackServicesCallback] +// interface. type trackCompressedServicesCallback struct { callback func(args ...any) js.Value } -// Callback is the callback for [Cmix.TrackServices] that passes a -// JSON-marshalled list of compressed backend services. If an error occurs while -// retrieving or marshalling the service list, then err will be non-null. +// 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 - JSON of [message.CompressedServiceList] (Uint8Array), -// which is a map of [id.ID] to an array of [message.CompressedService]. -// - err - Error that occurs during retrieval or marshalling. Null otherwise -// (Error). +// - marshalData - Returns the JSON of +// [message.CompressedServiceList] (Uint8Array). +// - err - Returns an error on failure (Error). // // Example JSON: // @@ -422,8 +424,9 @@ type trackCompressedServicesCallback struct { // } // ] // } -func (tsc *trackCompressedServicesCallback) Callback(marshalData []byte, err error) { - tsc.callback(utils.CopyBytesToJS(marshalData), exception.NewTrace(err)) +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 @@ -434,17 +437,20 @@ func (tsc *trackCompressedServicesCallback) Callback(marshalData []byte, err err // Parameters: // - args[0] - ID of [E2e] object in tracker (int). // - args[1] - Javascript object that has functions that implement the -// [bindings.ClientError] interface. -// - args[2] - Javascript object that has functions that implement the -// [bindings.TrackCompressedServicesCallback], which will be passed the JSON -// of [message.CompressedServiceList]. +// [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")}, - &trackCompressedServicesCallback{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 new file mode 100644 index 0000000000000000000000000000000000000000..2a4887292d140e22bbb8b14ee8d87ce1a72fbdff --- /dev/null +++ b/wasm/notifications.go @@ -0,0 +1,131 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 xx foundation // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file. // +//////////////////////////////////////////////////////////////////////////////// + +//go:build js && wasm + +package wasm + +import ( + "syscall/js" + + "gitlab.com/elixxir/client/v4/bindings" + "gitlab.com/elixxir/client/v4/notifications" + "gitlab.com/elixxir/wasm-utils/exception" +) + +type Notifications struct { + api bindings.Notifications +} + +// newNotificationsJS wrapts the bindings Noticiation object and implements +// wrappers in JS for all it's functionality. +func newNotificationsJS(api bindings.Notifications) map[string]any { + n := Notifications{api} + notificationsImplJS := map[string]any{ + "AddToken": js.FuncOf(n.AddToken), + "RemoveToken": js.FuncOf(n.RemoveToken), + "SetMaxState": js.FuncOf(n.SetMaxState), + "GetMaxState": js.FuncOf(n.GetMaxState), + "GetID": js.FuncOf(n.GetID), + } + return notificationsImplJS +} + +// LoadNotifications returns a JS wrapped implementation of +// [bindings.Notifications]. +// +// Parameters: +// - args[0] - the cMixID integer +// +// Returns a notifications object or throws an error +func LoadNotifications(_ js.Value, args []js.Value) any { + cMixID := args[0].Int() + api, err := bindings.LoadNotifications(cMixID) + if err != nil { + exception.ThrowTrace(err) + return nil + } + + return newNotificationsJS(api) +} + +// LoadNotificationsDummy returns a JS wrapped implementation of +// [bindings.Notifications] with a dummy notifications implementation. +// +// Parameters: +// - args[0] - the cMixID integer +// +// Returns a notifications object or throws an error +func LoadNotificationsDummy(_ js.Value, args []js.Value) any { + cMixID := args[0].Int() + api, err := bindings.LoadNotificationsDummy(cMixID) + if err != nil { + exception.ThrowTrace(err) + return nil + } + + return newNotificationsJS(api) +} + +// GetID returns the bindings ID for the [bindings.Notifications] object +func (n *Notifications) GetID(js.Value, []js.Value) any { + return n.api.GetID() +} + +// AddToken implements [bindings.Notifications.AddToken]. +// +// Parameters: +// - args[0] - newToken string +// - args[1] - app string +// +// Returns nothing or an error (throwable) +func (n *Notifications) AddToken(_ js.Value, args []js.Value) any { + newToken := args[0].String() + app := args[1].String() + + err := n.api.AddToken(newToken, app) + if err != nil { + exception.ThrowTrace(err) + } + + return nil +} + +// RemoveToken implements [bindings.Notifications.RemoveToken]. +// +// Returns nothing or throws an error. +func (n *Notifications) RemoveToken(_ js.Value, args []js.Value) any { + err := n.api.RemoveToken() + if err != nil { + exception.ThrowTrace(err) + } + return nil +} + +// SetMaxState implements [bindings.Notifications.SetMaxState] +// +// Parameters: +// - args[0] - maxState integer +// +// Returns nothing or throws an error +func (n *Notifications) SetMaxState(_ js.Value, args []js.Value) any { + maxState := int64(args[0].Int()) + + err := n.api.SetMaxState(notifications.NotificationState(maxState)) + if err != nil { + exception.ThrowTrace(err) + } + + return nil +} + +// GetMaxState implements [bindings.Notifications.GetMaxState] +// +// Returns the current maxState integer +func (n *Notifications) GetMaxState(_ js.Value, args []js.Value) any { + return int64(n.api.GetMaxState()) +}