From 408d04ee982ecc68295da70820bb29e4089b38e1 Mon Sep 17 00:00:00 2001
From: Jono Wenger <jono@elixxir.io>
Date: Fri, 10 Feb 2023 15:02:45 -0800
Subject: [PATCH] Fix bindings

---
 go.mod           |  2 +-
 go.sum           |  4 +--
 main.go          |  2 ++
 wasm/channels.go | 80 +++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 77 insertions(+), 11 deletions(-)

diff --git a/go.mod b/go.mod
index 36bb6b57..10df8563 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/pkg/errors v0.9.1
 	github.com/spf13/cobra v1.5.0
 	github.com/spf13/jwalterweatherman v1.1.0
-	gitlab.com/elixxir/client/v4 v4.3.12-0.20230130171647-cc3cced382ea
+	gitlab.com/elixxir/client/v4 v4.3.12-0.20230210230035-3659a70d7550
 	gitlab.com/elixxir/crypto v0.0.7-0.20230124220743-2a897bc01c59
 	gitlab.com/elixxir/primitives v0.0.3-0.20230109222259-f62b2a90b62c
 	gitlab.com/xx_network/crypto v0.0.5-0.20230124215920-951bed503c49
diff --git a/go.sum b/go.sum
index 256dd333..144015ee 100644
--- a/go.sum
+++ b/go.sum
@@ -401,8 +401,8 @@ 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-20211222005329-7d931ceead6f h1:yXGvNBqzZwAhDYlSnxPRbgor6JWoOt1Z7s3z1O9JR40=
 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20230130171647-cc3cced382ea h1:EeiPFLu/FLHN2XmbhLr8wAJrpoFx4JvWkYsn8FPiDLw=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20230130171647-cc3cced382ea/go.mod h1:OrNnBWm0nGiY/BK2ZNzjR6V0fS4+/aAYtVRE/d8uZ48=
+gitlab.com/elixxir/client/v4 v4.3.12-0.20230210230035-3659a70d7550 h1:hxzb7o1otcwbnnM8l5Wbo1wrxjcwh8iOa32/iBVpRYE=
+gitlab.com/elixxir/client/v4 v4.3.12-0.20230210230035-3659a70d7550/go.mod h1:OrNnBWm0nGiY/BK2ZNzjR6V0fS4+/aAYtVRE/d8uZ48=
 gitlab.com/elixxir/comms v0.0.4-0.20230116232020-39f76a2aeccc h1:sVcXrXylB4w4vMFTvPIssRNwz2FSTbyrtZTD921LRKo=
 gitlab.com/elixxir/comms v0.0.4-0.20230116232020-39f76a2aeccc/go.mod h1:Bb6XF9bC9TmuiklC4eWTeqSiZ0zMOTcMs5UFOp5DZlg=
 gitlab.com/elixxir/crypto v0.0.7-0.20230124220743-2a897bc01c59 h1:Imj5MSbTN+FtpRH+5Saf43YKU92J3cKvW9MpJ/QykcY=
diff --git a/main.go b/main.go
index 47552238..f170f646 100644
--- a/main.go
+++ b/main.go
@@ -89,6 +89,8 @@ func main() {
 	js.Global().Set("GetShareUrlType", js.FuncOf(wasm.GetShareUrlType))
 	js.Global().Set("ValidForever", js.FuncOf(wasm.ValidForever))
 	js.Global().Set("IsNicknameValid", js.FuncOf(wasm.IsNicknameValid))
+	js.Global().Set("GetNoMessageErr", js.FuncOf(wasm.GetNoMessageErr))
+	js.Global().Set("CheckNoMessageErr", js.FuncOf(wasm.CheckNoMessageErr))
 	js.Global().Set("NewChannelsDatabaseCipher",
 		js.FuncOf(wasm.NewChannelsDatabaseCipher))
 
diff --git a/wasm/channels.go b/wasm/channels.go
index 43ae72bd..73655407 100644
--- a/wasm/channels.go
+++ b/wasm/channels.go
@@ -402,6 +402,7 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any {
 // Returns a promise:
 //   - Resolves to a Javascript representation of the [ChannelsManager] object.
 //   - Rejected with an error if loading indexedDb or the manager fails.
+//
 // FIXME: package names in comments for indexedDb
 func NewChannelsManagerWithIndexedDbUnsafe(_ js.Value, args []js.Value) any {
 	cmixID := args[0].Int()
@@ -437,7 +438,7 @@ func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string,
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		cm, err := bindings.NewChannelsManagerGoEventModel(
-			cmixID, privateIdentity, model)
+			cmixID, privateIdentity, model, nil)
 		if err != nil {
 			reject(utils.JsTrace(err))
 		} else {
@@ -574,7 +575,7 @@ func loadChannelsManagerWithIndexedDb(cmixID int, wasmJsPath, storageTag string,
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		cm, err := bindings.LoadChannelsManagerGoEventModel(
-			cmixID, storageTag, model)
+			cmixID, storageTag, model, nil)
 		if err != nil {
 			reject(utils.JsTrace(err))
 		} else {
@@ -1673,6 +1674,30 @@ func (cm *ChannelsManager) RegisterReceiveHandler(_ js.Value, args []js.Value) a
 // Event Model Logic                                                          //
 ////////////////////////////////////////////////////////////////////////////////
 
+// GetNoMessageErr returns the error channels.NoMessageErr, which must be
+// returned by EventModel methods (such as EventModel.UpdateFromUUID,
+// EventModel.UpdateFromMessageID, and EventModel.GetMessage) when the message
+// cannot be found.
+//
+// Returns:
+//   - channels.NoMessageErr error message (string).
+func GetNoMessageErr(js.Value, []js.Value) any {
+	return bindings.GetNoMessageErr()
+}
+
+// CheckNoMessageErr determines if the error returned by an EventModel function
+// indicates that the message or item does not exist. It returns true if the
+// error contains channels.NoMessageErr.
+//
+// Parameters:
+//   - args[0] - Error to check (Error).
+//
+// Returns
+//   - True if the error contains channels.NoMessageErr (boolean).
+func CheckNoMessageErr(_ js.Value, args []js.Value) any {
+	return bindings.CheckNoMessageErr(utils.JsErrorToJson(args[0]))
+}
+
 // eventModelBuilder adheres to the [bindings.EventModelBuilder] interface.
 type eventModelBuilder struct {
 	build func(args ...any) js.Value
@@ -1864,13 +1889,22 @@ func (em *eventModel) ReceiveReaction(channelID, messageID, reactionTo []byte,
 //   - uuid - The unique identifier of the message in the database (int).
 //   - messageUpdateInfoJSON - JSON of [bindings.MessageUpdateInfo]
 //     (Uint8Array).
-func (em *eventModel) UpdateFromUUID(uuid int64, messageUpdateInfoJSON []byte) {
-	em.updateFromUUID(uuid, utils.CopyBytesToJS(messageUpdateInfoJSON))
+//
+// Returns:
+//   - Returns an error if the message cannot be updated. It must return the
+//     error from [GetNoMessageErr] if the message does not exist.
+func (em *eventModel) UpdateFromUUID(
+	uuid int64, messageUpdateInfoJSON []byte) error {
+	err := em.updateFromUUID(uuid, utils.CopyBytesToJS(messageUpdateInfoJSON))
+	return js.Error{Value: err}
 }
 
 // UpdateFromMessageID is called whenever a message with the message ID is
 // modified.
 //
+// Note for developers: The internal Javascript function must return JSON of
+// [UuidAndError], which includes the returned UUID or an error.
+//
 // Parameters:
 //   - messageID - The bytes of the [channel.MessageID] of the received message
 //     (Uint8Array).
@@ -1880,16 +1914,31 @@ func (em *eventModel) UpdateFromUUID(uuid int64, messageUpdateInfoJSON []byte) {
 // Returns:
 //   - A non-negative unique uuid for the modified message by which it can be
 //     referenced later with [EventModel.UpdateFromUUID] int).
+//   - Returns an error if the message cannot be updated. It must return the
+//     error from [GetNoMessageErr] if the message does not exist.
 func (em *eventModel) UpdateFromMessageID(
-	messageID []byte, messageUpdateInfoJSON []byte) int64 {
-	return int64(em.updateFromMessageID(utils.CopyBytesToJS(messageID),
-		utils.CopyBytesToJS(messageUpdateInfoJSON)).Int())
+	messageID []byte, messageUpdateInfoJSON []byte) (int64, error) {
+	uuidAndErrorBytes := utils.CopyBytesToGo(em.updateFromMessageID(
+		utils.CopyBytesToJS(messageID),
+		utils.CopyBytesToJS(messageUpdateInfoJSON)))
+
+	var uae UuidAndError
+	err := json.Unmarshal(uuidAndErrorBytes, &uae)
+	if err != nil {
+		return 0, err
+	}
+
+	if uae.Error != "" {
+		return 0, errors.New(uae.Error)
+	}
+
+	return uae.UUID, nil
 }
 
 // GetMessage returns the message with the given [channel.MessageID].
 //
 // Note for developers: The internal Javascript function must return JSON of
-// MessageAndError, which includes the returned [channels.ModelMessage] or any
+// [MessageAndError], which includes the returned [channels.ModelMessage] or any
 // error that occurs during lookup.
 //
 // Parameters:
@@ -1940,6 +1989,21 @@ func (em *eventModel) MuteUser(channelID, pubkey []byte, unmute bool) {
 		utils.CopyBytesToJS(channelID), utils.CopyBytesToJS(pubkey), unmute)
 }
 
+// UuidAndError contains a UUID returned by an eventModel method or any possible
+// error that occurs. Only one field should be present at a time.
+//
+// Example JSON:
+//
+//	{ "uuid": 5, }
+//
+// Or:
+//
+//	{ "error": "An error occurred." }
+type UuidAndError struct {
+	UUID  int64  `json:"uuid,omitempty"`
+	Error string `json:"error,omitempty"`
+}
+
 // MessageAndError contains a message returned by eventModel.GetMessage or any
 // possible error that occurs during lookup. Only one field should be present at
 // a time; if an error occurs, ModelMessage should be empty.
-- 
GitLab