Handle async raw message confirmations

Sometimes confirmation for raw messages are received before the record
is actually saved in the database.

In this case, the code will preserve the Sent status.
This commit is contained in:
Andrea Maria Piana 2023-06-19 14:10:21 +01:00
parent 83238283b4
commit 14e3eafaeb
3 changed files with 75 additions and 3 deletions

View File

@ -32,6 +32,19 @@ func NewRawMessagesPersistence(db *sql.DB) *RawMessagesPersistence {
}
func (db RawMessagesPersistence) SaveRawMessage(message *RawMessage) error {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
var pubKeys [][]byte
for _, pk := range message.Recipients {
pubKeys = append(pubKeys, crypto.CompressPubkey(pk))
@ -44,7 +57,19 @@ func (db RawMessagesPersistence) SaveRawMessage(message *RawMessage) error {
return err
}
_, err := db.db.Exec(`
// If the message is not sent, we check whether there's a record
// in the database already and preserve the state
if !message.Sent {
oldMessage, err := db.rawMessageByID(tx, message.ID)
if err != nil && err != sql.ErrNoRows {
return err
}
if oldMessage != nil {
message.Sent = oldMessage.Sent
}
}
_, err = tx.Exec(`
INSERT INTO
raw_messages
(
@ -80,13 +105,30 @@ func (db RawMessagesPersistence) SaveRawMessage(message *RawMessage) error {
}
func (db RawMessagesPersistence) RawMessageByID(id string) (*RawMessage, error) {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return nil, err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
return db.rawMessageByID(tx, id)
}
func (db RawMessagesPersistence) rawMessageByID(tx *sql.Tx, id string) (*RawMessage, error) {
var rawPubKeys [][]byte
var encodedRecipients []byte
var skipGroupMessageWrap sql.NullBool
var sendOnPersonalTopic sql.NullBool
message := &RawMessage{}
err := db.db.QueryRow(`
err := tx.QueryRow(`
SELECT
id,
local_chat_id,

View File

@ -574,7 +574,14 @@ func (m *Messenger) processSentMessages(ids []string) error {
for _, id := range ids {
rawMessage, err := m.persistence.RawMessageByID(id)
if err != nil {
// If we have no raw message, we create a temporary one, so that
// the sent status is preserved
if err == sql.ErrNoRows || rawMessage == nil {
rawMessage = &common.RawMessage{
ID: id,
MessageType: protobuf.ApplicationMetadataMessage_CHAT_MESSAGE,
}
} else if err != nil {
return errors.Wrapf(err, "Can't get raw message with id %v", id)
}

View File

@ -766,6 +766,29 @@ func TestExpiredMessagesIDs(t *testing.T) {
require.Equal(t, 1, len(ids))
}
func TestDontOverwriteSentStatus(t *testing.T) {
db, err := openTestDB()
require.NoError(t, err)
p := newSQLitePersistence(db)
//save rawMessage
rawMessage := minimalRawMessage("chat-message-id", protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
rawMessage.Sent = true
err = p.SaveRawMessage(rawMessage)
require.NoError(t, err)
rawMessage.Sent = false
rawMessage.ResendAutomatically = true
err = p.SaveRawMessage(rawMessage)
require.NoError(t, err)
m, err := p.RawMessageByID(rawMessage.ID)
require.NoError(t, err)
require.True(t, m.Sent)
require.True(t, m.ResendAutomatically)
}
func TestPersistenceEmojiReactions(t *testing.T) {
db, err := openTestDB()
require.NoError(t, err)