Skip to content
Snippets Groups Projects

fix for latest client release

Merged Jake Taylor requested to merge release into master
Compare and Show latest version
20 files
+ 684
586
Compare changes
  • Side-by-side
  • Inline
Files
20
@@ -13,8 +13,6 @@ import (
"crypto/ed25519"
"encoding/json"
"strconv"
"strings"
"sync"
"syscall/js"
"time"
@@ -36,13 +34,14 @@ import (
// wasmModel implements [channels.EventModel] interface, which uses the channels
// system passed an object that adheres to in order to get events on the
// channel.
// NOTE: This model is NOT thread safe - it is the responsibility of the
// caller to ensure that its methods are called sequentially.
type wasmModel struct {
db *idb.Database
cipher cryptoChannel.Cipher
receivedMessageCB wChannels.MessageReceivedCallback
deletedMessageCB wChannels.DeletedMessageCallback
mutedUserCB wChannels.MutedUserCallback
updateMux sync.Mutex
}
// JoinChannel is called whenever a channel is joined locally.
@@ -166,9 +165,10 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID, messageID message.ID,
textBytes, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType,
false, hidden, status)
uuid, err := w.receiveHelper(msgToInsert, false)
uuid, err := w.upsertMessage(msgToInsert)
if err != nil {
jww.ERROR.Printf("Failed to receive Message: %+v", err)
return 0
}
go w.receivedMessageCB(uuid, channelID, false)
@@ -202,10 +202,10 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID, messageID,
replyTo.Bytes(), nickname, textBytes, pubKey, dmToken, codeset,
timestamp, lease, round.ID, mType, hidden, false, status)
uuid, err := w.receiveHelper(msgToInsert, false)
uuid, err := w.upsertMessage(msgToInsert)
if err != nil {
jww.ERROR.Printf("Failed to receive reply: %+v", err)
return 0
}
go w.receivedMessageCB(uuid, channelID, false)
return uuid
@@ -239,9 +239,10 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID, messageID,
textBytes, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType,
false, hidden, status)
uuid, err := w.receiveHelper(msgToInsert, false)
uuid, err := w.upsertMessage(msgToInsert)
if err != nil {
jww.ERROR.Printf("Failed to receive reaction: %+v", err)
return 0
}
go w.receivedMessageCB(uuid, channelID, false)
return uuid
@@ -257,24 +258,25 @@ func (w *wasmModel) UpdateFromUUID(uuid uint64, messageID *message.ID,
status *channels.SentStatus) {
parentErr := errors.New("failed to UpdateFromUUID")
// FIXME: this is a bit of race condition without the mux.
// This should be done via the transactions (i.e., make a
// special version of receiveHelper)
w.updateMux.Lock()
defer w.updateMux.Unlock()
// Convert messageID to the key generated by json.Marshal
key := js.ValueOf(uuid)
// Use the key to get the existing Message
currentMsg, err := impl.Get(w.db, messageStoreName, key)
msgObj, err := impl.Get(w.db, messageStoreName, key)
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
"Unable to get message: %+v", err))
return
}
_, err = w.updateMessage(utils.JsToJson(currentMsg), messageID, timestamp,
currentMsg, err := valueToMessage(msgObj)
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
"Failed to marshal Message: %+v", err))
return
}
_, err = w.updateMessage(currentMsg, messageID, timestamp,
round, pinned, hidden, status)
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
@@ -296,13 +298,7 @@ func (w *wasmModel) UpdateFromMessageID(messageID message.ID,
status *channels.SentStatus) uint64 {
parentErr := errors.New("failed to UpdateFromMessageID")
// FIXME: this is a bit of race condition without the mux.
// This should be done via the transactions (i.e., make a
// special version of receiveHelper)
w.updateMux.Lock()
defer w.updateMux.Unlock()
currentMsgObj, err := impl.GetIndex(w.db, messageStoreName,
msgObj, err := impl.GetIndex(w.db, messageStoreName,
messageStoreMessageIndex, impl.EncodeBytes(messageID.Marshal()))
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
@@ -310,7 +306,13 @@ func (w *wasmModel) UpdateFromMessageID(messageID message.ID,
return 0
}
currentMsg := utils.JsToJson(currentMsgObj)
currentMsg, err := valueToMessage(msgObj)
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
"Failed to marshal Message: %+v", err))
return 0
}
uuid, err := w.updateMessage(currentMsg, &messageID, timestamp,
round, pinned, hidden, status)
if err != nil {
@@ -320,52 +322,6 @@ func (w *wasmModel) UpdateFromMessageID(messageID message.ID,
return uuid
}
// updateMessage is a helper for updating a stored message.
func (w *wasmModel) updateMessage(currentMsgJson string, messageID *message.ID,
timestamp *time.Time, round *rounds.Round, pinned, hidden *bool,
status *channels.SentStatus) (uint64, error) {
newMessage := &Message{}
err := json.Unmarshal([]byte(currentMsgJson), newMessage)
if err != nil {
return 0, err
}
if status != nil {
newMessage.Status = uint8(*status)
}
if messageID != nil {
newMessage.MessageID = messageID.Bytes()
}
if round != nil {
newMessage.Round = uint64(round.ID)
}
if timestamp != nil {
newMessage.Timestamp = *timestamp
}
if pinned != nil {
newMessage.Pinned = *pinned
}
if hidden != nil {
newMessage.Hidden = *hidden
}
// Store the updated Message
uuid, err := w.receiveHelper(newMessage, true)
if err != nil {
return 0, err
}
channelID := &id.ID{}
copy(channelID[:], newMessage.ChannelID)
go w.receivedMessageCB(uuid, channelID, true)
return uuid, nil
}
// buildMessage is a private helper that converts typical [channels.EventModel]
// inputs into a basic Message structure for insertion into storage.
//
@@ -397,11 +353,51 @@ func buildMessage(channelID, messageID, parentID []byte, nickname string,
}
}
// receiveHelper is a private helper for receiving any sort of message.
func (w *wasmModel) receiveHelper(
newMessage *Message, isUpdate bool) (uint64, error) {
// updateMessage is a helper for updating a stored message.
func (w *wasmModel) updateMessage(currentMsg *Message, messageID *message.ID,
timestamp *time.Time, round *rounds.Round, pinned, hidden *bool,
status *channels.SentStatus) (uint64, error) {
if status != nil {
currentMsg.Status = uint8(*status)
}
if messageID != nil {
currentMsg.MessageID = messageID.Bytes()
}
if round != nil {
currentMsg.Round = uint64(round.ID)
}
if timestamp != nil {
currentMsg.Timestamp = *timestamp
}
if pinned != nil {
currentMsg.Pinned = *pinned
}
if hidden != nil {
currentMsg.Hidden = *hidden
}
// Store the updated Message
uuid, err := w.upsertMessage(currentMsg)
if err != nil {
return 0, err
}
channelID := &id.ID{}
copy(channelID[:], currentMsg.ChannelID)
go w.receivedMessageCB(uuid, channelID, true)
return uuid, nil
}
// upsertMessage is a helper function that will update an existing record
// if Message.ID is specified. Otherwise, it will perform an insert.
func (w *wasmModel) upsertMessage(msg *Message) (uint64, error) {
// Convert to jsObject
newMessageJson, err := json.Marshal(newMessage)
newMessageJson, err := json.Marshal(msg)
if err != nil {
return 0, errors.Errorf("Unable to marshal Message: %+v", err)
}
@@ -410,43 +406,29 @@ func (w *wasmModel) receiveHelper(
return 0, errors.Errorf("Unable to marshal Message: %+v", err)
}
// Unset the primaryKey for inserts so that it can be auto-populated and
// incremented
if !isUpdate {
messageObj.Delete("id")
}
// Store message to database
result, err := impl.Put(w.db, messageStoreName, messageObj)
// FIXME: The following is almost certainly causing a bug
// where all of our upsert operations are failing.
if err != nil && !strings.Contains(err.Error(), impl.ErrUniqueConstraint) {
// Only return non-unique constraint errors so that the case
// below this one can be hit and handle duplicate entries properly.
msgIdObj, err := impl.Put(w.db, messageStoreName, messageObj)
if err != nil {
return 0, errors.Errorf("Unable to put Message: %+v", err)
}
// NOTE: Sometimes the insert fails to return an error but hits a duplicate
// insert, so this fallthrough returns the UUID entry in that case.
if result.IsUndefined() {
msgID := message.ID{}
copy(msgID[:], newMessage.MessageID)
msg, errLookup := w.msgIDLookup(msgID)
if errLookup == nil && msg.ID != 0 {
return msg.ID, nil
}
return 0, errors.Errorf("uuid lookup failure: %+v", err)
}
uuid := uint64(result.Int())
uuid := msgIdObj.Int()
jww.DEBUG.Printf("Successfully stored message %d", uuid)
return uuid, nil
return uint64(uuid), nil
}
// GetMessage returns the message with the given [channel.MessageID].
func (w *wasmModel) GetMessage(
messageID message.ID) (channels.ModelMessage, error) {
lookupResult, err := w.msgIDLookup(messageID)
msgIDStr := impl.EncodeBytes(messageID.Marshal())
resultObj, err := impl.GetIndex(w.db, messageStoreName,
messageStoreMessageIndex, msgIDStr)
if err != nil {
return channels.ModelMessage{}, err
}
lookupResult, err := valueToMessage(resultObj)
if err != nil {
return channels.ModelMessage{}, err
}
@@ -514,20 +496,10 @@ func (w *wasmModel) MuteUser(
go w.mutedUserCB(channelID, pubKey, unmute)
}
// msgIDLookup gets the UUID of the Message with the given messageID.
func (w *wasmModel) msgIDLookup(messageID message.ID) (*Message, error) {
msgIDStr := impl.EncodeBytes(messageID.Marshal())
resultObj, err := impl.GetIndex(w.db, messageStoreName,
messageStoreMessageIndex, msgIDStr)
if err != nil {
return nil, err
} else if resultObj.IsUndefined() {
return nil, errors.Errorf("no message for %s found", msgIDStr)
}
// Process result into string
// valueToMessage is a helper for converting js.Value to Message.
func valueToMessage(msgObj js.Value) (*Message, error) {
resultMsg := &Message{}
err = json.Unmarshal([]byte(utils.JsToJson(resultObj)), resultMsg)
err := json.Unmarshal([]byte(utils.JsToJson(msgObj)), resultMsg)
if err != nil {
return nil, err
}
Loading