github.com/status-im/status-go@v1.1.0/protocol/messenger_raw_message_resend.go (about)

     1  package protocol
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"time"
     8  
     9  	"github.com/status-im/status-go/protocol/protobuf"
    10  
    11  	"github.com/pkg/errors"
    12  	"go.uber.org/zap"
    13  
    14  	"github.com/status-im/status-go/protocol/common"
    15  )
    16  
    17  // watchExpiredMessages regularly checks for expired emojis and invoke their resending
    18  func (m *Messenger) watchExpiredMessages() {
    19  	m.logger.Debug("watching expired messages")
    20  	go func() {
    21  		for {
    22  			select {
    23  			case <-time.After(time.Second):
    24  				if m.Online() {
    25  					err := m.resendExpiredMessages()
    26  					if err != nil {
    27  						m.logger.Debug("failed to resend expired message", zap.Error(err))
    28  					}
    29  				}
    30  			case <-m.quit:
    31  				return
    32  			}
    33  		}
    34  	}()
    35  }
    36  
    37  func (m *Messenger) resendExpiredMessages() error {
    38  	if m.connectionState.Offline {
    39  		return errors.New("offline")
    40  	}
    41  
    42  	ids, err := m.persistence.ExpiredMessagesIDs(m.config.messageResendMaxCount)
    43  	if err != nil {
    44  		return errors.Wrapf(err, "Can't get expired reactions from db")
    45  	}
    46  
    47  	for _, id := range ids {
    48  		message, shouldResend, err := m.processMessageID(id)
    49  		if err != nil {
    50  			m.logger.Error("Error processing message ID when trying resend raw message", zap.String("id", id), zap.Error(err))
    51  		} else if shouldResend {
    52  			m.logger.Debug("Resent raw message",
    53  				zap.String("id", id),
    54  				zap.Any("message type", message.MessageType),
    55  				zap.Int("send count", message.SendCount),
    56  			)
    57  		}
    58  	}
    59  	return nil
    60  }
    61  
    62  func (m *Messenger) processMessageID(id string) (*common.RawMessage, bool, error) {
    63  	rawMessage, err := m.persistence.RawMessageByID(id)
    64  	if err != nil {
    65  		return nil, false, errors.Wrap(err, "Can't get raw message by ID")
    66  	}
    67  
    68  	shouldResend := m.shouldResendMessage(rawMessage, m.getTimesource())
    69  	if !shouldResend {
    70  		return rawMessage, false, nil
    71  	}
    72  
    73  	switch rawMessage.ResendMethod {
    74  	case common.ResendMethodSendCommunityMessage:
    75  		err = m.handleSendCommunityMessage(rawMessage)
    76  	case common.ResendMethodSendPrivate:
    77  		err = m.handleSendPrivateMessage(rawMessage)
    78  	case common.ResendMethodDynamic:
    79  		shouldResend, err = m.handleOtherResendMethods(rawMessage)
    80  	default:
    81  		err = errors.New("Unknown resend method")
    82  	}
    83  	return rawMessage, shouldResend, err
    84  }
    85  
    86  func (m *Messenger) handleSendCommunityMessage(rawMessage *common.RawMessage) error {
    87  	_, err := m.sender.SendCommunityMessage(context.TODO(), rawMessage)
    88  	if err != nil {
    89  		err = errors.Wrap(err, "Can't resend message with SendCommunityMessage")
    90  	}
    91  	m.upsertRawMessageToWatch(rawMessage)
    92  	return err
    93  }
    94  
    95  func (m *Messenger) handleSendPrivateMessage(rawMessage *common.RawMessage) error {
    96  	if len(rawMessage.Recipients) == 0 {
    97  		m.logger.Error("No recipients to resend message", zap.String("id", rawMessage.ID))
    98  		m.upsertRawMessageToWatch(rawMessage)
    99  		return errors.New("No recipients to resend message with SendPrivate")
   100  	}
   101  
   102  	var err error
   103  	for _, r := range rawMessage.Recipients {
   104  		_, err = m.sender.SendPrivate(context.TODO(), r, rawMessage)
   105  		if err != nil {
   106  			err = errors.Wrap(err, fmt.Sprintf("Can't resend message with SendPrivate to %s", common.PubkeyToHex(r)))
   107  		}
   108  	}
   109  
   110  	m.upsertRawMessageToWatch(rawMessage)
   111  	return err
   112  }
   113  
   114  func (m *Messenger) handleOtherResendMethods(rawMessage *common.RawMessage) (bool, error) {
   115  	chat, ok := m.allChats.Load(rawMessage.LocalChatID)
   116  	if !ok {
   117  		m.logger.Error("Can't find chat with id", zap.String("id", rawMessage.LocalChatID))
   118  		return false, nil // Continue with next message if chat not found
   119  	}
   120  
   121  	if !(chat.Public() || chat.CommunityChat()) {
   122  		return false, nil // Only resend for public or community chats
   123  	}
   124  
   125  	if ok {
   126  		err := m.persistence.SaveRawMessage(rawMessage)
   127  		if err != nil {
   128  			m.logger.Error("Can't save raw message marked as expired", zap.Error(err))
   129  			return true, err
   130  		}
   131  	}
   132  	return true, m.reSendRawMessage(context.Background(), rawMessage.ID)
   133  }
   134  
   135  func (m *Messenger) shouldResendMessage(message *common.RawMessage, t common.TimeSource) bool {
   136  	if m.featureFlags.ResendRawMessagesDisabled {
   137  		return false
   138  	}
   139  	//exponential backoff depends on how many attempts to send message already made
   140  	power := math.Pow(2, float64(message.SendCount-1))
   141  	backoff := uint64(power) * uint64(m.config.messageResendMinDelay.Milliseconds())
   142  	backoffElapsed := t.GetCurrentTime() > (message.LastSent + backoff)
   143  
   144  	return backoffElapsed
   145  }
   146  
   147  // pull a message from the database and send it again
   148  func (m *Messenger) reSendRawMessage(ctx context.Context, messageID string) error {
   149  	message, err := m.persistence.RawMessageByID(messageID)
   150  	if err != nil {
   151  		return err
   152  	}
   153  
   154  	chat, ok := m.allChats.Load(message.LocalChatID)
   155  	if !ok {
   156  		return errors.New("chat not found")
   157  	}
   158  
   159  	_, err = m.dispatchMessage(ctx, common.RawMessage{
   160  		LocalChatID: chat.ID,
   161  		Payload:     message.Payload,
   162  		PubsubTopic: message.PubsubTopic,
   163  		MessageType: message.MessageType,
   164  		Recipients:  message.Recipients,
   165  		ResendType:  message.ResendType,
   166  		SendCount:   message.SendCount,
   167  	})
   168  	return err
   169  }
   170  
   171  // UpsertRawMessageToWatch insert/update the rawMessage to the database, resend it if necessary.
   172  // relate watch method: Messenger#watchExpiredMessages
   173  func (m *Messenger) UpsertRawMessageToWatch(rawMessage *common.RawMessage) (*common.RawMessage, error) {
   174  	rawMessage.SendCount++
   175  	rawMessage.LastSent = m.getTimesource().GetCurrentTime()
   176  	err := m.persistence.SaveRawMessage(rawMessage)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  	return rawMessage, nil
   181  }
   182  
   183  // AddRawMessageToWatch check if RawMessage is correct and insert the rawMessage to the database
   184  // relate watch method: Messenger#watchExpiredMessages
   185  func (m *Messenger) AddRawMessageToWatch(rawMessage *common.RawMessage) (*common.RawMessage, error) {
   186  	if err := m.sender.ValidateRawMessage(rawMessage); err != nil {
   187  		m.logger.Error("Can't add raw message to watch", zap.String("messageID", rawMessage.ID), zap.Error(err))
   188  		return nil, err
   189  	}
   190  
   191  	return m.UpsertRawMessageToWatch(rawMessage)
   192  }
   193  
   194  func (m *Messenger) upsertRawMessageToWatch(rawMessage *common.RawMessage) {
   195  	_, err := m.UpsertRawMessageToWatch(rawMessage)
   196  	if err != nil {
   197  		// this is unlikely to happen, but we should log it
   198  		m.logger.Error("Can't upsert raw message after SendCommunityMessage", zap.Error(err), zap.String("id", rawMessage.ID))
   199  	}
   200  }
   201  
   202  func (m *Messenger) RawMessagesIDsByType(t protobuf.ApplicationMetadataMessage_Type) ([]string, error) {
   203  	return m.persistence.RawMessagesIDsByType(t)
   204  }
   205  
   206  func (m *Messenger) RawMessageByID(id string) (*common.RawMessage, error) {
   207  	return m.persistence.RawMessageByID(id)
   208  }
   209  
   210  func (m *Messenger) UpdateRawMessageSent(id string, sent bool) error {
   211  	return m.persistence.UpdateRawMessageSent(id, sent)
   212  }
   213  
   214  func (m *Messenger) UpdateRawMessageLastSent(id string, lastSent uint64) error {
   215  	return m.persistence.UpdateRawMessageLastSent(id, lastSent)
   216  }