add PinMessage and PinnedMessage (#2180)
* add PinMessage and PinnedMessage * fix gruop pin messages * add SkipGroupMessageWrap to pin messages * update pinMessage ID generation to be symmetric
This commit is contained in:
parent
6a930ed0c6
commit
e9a42bfa2b
|
@ -0,0 +1,60 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
type PinMessage struct {
|
||||
protobuf.PinMessage
|
||||
|
||||
// ID calculated as keccak256(compressedAuthorPubKey, data) where data is unencrypted payload.
|
||||
ID string `json:"id"`
|
||||
// MessageID string `json:"messageID"`
|
||||
// WhisperTimestamp is a timestamp of a Whisper envelope.
|
||||
WhisperTimestamp uint64 `json:"whisperTimestamp"`
|
||||
// From is a public key of the user who pinned the message.
|
||||
From string `json:"from"`
|
||||
// The chat id to be stored locally
|
||||
LocalChatID string `json:"localChatId"`
|
||||
SigPubKey *ecdsa.PublicKey `json:"-"`
|
||||
// Identicon of the author
|
||||
Identicon string `json:"identicon"`
|
||||
// Random 3 words name
|
||||
Alias string `json:"alias"`
|
||||
}
|
||||
|
||||
type PinnedMessage struct {
|
||||
Message
|
||||
PinnedAt uint64 `json:"pinnedAt"`
|
||||
}
|
||||
|
||||
// WrapGroupMessage indicates whether we should wrap this in membership information
|
||||
func (m *PinMessage) WrapGroupMessage() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetMessageType a setter for the MessageType field
|
||||
// this function is required to implement the ChatEntity interface
|
||||
func (m *PinMessage) SetMessageType(messageType protobuf.MessageType) {
|
||||
m.MessageType = messageType
|
||||
}
|
||||
|
||||
func (m *PinMessage) GetGrant() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetProtoBuf returns the struct's embedded protobuf struct
|
||||
// this function is required to implement the ChatEntity interface
|
||||
func (m *PinMessage) GetProtobuf() proto.Message {
|
||||
return &m.PinMessage
|
||||
}
|
||||
|
||||
// GetSigPubKey returns an ecdsa encoded public key
|
||||
// this function is required to implement the ChatEntity interface
|
||||
func (m PinMessage) GetSigPubKey() *ecdsa.PublicKey {
|
||||
return m.SigPubKey
|
||||
}
|
|
@ -38,3 +38,29 @@ func extendMessageFromChat(message *common.Message, chat *Chat, key *ecdsa.Publi
|
|||
return nil
|
||||
|
||||
}
|
||||
|
||||
func extendPinMessageFromChat(message *common.PinMessage, chat *Chat, key *ecdsa.PublicKey, timesource common.TimeSource) error {
|
||||
clock, timestamp := chat.NextClockAndTimestamp(timesource)
|
||||
|
||||
message.LocalChatID = chat.ID
|
||||
message.Clock = clock
|
||||
message.From = types.EncodeHex(crypto.FromECDSAPub(key))
|
||||
message.SigPubKey = key
|
||||
message.WhisperTimestamp = timestamp
|
||||
|
||||
identicon, err := identicon.GenerateBase64(message.From)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
message.Identicon = identicon
|
||||
|
||||
alias, err := alias.GenerateFromPublicKeyString(message.From)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
message.Alias = alias
|
||||
return nil
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/status-go/protocol/transport"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/images"
|
||||
|
@ -18,9 +18,9 @@ import (
|
|||
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
||||
"github.com/status-im/status-go/protocol/ens"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
v1protocol "github.com/status-im/status-go/protocol/v1"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"github.com/status-im/status-go/protocol/transport"
|
||||
v1protocol "github.com/status-im/status-go/protocol/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -324,6 +324,59 @@ func (m *MessageHandler) HandleSyncInstallationPublicChat(state *ReceivedMessage
|
|||
return true
|
||||
}
|
||||
|
||||
func (m *MessageHandler) HandlePinMessage(state *ReceivedMessageState, message protobuf.PinMessage) error {
|
||||
logger := m.logger.With(zap.String("site", "HandlePinMessage"))
|
||||
|
||||
logger.Info("Handling pin message")
|
||||
|
||||
pinMessage := &common.PinMessage{
|
||||
PinMessage: message,
|
||||
// MessageID: message.MessageId,
|
||||
WhisperTimestamp: state.CurrentMessageState.WhisperTimestamp,
|
||||
From: state.CurrentMessageState.Contact.ID,
|
||||
SigPubKey: state.CurrentMessageState.PublicKey,
|
||||
Identicon: state.CurrentMessageState.Contact.Identicon,
|
||||
Alias: state.CurrentMessageState.Contact.Alias,
|
||||
}
|
||||
|
||||
chat, err := m.matchChatEntity(pinMessage, state.AllChats, state.AllContacts, state.Timesource)
|
||||
if err != nil {
|
||||
return err // matchChatEntity returns a descriptive error message
|
||||
}
|
||||
|
||||
pinMessage.ID, err = generatePinMessageID(&m.identity.PublicKey, pinMessage, chat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If deleted-at is greater, ignore message
|
||||
if chat.DeletedAtClockValue >= pinMessage.Clock {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the LocalChatID for the message
|
||||
pinMessage.LocalChatID = chat.ID
|
||||
|
||||
if c, ok := state.AllChats.Load(chat.ID); ok {
|
||||
chat = c
|
||||
}
|
||||
|
||||
// Set the LocalChatID for the message
|
||||
pinMessage.LocalChatID = chat.ID
|
||||
|
||||
if chat.LastClockValue < message.Clock {
|
||||
chat.LastClockValue = message.Clock
|
||||
}
|
||||
|
||||
state.Response.AddPinMessage(pinMessage)
|
||||
|
||||
// Set in the modified maps chat
|
||||
state.Response.AddChat(chat)
|
||||
state.AllChats.Store(chat.ID, chat)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MessageHandler) HandleContactUpdate(state *ReceivedMessageState, message protobuf.ContactUpdate) error {
|
||||
logger := m.logger.With(zap.String("site", "HandleContactUpdate"))
|
||||
contact := state.CurrentMessageState.Contact
|
||||
|
|
|
@ -543,6 +543,91 @@ func (db sqlitePersistence) MessageByChatID(chatID string, currCursor string, li
|
|||
return result, newCursor, nil
|
||||
}
|
||||
|
||||
// PinnedMessageByChatID returns all pinned messages for a given chatID in descending order.
|
||||
// Ordering is accomplished using two concatenated values: ClockValue and ID.
|
||||
// These two values are also used to compose a cursor which is returned to the result.
|
||||
func (db sqlitePersistence) PinnedMessageByChatIDs(chatIDs []string, currCursor string, limit int) ([]*common.PinnedMessage, string, error) {
|
||||
cursorWhere := ""
|
||||
if currCursor != "" {
|
||||
cursorWhere = "AND cursor <= ?" //nolint: goconst
|
||||
}
|
||||
allFields := db.tableUserMessagesAllFieldsJoin()
|
||||
args := make([]interface{}, len(chatIDs))
|
||||
for i, v := range chatIDs {
|
||||
args[i] = v
|
||||
}
|
||||
if currCursor != "" {
|
||||
args = append(args, currCursor)
|
||||
}
|
||||
// Build a new column `cursor` at the query time by having a fixed-sized clock value at the beginning
|
||||
// concatenated with message ID. Results are sorted using this new column.
|
||||
// This new column values can also be returned as a cursor for subsequent requests.
|
||||
rows, err := db.db.Query(
|
||||
fmt.Sprintf(`
|
||||
SELECT
|
||||
%s,
|
||||
pm.clock_value as pinnedAt,
|
||||
substr('0000000000000000000000000000000000000000000000000000000000000000' || m1.clock_value, -64, 64) || m1.id as cursor
|
||||
FROM
|
||||
pin_messages pm
|
||||
JOIN
|
||||
user_messages m1
|
||||
ON
|
||||
pm.message_id = m1.id
|
||||
LEFT JOIN
|
||||
user_messages m2
|
||||
ON
|
||||
m1.response_to = m2.id
|
||||
LEFT JOIN
|
||||
contacts c
|
||||
ON
|
||||
m1.source = c.id
|
||||
WHERE
|
||||
pm.pinned = 1
|
||||
AND NOT(m1.hide) AND m1.local_chat_id IN %s %s
|
||||
ORDER BY cursor DESC
|
||||
LIMIT ?
|
||||
`, allFields, "(?"+strings.Repeat(",?", len(chatIDs)-1)+")", cursorWhere),
|
||||
append(args, limit+1)..., // take one more to figure our whether a cursor should be returned
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var (
|
||||
result []*common.PinnedMessage
|
||||
cursors []string
|
||||
)
|
||||
for rows.Next() {
|
||||
var (
|
||||
message common.Message
|
||||
pinnedAt uint64
|
||||
cursor string
|
||||
)
|
||||
if err := db.tableUserMessagesScanAllFields(rows, &message, &pinnedAt, &cursor); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
pinnedMessage := &common.PinnedMessage{
|
||||
Message: message,
|
||||
PinnedAt: pinnedAt,
|
||||
}
|
||||
result = append(result, pinnedMessage)
|
||||
cursors = append(cursors, cursor)
|
||||
}
|
||||
|
||||
var newCursor string
|
||||
if len(result) > limit && cursors != nil {
|
||||
newCursor = cursors[limit]
|
||||
result = result[:limit]
|
||||
}
|
||||
return result, newCursor, nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) PinnedMessageByChatID(chatID string, currCursor string, limit int) ([]*common.PinnedMessage, string, error) {
|
||||
return db.PinnedMessageByChatIDs([]string{chatID}, currCursor, limit)
|
||||
}
|
||||
|
||||
// MessageByChatIDs returns all messages for a given chatIDs in descending order.
|
||||
// Ordering is accomplished using two concatenated values: ClockValue and ID.
|
||||
// These two values are also used to compose a cursor which is returned to the result.
|
||||
|
@ -807,6 +892,76 @@ func (db sqlitePersistence) SaveMessages(messages []*common.Message) (err error)
|
|||
return
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) SavePinMessages(messages []*common.PinMessage) (err error) {
|
||||
tx, err := db.db.BeginTx(context.Background(), nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
// don't shadow original error
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// select
|
||||
selectQuery := "SELECT clock_value FROM pin_messages WHERE id = ?"
|
||||
|
||||
// insert
|
||||
allInsertFields := `id, message_id, whisper_timestamp, chat_id, local_chat_id, clock_value, pinned`
|
||||
insertValues := strings.Repeat("?, ", strings.Count(allInsertFields, ",")) + "?"
|
||||
insertQuery := "INSERT INTO pin_messages(" + allInsertFields + ") VALUES (" + insertValues + ")" // nolint: gosec
|
||||
insertStmt, err := tx.Prepare(insertQuery)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// update
|
||||
updateQuery := "UPDATE pin_messages SET pinned = ?, clock_value = ? WHERE id = ?"
|
||||
updateStmt, err := tx.Prepare(updateQuery)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, message := range messages {
|
||||
row := tx.QueryRow(selectQuery, message.ID)
|
||||
var existingClock uint64
|
||||
switch err = row.Scan(&existingClock); err {
|
||||
case sql.ErrNoRows:
|
||||
// not found, insert new record
|
||||
allValues := []interface{}{
|
||||
message.ID,
|
||||
message.MessageId,
|
||||
message.WhisperTimestamp,
|
||||
message.ChatId,
|
||||
message.LocalChatID,
|
||||
message.Clock,
|
||||
message.Pinned,
|
||||
}
|
||||
_, err = insertStmt.Exec(allValues...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case nil:
|
||||
// found, update if current message is more recent, otherwise skip
|
||||
if existingClock < message.Clock {
|
||||
// update
|
||||
_, err = updateStmt.Exec(message.Pinned, message.Clock, message.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) DeleteMessage(id string) error {
|
||||
_, err := db.db.Exec(`DELETE FROM user_messages WHERE id = ?`, id)
|
||||
return err
|
||||
|
@ -838,6 +993,12 @@ func (db sqlitePersistence) deleteMessagesByChatID(id string, tx *sql.Tx) (err e
|
|||
}
|
||||
|
||||
_, err = tx.Exec(`DELETE FROM user_messages WHERE local_chat_id = ?`, id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = tx.Exec(`DELETE FROM pin_messages WHERE local_chat_id = ?`, id)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -2539,6 +2539,15 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
|||
continue
|
||||
}
|
||||
|
||||
case protobuf.PinMessage:
|
||||
pinMessage := msg.ParsedMessage.Interface().(protobuf.PinMessage)
|
||||
err = m.handler.HandlePinMessage(messageState, pinMessage)
|
||||
if err != nil {
|
||||
logger.Warn("failed to handle PinMessage", zap.Error(err))
|
||||
allMessagesProcessed = false
|
||||
continue
|
||||
}
|
||||
|
||||
case protobuf.PairInstallation:
|
||||
if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
|
||||
logger.Warn("not coming from us, ignoring")
|
||||
|
@ -2939,6 +2948,12 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(messageState.Response.pinMessages) > 0 {
|
||||
err = m.SavePinMessages(messageState.Response.PinMessages())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, emojiReaction := range messageState.EmojiReactions {
|
||||
messageState.Response.EmojiReactions = append(messageState.Response.EmojiReactions, emojiReaction)
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"go.uber.org/zap"
|
||||
|
||||
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/tt"
|
||||
"github.com/status-im/status-go/waku"
|
||||
)
|
||||
|
||||
func TestMessengerPinMessageSuite(t *testing.T) {
|
||||
suite.Run(t, new(MessengerPinMessageSuite))
|
||||
}
|
||||
|
||||
type MessengerPinMessageSuite struct {
|
||||
suite.Suite
|
||||
m *Messenger // main instance of Messenger
|
||||
privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger
|
||||
// If one wants to send messages between different instances of Messenger,
|
||||
// a single waku service should be shared.
|
||||
shh types.Waku
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func (s *MessengerPinMessageSuite) SetupTest() {
|
||||
s.logger = tt.MustCreateTestLogger()
|
||||
|
||||
config := waku.DefaultConfig
|
||||
config.MinimumAcceptedPoW = 0
|
||||
shh := waku.New(&config, s.logger)
|
||||
s.shh = gethbridge.NewGethWakuWrapper(shh)
|
||||
s.Require().NoError(shh.Start(nil))
|
||||
|
||||
s.m = s.newMessenger()
|
||||
s.privateKey = s.m.identity
|
||||
_, err := s.m.Start()
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *MessengerPinMessageSuite) TearDownTest() {
|
||||
s.Require().NoError(s.m.Shutdown())
|
||||
}
|
||||
|
||||
func (s *MessengerPinMessageSuite) newMessenger() *Messenger {
|
||||
privateKey, err := crypto.GenerateKey()
|
||||
s.Require().NoError(err)
|
||||
|
||||
messenger, err := newMessengerWithKey(s.shh, privateKey, s.logger, nil)
|
||||
s.Require().NoError(err)
|
||||
return messenger
|
||||
}
|
||||
|
||||
func (s *MessengerPinMessageSuite) TestPinMessage() {
|
||||
theirMessenger := s.newMessenger()
|
||||
_, err := theirMessenger.Start()
|
||||
s.Require().NoError(err)
|
||||
|
||||
theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport)
|
||||
err = theirMessenger.SaveChat(theirChat)
|
||||
s.Require().NoError(err)
|
||||
|
||||
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
|
||||
err = s.m.SaveChat(ourChat)
|
||||
s.Require().NoError(err)
|
||||
|
||||
inputMessage := buildTestMessage(*theirChat)
|
||||
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
||||
s.NoError(err)
|
||||
s.Require().Len(sendResponse.Messages, 1)
|
||||
|
||||
response, err := WaitOnMessengerResponse(
|
||||
s.m,
|
||||
func(r *MessengerResponse) bool { return len(r.Messages) > 0 },
|
||||
"no messages",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.Chats(), 1)
|
||||
|
||||
pinMessage := &common.PinMessage{
|
||||
LocalChatID: theirChat.ID,
|
||||
}
|
||||
pinMessage.MessageId = inputMessage.ID
|
||||
pinMessage.Pinned = true
|
||||
pinMessage.ChatId = theirChat.ID
|
||||
sendResponse, err = theirMessenger.SendPinMessage(context.Background(), pinMessage)
|
||||
s.NoError(err)
|
||||
s.Require().Len(sendResponse.PinMessages(), 1)
|
||||
|
||||
// Wait for the message to reach its destination
|
||||
response, err = WaitOnMessengerResponse(
|
||||
s.m,
|
||||
func(r *MessengerResponse) bool {
|
||||
return len(r.PinMessages()) > 0
|
||||
},
|
||||
"pin message not received",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
receivedPinMessage := response.PinMessages()[0]
|
||||
s.Require().True(receivedPinMessage.Pinned)
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
// SendPinMessage sends the PinMessage to the corresponding chat
|
||||
func (m *Messenger) SendPinMessage(ctx context.Context, message *common.PinMessage) (*MessengerResponse, error) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
return m.sendPinMessage(ctx, message)
|
||||
}
|
||||
|
||||
func (m *Messenger) sendPinMessage(ctx context.Context, message *common.PinMessage) (*MessengerResponse, error) {
|
||||
var response MessengerResponse
|
||||
|
||||
// A valid added chat is required.
|
||||
chat, ok := m.allChats.Load(message.ChatId)
|
||||
if !ok {
|
||||
return nil, errors.New("chat not found")
|
||||
}
|
||||
|
||||
err := m.handleStandaloneChatIdentity(chat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = extendPinMessageFromChat(message, chat, &m.identity.PublicKey, m.getTimesource())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
message.ID, err = generatePinMessageID(&m.identity.PublicKey, message, chat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encodedMessage, err := m.encodeChatEntity(chat, message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawMessage := common.RawMessage{
|
||||
LocalChatID: chat.ID,
|
||||
Payload: encodedMessage,
|
||||
MessageType: protobuf.ApplicationMetadataMessage_PIN_MESSAGE,
|
||||
SkipGroupMessageWrap: true,
|
||||
ResendAutomatically: true,
|
||||
}
|
||||
_, err = m.dispatchMessage(ctx, rawMessage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = m.persistence.SavePinMessages([]*common.PinMessage{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response.AddPinMessage(message)
|
||||
response.AddChat(chat)
|
||||
return &response, m.saveChat(chat)
|
||||
}
|
||||
|
||||
func (m *Messenger) PinnedMessageByChatID(chatID, cursor string, limit int) ([]*common.PinnedMessage, string, error) {
|
||||
chat, err := m.persistence.Chat(chatID)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if chat.Timeline() {
|
||||
var chatIDs = []string{"@" + contactIDFromPublicKey(&m.identity.PublicKey)}
|
||||
contacts, err := m.persistence.Contacts()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
for _, contact := range contacts {
|
||||
if contact.IsAdded() {
|
||||
chatIDs = append(chatIDs, "@"+contact.ID)
|
||||
}
|
||||
}
|
||||
return m.persistence.PinnedMessageByChatIDs(chatIDs, cursor, limit)
|
||||
}
|
||||
return m.persistence.PinnedMessageByChatID(chatID, cursor, limit)
|
||||
}
|
||||
|
||||
func (m *Messenger) SavePinMessages(messages []*common.PinMessage) error {
|
||||
return m.persistence.SavePinMessages(messages)
|
||||
}
|
||||
|
||||
func generatePinMessageID(pubKey *ecdsa.PublicKey, pm *common.PinMessage, chat *Chat) (string, error) {
|
||||
data := gethcommon.FromHex(pm.MessageId)
|
||||
|
||||
switch {
|
||||
case chat.ChatType == ChatTypeOneToOne:
|
||||
ourPubKey := crypto.FromECDSAPub(pubKey)
|
||||
tmpPubKey, err := chat.PublicKey()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
theirPubKey := crypto.FromECDSAPub(tmpPubKey)
|
||||
|
||||
if bytes.Compare(ourPubKey, theirPubKey) < 0 {
|
||||
data = append(data, ourPubKey...) // our key
|
||||
data = append(data, theirPubKey...) // their key
|
||||
} else {
|
||||
data = append(data, theirPubKey...) // their key
|
||||
data = append(data, ourPubKey...) // our key
|
||||
}
|
||||
default:
|
||||
data = append(data, []byte(chat.ID)...)
|
||||
}
|
||||
id := sha256.Sum256(data)
|
||||
idString := fmt.Sprintf("%x", id)
|
||||
|
||||
return idString, nil
|
||||
}
|
|
@ -32,6 +32,7 @@ type MessengerResponse struct {
|
|||
removedChats map[string]bool
|
||||
communities map[string]*communities.Community
|
||||
activityCenterNotifications map[string]*ActivityCenterNotification
|
||||
pinMessages map[string]*common.PinMessage
|
||||
}
|
||||
|
||||
func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
|
||||
|
@ -39,6 +40,7 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
|
|||
Chats []*Chat `json:"chats,omitempty"`
|
||||
RemovedChats []string `json:"removedChats,omitempty"`
|
||||
Messages []*common.Message `json:"messages,omitempty"`
|
||||
PinMessages []*common.PinMessage `json:"pinMessages,omitempty"`
|
||||
Contacts []*Contact `json:"contacts,omitempty"`
|
||||
Installations []*multidevice.Installation `json:"installations,omitempty"`
|
||||
EmojiReactions []*EmojiReaction `json:"emojiReactions,omitempty"`
|
||||
|
@ -75,6 +77,7 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
|
|||
responseItem.Communities = r.Communities()
|
||||
responseItem.RemovedChats = r.RemovedChats()
|
||||
responseItem.ActivityCenterNotifications = r.ActivityCenterNotifications()
|
||||
responseItem.PinMessages = r.PinMessages()
|
||||
|
||||
return json.Marshal(responseItem)
|
||||
}
|
||||
|
@ -111,9 +114,18 @@ func (r *MessengerResponse) Notifications() []*localnotifications.Notification {
|
|||
return notifications
|
||||
}
|
||||
|
||||
func (r *MessengerResponse) PinMessages() []*common.PinMessage {
|
||||
var pinMessages []*common.PinMessage
|
||||
for _, pm := range r.pinMessages {
|
||||
pinMessages = append(pinMessages, pm)
|
||||
}
|
||||
return pinMessages
|
||||
}
|
||||
|
||||
func (r *MessengerResponse) IsEmpty() bool {
|
||||
return len(r.chats)+
|
||||
len(r.Messages)+
|
||||
len(r.pinMessages)+
|
||||
len(r.Contacts)+
|
||||
len(r.Installations)+
|
||||
len(r.Invitations)+
|
||||
|
@ -154,6 +166,7 @@ func (r *MessengerResponse) Merge(response *MessengerResponse) error {
|
|||
r.overrideFilters(response.Filters)
|
||||
r.overrideRemovedFilters(response.Filters)
|
||||
r.AddCommunities(response.Communities())
|
||||
r.AddPinMessages(response.PinMessages())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -287,3 +300,17 @@ func (r *MessengerResponse) ActivityCenterNotifications() []*ActivityCenterNotif
|
|||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
func (r *MessengerResponse) AddPinMessage(pm *common.PinMessage) {
|
||||
if r.pinMessages == nil {
|
||||
r.pinMessages = make(map[string]*common.PinMessage)
|
||||
}
|
||||
|
||||
r.pinMessages[pm.ID] = pm
|
||||
}
|
||||
|
||||
func (r *MessengerResponse) AddPinMessages(pms []*common.PinMessage) {
|
||||
for _, pm := range pms {
|
||||
r.AddPinMessage(pm)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +1,40 @@
|
|||
// Code generated by go-bindata. DO NOT EDIT.
|
||||
// Code generated for package migrations by go-bindata DO NOT EDIT. (@generated)
|
||||
// sources:
|
||||
// 000001_init.down.db.sql (65B)
|
||||
// 000001_init.up.db.sql (2.719kB)
|
||||
// 000002_add_last_ens_clock_value.up.sql (77B)
|
||||
// 1586358095_add_replace.up.sql (224B)
|
||||
// 1588665364_add_image_data.up.sql (186B)
|
||||
// 1589365189_add_pow_target.up.sql (66B)
|
||||
// 1591277220_add_index_messages.up.sql (240B)
|
||||
// 1593087212_add_mute_chat_and_raw_message_fields.up.sql (215B)
|
||||
// 1595862781_add_audio_data.up.sql (246B)
|
||||
// 1595865249_create_emoji_reactions_table.up.sql (300B)
|
||||
// 1596805115_create_group_chat_invitations_table.up.sql (231B)
|
||||
// 1597322655_add_invitation_admin_chat_field.up.sql (54B)
|
||||
// 1597757544_add_nickname.up.sql (52B)
|
||||
// 1598955122_add_mentions.up.sql (52B)
|
||||
// 1599641390_add_emoji_reactions_index.up.sql (126B)
|
||||
// 1599720851_add_seen_index_remove_long_messages.up.sql (150B)
|
||||
// 1603198582_add_profile_chat_field.up.sql (45B)
|
||||
// 1603816533_add_links.up.sql (48B)
|
||||
// 1603888149_create_chat_identity_last_published_table.up.sql (407B)
|
||||
// 1605075346_add_communities.up.sql (6.971kB)
|
||||
// 1610117927_add_message_cache.up.sql (142B)
|
||||
// 1610959908_add_dont_wrap_to_raw_messages.up.sql (83B)
|
||||
// 1610960912_add_send_on_personal_topic.up.sql (82B)
|
||||
// 1612870480_add_datasync_id.up.sql (111B)
|
||||
// 1614152139_add_communities_request_to_join.up.sql (831B)
|
||||
// 1615374373_add_confirmations.up.sql (227B)
|
||||
// 1617694931_add_notification_center.up.sql (572B)
|
||||
// README.md (554B)
|
||||
// doc.go (850B)
|
||||
|
||||
// 000001_init.down.db.sql
|
||||
// 000001_init.up.db.sql
|
||||
// 000002_add_last_ens_clock_value.up.sql
|
||||
// 1586358095_add_replace.up.sql
|
||||
// 1588665364_add_image_data.up.sql
|
||||
// 1589365189_add_pow_target.up.sql
|
||||
// 1591277220_add_index_messages.up.sql
|
||||
// 1593087212_add_mute_chat_and_raw_message_fields.up.sql
|
||||
// 1595862781_add_audio_data.up.sql
|
||||
// 1595865249_create_emoji_reactions_table.up.sql
|
||||
// 1596805115_create_group_chat_invitations_table.up.sql
|
||||
// 1597322655_add_invitation_admin_chat_field.up.sql
|
||||
// 1597757544_add_nickname.up.sql
|
||||
// 1598955122_add_mentions.up.sql
|
||||
// 1599641390_add_emoji_reactions_index.up.sql
|
||||
// 1599720851_add_seen_index_remove_long_messages.up.sql
|
||||
// 1603198582_add_profile_chat_field.up.sql
|
||||
// 1603816533_add_links.up.sql
|
||||
// 1603888149_create_chat_identity_last_published_table.up.sql
|
||||
// 1605075346_add_communities.up.sql
|
||||
// 1610117927_add_message_cache.up.sql
|
||||
// 1610959908_add_dont_wrap_to_raw_messages.up.sql
|
||||
// 1610960912_add_send_on_personal_topic.up.sql
|
||||
// 1612870480_add_datasync_id.up.sql
|
||||
// 1614152139_add_communities_request_to_join.up.sql
|
||||
// 1615374373_add_confirmations.up.sql
|
||||
// 1617694931_add_notification_center.up.sql
|
||||
// 1618923660_create_pin_messages.up.sql
|
||||
// README.md
|
||||
// doc.go
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -48,7 +47,7 @@ import (
|
|||
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read %q: %v", name, err)
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
@ -56,7 +55,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
|
|||
clErr := gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read %q: %v", name, err)
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
if clErr != nil {
|
||||
return nil, err
|
||||
|
@ -66,9 +65,8 @@ func bindataRead(data []byte, name string) ([]byte, error) {
|
|||
}
|
||||
|
||||
type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
digest [sha256.Size]byte
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
}
|
||||
|
||||
type bindataFileInfo struct {
|
||||
|
@ -78,21 +76,32 @@ type bindataFileInfo struct {
|
|||
modTime time.Time
|
||||
}
|
||||
|
||||
// Name return file name
|
||||
func (fi bindataFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
|
||||
// Size return file size
|
||||
func (fi bindataFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
|
||||
// Mode return file mode
|
||||
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
|
||||
// Mode return file modify time
|
||||
func (fi bindataFileInfo) ModTime() time.Time {
|
||||
return fi.modTime
|
||||
}
|
||||
|
||||
// IsDir return file whether a directory
|
||||
func (fi bindataFileInfo) IsDir() bool {
|
||||
return false
|
||||
return fi.mode&os.ModeDir != 0
|
||||
}
|
||||
|
||||
// Sys return file is sys mode
|
||||
func (fi bindataFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
@ -112,8 +121,8 @@ func _000001_initDownDbSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5e, 0xbb, 0x3f, 0x1, 0x75, 0x19, 0x70, 0x86, 0xa7, 0x34, 0x40, 0x17, 0x34, 0x3e, 0x18, 0x51, 0x79, 0xd4, 0x22, 0xad, 0x8f, 0x80, 0xcc, 0xa6, 0xcc, 0x6, 0x2b, 0x62, 0x2, 0x47, 0xba, 0xf9}}
|
||||
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(420), modTime: time.Unix(1581522640, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -132,8 +141,8 @@ func _000001_initUpDbSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2719, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x60, 0xdc, 0xeb, 0xe, 0xc2, 0x4f, 0x75, 0xa, 0xf6, 0x3e, 0xc7, 0xc4, 0x4, 0xe2, 0xe1, 0xa4, 0x73, 0x2f, 0x4a, 0xad, 0x1a, 0x0, 0xc3, 0x93, 0x9d, 0x77, 0x3e, 0x31, 0x91, 0x77, 0x2e, 0xc8}}
|
||||
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2719, mode: os.FileMode(420), modTime: time.Unix(1581522640, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -152,8 +161,8 @@ func _000002_add_last_ens_clock_valueUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "000002_add_last_ens_clock_value.up.sql", size: 77, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4d, 0x3, 0x8f, 0xd5, 0x85, 0x83, 0x47, 0xbe, 0xf9, 0x82, 0x7e, 0x81, 0xa4, 0xbd, 0xaa, 0xd5, 0x98, 0x18, 0x5, 0x2d, 0x82, 0x42, 0x3b, 0x3, 0x50, 0xc3, 0x1e, 0x84, 0x35, 0xf, 0xb6, 0x2b}}
|
||||
info := bindataFileInfo{name: "000002_add_last_ens_clock_value.up.sql", size: 77, mode: os.FileMode(420), modTime: time.Unix(1581522640, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -172,8 +181,8 @@ func _1586358095_add_replaceUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1586358095_add_replace.up.sql", size: 224, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd2, 0xb3, 0xa9, 0xc7, 0x7f, 0x9d, 0x8f, 0x43, 0x8c, 0x9e, 0x58, 0x8d, 0x44, 0xbc, 0xfa, 0x6b, 0x5f, 0x3f, 0x5a, 0xbe, 0xe8, 0xb1, 0x16, 0xf, 0x91, 0x2a, 0xa0, 0x71, 0xbb, 0x8d, 0x6b, 0xcb}}
|
||||
info := bindataFileInfo{name: "1586358095_add_replace.up.sql", size: 224, mode: os.FileMode(420), modTime: time.Unix(1587130924, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -192,8 +201,8 @@ func _1588665364_add_image_dataUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1588665364_add_image_data.up.sql", size: 186, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd6, 0xc6, 0x35, 0xb4, 0x4c, 0x39, 0x96, 0x29, 0x30, 0xda, 0xf4, 0x8f, 0xcb, 0xf1, 0x9f, 0x84, 0xdc, 0x88, 0xd4, 0xd5, 0xbc, 0xb6, 0x5b, 0x46, 0x78, 0x67, 0x76, 0x1a, 0x5, 0x36, 0xdc, 0xe5}}
|
||||
info := bindataFileInfo{name: "1588665364_add_image_data.up.sql", size: 186, mode: os.FileMode(420), modTime: time.Unix(1599566672, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -212,8 +221,8 @@ func _1589365189_add_pow_targetUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1589365189_add_pow_target.up.sql", size: 66, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4e, 0x3a, 0xe2, 0x2e, 0x7d, 0xaf, 0xbb, 0xcc, 0x21, 0xa1, 0x7a, 0x41, 0x9a, 0xd0, 0xbb, 0xa9, 0xc8, 0x35, 0xf9, 0x32, 0x34, 0x46, 0x44, 0x9a, 0x86, 0x40, 0x7c, 0xb9, 0x23, 0xc7, 0x3, 0x3f}}
|
||||
info := bindataFileInfo{name: "1589365189_add_pow_target.up.sql", size: 66, mode: os.FileMode(420), modTime: time.Unix(1599566672, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -232,8 +241,8 @@ func _1591277220_add_index_messagesUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1591277220_add_index_messages.up.sql", size: 240, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9c, 0xfe, 0xbe, 0xd5, 0xb8, 0x8f, 0xdd, 0xef, 0xbb, 0xa8, 0xad, 0x7f, 0xed, 0x5b, 0x5b, 0x2f, 0xe6, 0x82, 0x27, 0x78, 0x1f, 0xb9, 0x57, 0xdc, 0x8, 0xc2, 0xb2, 0xa9, 0x9a, 0x4, 0xe1, 0x7a}}
|
||||
info := bindataFileInfo{name: "1591277220_add_index_messages.up.sql", size: 240, mode: os.FileMode(420), modTime: time.Unix(1599566672, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -252,8 +261,8 @@ func _1593087212_add_mute_chat_and_raw_message_fieldsUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1593087212_add_mute_chat_and_raw_message_fields.up.sql", size: 215, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x73, 0x99, 0x61, 0xd1, 0xaa, 0xb4, 0xbf, 0xaf, 0xd7, 0x20, 0x17, 0x40, 0xf9, 0x2, 0xfb, 0xcc, 0x40, 0x2a, 0xd, 0x86, 0x36, 0x30, 0x88, 0x89, 0x25, 0x80, 0x42, 0xb0, 0x5b, 0xe9, 0x73, 0x78}}
|
||||
info := bindataFileInfo{name: "1593087212_add_mute_chat_and_raw_message_fields.up.sql", size: 215, mode: os.FileMode(420), modTime: time.Unix(1599566672, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -272,8 +281,8 @@ func _1595862781_add_audio_dataUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1595862781_add_audio_data.up.sql", size: 246, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xae, 0xd2, 0xee, 0x55, 0xfb, 0x36, 0xa4, 0x92, 0x66, 0xe, 0x81, 0x62, 0x1e, 0x7a, 0x69, 0xa, 0xd5, 0x4b, 0xa5, 0x6a, 0x8d, 0x1d, 0xce, 0xf3, 0x3e, 0xc0, 0x5f, 0x9c, 0x66, 0x1b, 0xb4, 0xed}}
|
||||
info := bindataFileInfo{name: "1595862781_add_audio_data.up.sql", size: 246, mode: os.FileMode(420), modTime: time.Unix(1599566672, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -292,8 +301,8 @@ func _1595865249_create_emoji_reactions_tableUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1595865249_create_emoji_reactions_table.up.sql", size: 300, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xc5, 0x43, 0x5c, 0x3d, 0x53, 0x43, 0x2c, 0x1a, 0xa5, 0xb6, 0xbf, 0x7, 0x4, 0x5a, 0x3e, 0x40, 0x8b, 0xa4, 0x57, 0x12, 0x58, 0xbc, 0x42, 0xe2, 0xc3, 0xde, 0x76, 0x98, 0x80, 0xe2, 0xbe}}
|
||||
info := bindataFileInfo{name: "1595865249_create_emoji_reactions_table.up.sql", size: 300, mode: os.FileMode(420), modTime: time.Unix(1599566672, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -312,8 +321,8 @@ func _1596805115_create_group_chat_invitations_tableUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1596805115_create_group_chat_invitations_table.up.sql", size: 231, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6d, 0xb1, 0x14, 0x6d, 0x54, 0x28, 0x67, 0xc3, 0x23, 0x6a, 0xfc, 0x80, 0xdf, 0x9e, 0x4c, 0x35, 0x36, 0xf, 0xf8, 0xf3, 0x5f, 0xae, 0xad, 0xb, 0xc1, 0x51, 0x8e, 0x17, 0x7, 0xe5, 0x7f, 0x91}}
|
||||
info := bindataFileInfo{name: "1596805115_create_group_chat_invitations_table.up.sql", size: 231, mode: os.FileMode(420), modTime: time.Unix(1599566672, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -332,8 +341,8 @@ func _1597322655_add_invitation_admin_chat_fieldUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1597322655_add_invitation_admin_chat_field.up.sql", size: 54, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0x7a, 0xa0, 0xf2, 0xdb, 0x13, 0x91, 0x91, 0xa8, 0x34, 0x1a, 0xa1, 0x49, 0x68, 0xd5, 0xae, 0x2c, 0xd8, 0xd5, 0xea, 0x8f, 0x8c, 0xc7, 0x2, 0x4e, 0x58, 0x2c, 0x3a, 0x14, 0xd4, 0x4f, 0x2c}}
|
||||
info := bindataFileInfo{name: "1597322655_add_invitation_admin_chat_field.up.sql", size: 54, mode: os.FileMode(420), modTime: time.Unix(1599566672, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -352,8 +361,8 @@ func _1597757544_add_nicknameUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1597757544_add_nickname.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf4, 0xa2, 0x64, 0x50, 0xc5, 0x4, 0xb9, 0x8b, 0xd1, 0x18, 0x9b, 0xc3, 0x91, 0x36, 0x2a, 0x1f, 0xc3, 0x6c, 0x2d, 0x92, 0xf8, 0x5e, 0xff, 0xb1, 0x59, 0x61, 0x2, 0x1c, 0xe1, 0x85, 0x90, 0xa4}}
|
||||
info := bindataFileInfo{name: "1597757544_add_nickname.up.sql", size: 52, mode: os.FileMode(420), modTime: time.Unix(1599566672, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -372,8 +381,8 @@ func _1598955122_add_mentionsUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1598955122_add_mentions.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8d, 0x22, 0x17, 0x92, 0xd2, 0x11, 0x4e, 0x7, 0x93, 0x9a, 0x55, 0xfd, 0xb, 0x97, 0xc4, 0x63, 0x6a, 0x81, 0x97, 0xcd, 0xb2, 0xf8, 0x4b, 0x5f, 0x3c, 0xfa, 0x3a, 0x38, 0x53, 0x10, 0xed, 0x9d}}
|
||||
info := bindataFileInfo{name: "1598955122_add_mentions.up.sql", size: 52, mode: os.FileMode(420), modTime: time.Unix(1601295087, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -392,8 +401,8 @@ func _1599641390_add_emoji_reactions_indexUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.up.sql", size: 126, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf9, 0xd8, 0xdc, 0xa7, 0xb, 0x92, 0x7a, 0x61, 0x37, 0x24, 0x1c, 0x77, 0x5e, 0xe, 0x7e, 0xfc, 0x9f, 0x98, 0x7b, 0x65, 0xe7, 0xf9, 0x71, 0x57, 0x89, 0x2d, 0x90, 0x1b, 0xf6, 0x5e, 0x37, 0xe8}}
|
||||
info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.up.sql", size: 126, mode: os.FileMode(420), modTime: time.Unix(1601295087, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -412,8 +421,8 @@ func _1599720851_add_seen_index_remove_long_messagesUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1599720851_add_seen_index_remove_long_messages.up.sql", size: 150, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x24, 0x1c, 0xc4, 0x78, 0x91, 0xc7, 0xeb, 0xfe, 0xc8, 0xa0, 0xd8, 0x13, 0x27, 0x97, 0xc8, 0x96, 0x56, 0x97, 0x33, 0x2c, 0x1e, 0x16, 0x8a, 0xd3, 0x49, 0x99, 0x3, 0xe9, 0xbb, 0xc4, 0x5, 0x3c}}
|
||||
info := bindataFileInfo{name: "1599720851_add_seen_index_remove_long_messages.up.sql", size: 150, mode: os.FileMode(420), modTime: time.Unix(1602575653, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -432,8 +441,8 @@ func _1603198582_add_profile_chat_fieldUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1603198582_add_profile_chat_field.up.sql", size: 45, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xaa, 0xca, 0xe, 0x46, 0xa0, 0x9, 0x9d, 0x47, 0x57, 0xe9, 0xfb, 0x17, 0xeb, 0x9c, 0xf6, 0xb8, 0x1d, 0xe9, 0xd, 0x0, 0xd5, 0xe5, 0xd8, 0x9e, 0x60, 0xa, 0xbf, 0x32, 0x2c, 0x52, 0x7f, 0x6a}}
|
||||
info := bindataFileInfo{name: "1603198582_add_profile_chat_field.up.sql", size: 45, mode: os.FileMode(420), modTime: time.Unix(1614159156, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -452,8 +461,8 @@ func _1603816533_add_linksUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1603816533_add_links.up.sql", size: 48, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0x24, 0xd6, 0x1d, 0xa, 0x83, 0x1e, 0x4d, 0xf, 0xae, 0x4d, 0x8c, 0x51, 0x32, 0xa8, 0x37, 0xb0, 0x14, 0xfb, 0x32, 0x34, 0xc8, 0xc, 0x4e, 0x5b, 0xc5, 0x15, 0x65, 0x73, 0x0, 0x0, 0x1d}}
|
||||
info := bindataFileInfo{name: "1603816533_add_links.up.sql", size: 48, mode: os.FileMode(420), modTime: time.Unix(1614159156, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -472,8 +481,8 @@ func _1603888149_create_chat_identity_last_published_tableUpSql() (*asset, error
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1603888149_create_chat_identity_last_published_table.up.sql", size: 407, mode: os.FileMode(0644), modTime: time.Unix(1608652331, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7f, 0x9, 0xf, 0xfb, 0xdb, 0x3c, 0x86, 0x70, 0x82, 0xda, 0x10, 0x25, 0xe2, 0x4e, 0x40, 0x45, 0xab, 0x8b, 0x1c, 0x91, 0x7c, 0xf1, 0x70, 0x2e, 0x81, 0xf3, 0x71, 0x45, 0xda, 0xe2, 0xa4, 0x57}}
|
||||
info := bindataFileInfo{name: "1603888149_create_chat_identity_last_published_table.up.sql", size: 407, mode: os.FileMode(420), modTime: time.Unix(1614159156, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -492,8 +501,8 @@ func _1605075346_add_communitiesUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1605075346_add_communities.up.sql", size: 6971, mode: os.FileMode(0644), modTime: time.Unix(1610388501, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1f, 0x64, 0xea, 0xb4, 0xae, 0x9e, 0xdb, 0x9, 0x58, 0xb6, 0x5c, 0x7a, 0x50, 0xc5, 0xfe, 0x93, 0x5d, 0x36, 0x85, 0x5d, 0x6a, 0xba, 0xc9, 0x7e, 0x84, 0xd7, 0xbf, 0x2a, 0x53, 0xf3, 0x97, 0xf1}}
|
||||
info := bindataFileInfo{name: "1605075346_add_communities.up.sql", size: 6971, mode: os.FileMode(420), modTime: time.Unix(1614159156, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -512,8 +521,8 @@ func _1610117927_add_message_cacheUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1610117927_add_message_cache.up.sql", size: 142, mode: os.FileMode(0644), modTime: time.Unix(1611563400, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0xf1, 0xf0, 0x82, 0x79, 0x28, 0x19, 0xc2, 0x39, 0x6a, 0xa5, 0x96, 0x59, 0x23, 0xa0, 0xed, 0x60, 0x58, 0x86, 0x9, 0xb9, 0xad, 0xfb, 0xa, 0xe3, 0x47, 0x6e, 0xa1, 0x18, 0xe8, 0x39, 0x2c}}
|
||||
info := bindataFileInfo{name: "1610117927_add_message_cache.up.sql", size: 142, mode: os.FileMode(420), modTime: time.Unix(1614159156, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -532,8 +541,8 @@ func _1610959908_add_dont_wrap_to_raw_messagesUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1610959908_add_dont_wrap_to_raw_messages.up.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1611825589, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x71, 0x2, 0x9a, 0xca, 0xd4, 0x38, 0x44, 0x30, 0x2b, 0xa8, 0x27, 0x32, 0x63, 0x53, 0x22, 0x60, 0x59, 0x84, 0x23, 0x96, 0x77, 0xf0, 0x56, 0xd7, 0x94, 0xe0, 0x95, 0x28, 0x6, 0x1d, 0x4e, 0xb1}}
|
||||
info := bindataFileInfo{name: "1610959908_add_dont_wrap_to_raw_messages.up.sql", size: 83, mode: os.FileMode(420), modTime: time.Unix(1614159156, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -552,8 +561,8 @@ func _1610960912_add_send_on_personal_topicUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1610960912_add_send_on_personal_topic.up.sql", size: 82, mode: os.FileMode(0644), modTime: time.Unix(1611825589, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x77, 0xac, 0x2f, 0xc4, 0xd, 0xa7, 0x1b, 0x37, 0x30, 0xc2, 0x68, 0xee, 0xde, 0x54, 0x5e, 0xbf, 0x3f, 0xa0, 0xd6, 0xc6, 0x9f, 0xd4, 0x34, 0x12, 0x76, 0x1e, 0x66, 0x4a, 0xfc, 0xf, 0xee, 0xc9}}
|
||||
info := bindataFileInfo{name: "1610960912_add_send_on_personal_topic.up.sql", size: 82, mode: os.FileMode(420), modTime: time.Unix(1614159156, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -572,8 +581,8 @@ func _1612870480_add_datasync_idUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1612870480_add_datasync_id.up.sql", size: 111, mode: os.FileMode(0644), modTime: time.Unix(1614251236, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0x9a, 0xbc, 0xfa, 0xaa, 0x8c, 0x9c, 0x37, 0x67, 0x15, 0x9c, 0x7e, 0x78, 0x75, 0x66, 0x82, 0x18, 0x72, 0x10, 0xbc, 0xd4, 0xab, 0x44, 0xfe, 0x57, 0x85, 0x6d, 0x19, 0xf5, 0x96, 0x8a, 0xbe}}
|
||||
info := bindataFileInfo{name: "1612870480_add_datasync_id.up.sql", size: 111, mode: os.FileMode(420), modTime: time.Unix(1614159156, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -592,8 +601,8 @@ func _1614152139_add_communities_request_to_joinUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1614152139_add_communities_request_to_join.up.sql", size: 831, mode: os.FileMode(0644), modTime: time.Unix(1614608661, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x11, 0x3, 0x26, 0xf9, 0x29, 0x50, 0x4f, 0xcd, 0x46, 0xe5, 0xb1, 0x6b, 0xb9, 0x2, 0x40, 0xb1, 0xdf, 0x4a, 0x4c, 0x7a, 0xda, 0x3, 0x35, 0xcd, 0x2d, 0xcc, 0x80, 0x7d, 0x57, 0x5f, 0x3, 0x5c}}
|
||||
info := bindataFileInfo{name: "1614152139_add_communities_request_to_join.up.sql", size: 831, mode: os.FileMode(420), modTime: time.Unix(1616621584, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -612,8 +621,8 @@ func _1615374373_add_confirmationsUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1615374373_add_confirmations.up.sql", size: 227, mode: os.FileMode(0644), modTime: time.Unix(1615904318, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xdd, 0xa6, 0x65, 0xc5, 0x1d, 0xb2, 0x77, 0x36, 0xe3, 0x79, 0xda, 0xe8, 0x7a, 0xa4, 0xdf, 0x45, 0xae, 0xd8, 0xb4, 0xba, 0x90, 0xfd, 0x74, 0x71, 0x14, 0x75, 0x73, 0x72, 0xb9, 0x9e, 0x1, 0x81}}
|
||||
info := bindataFileInfo{name: "1615374373_add_confirmations.up.sql", size: 227, mode: os.FileMode(420), modTime: time.Unix(1616621584, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -632,8 +641,28 @@ func _1617694931_add_notification_centerUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1617694931_add_notification_center.up.sql", size: 572, mode: os.FileMode(0644), modTime: time.Unix(1618824585, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x10, 0x45, 0xc6, 0xc9, 0x73, 0xbb, 0x1f, 0xda, 0xa3, 0x4d, 0x19, 0x98, 0x85, 0x2d, 0xca, 0xda, 0xcc, 0x3b, 0x32, 0xff, 0xc7, 0x7b, 0xe3, 0x9f, 0x9b, 0x2a, 0x93, 0xf5, 0xdf, 0x65, 0x38, 0x91}}
|
||||
info := bindataFileInfo{name: "1617694931_add_notification_center.up.sql", size: 572, mode: os.FileMode(420), modTime: time.Unix(1618923733, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __1618923660_create_pin_messagesUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\xcc\x41\x0b\xc2\x20\x18\xc6\xf1\xbb\x9f\xe2\x3d\x16\xf4\x0d\x3a\xb9\xf1\x56\x92\xb9\x70\x16\xed\x24\xe2\xa4\x49\x6e\x93\x5c\xf5\xf5\xa3\x88\xd8\x0e\x75\xfe\xff\x9e\x27\x97\x48\x15\x82\xa2\x19\x47\x60\x2b\x10\x85\x02\x3c\xb1\x52\x95\x10\x7d\xa7\x5b\x97\x92\x39\xbb\x04\x33\x02\xe0\x6b\x38\x52\x99\x6f\xa8\x84\xbd\x64\x3b\x2a\x2b\xd8\x62\xf5\x9e\x88\x03\xe7\x0b\x02\xf0\xf1\x7a\x44\xc7\xf9\xd1\xf8\x14\xdd\x55\x0f\xbe\x75\x69\x30\x6d\x04\x26\x14\xae\x71\xaa\x6c\x63\x86\x5f\x0f\xa1\xb7\x26\xe8\x7f\xc2\x86\xde\x5e\xf4\xdd\x84\x9b\x7b\xbd\x4f\x5a\xf4\x5d\xe7\x6a\xc8\x8a\x82\x23\x15\xdf\x44\xe6\x4b\xf2\x0c\x00\x00\xff\xff\x44\xad\x25\xa3\x09\x01\x00\x00")
|
||||
|
||||
func _1618923660_create_pin_messagesUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1618923660_create_pin_messagesUpSql,
|
||||
"1618923660_create_pin_messages.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1618923660_create_pin_messagesUpSql() (*asset, error) {
|
||||
bytes, err := _1618923660_create_pin_messagesUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1618923660_create_pin_messages.up.sql", size: 265, mode: os.FileMode(420), modTime: time.Unix(1620337259, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -652,8 +681,8 @@ func readmeMd() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "README.md", size: 554, mode: os.FileMode(0644), modTime: time.Unix(1610388501, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1c, 0x6e, 0xfb, 0xcc, 0x81, 0x94, 0x4d, 0x8c, 0xa0, 0x3b, 0x5, 0xb0, 0x18, 0xd6, 0xbb, 0xb3, 0x79, 0xc8, 0x8f, 0xff, 0xc1, 0x10, 0xf9, 0xf, 0x20, 0x1b, 0x4a, 0x74, 0x96, 0x42, 0xd7, 0xa8}}
|
||||
info := bindataFileInfo{name: "README.md", size: 554, mode: os.FileMode(420), modTime: time.Unix(1614159156, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -672,8 +701,8 @@ func docGo() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "doc.go", size: 850, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa0, 0xcc, 0x41, 0xe1, 0x61, 0x12, 0x97, 0xe, 0x36, 0x8c, 0xa7, 0x9e, 0xe0, 0x6e, 0x59, 0x9e, 0xee, 0xd5, 0x4a, 0xcf, 0x1e, 0x60, 0xd6, 0xc3, 0x3a, 0xc9, 0x6c, 0xf2, 0x86, 0x5a, 0xb4, 0x1e}}
|
||||
info := bindataFileInfo{name: "doc.go", size: 850, mode: os.FileMode(420), modTime: time.Unix(1620338680, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
|
@ -681,8 +710,8 @@ func docGo() (*asset, error) {
|
|||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[canonicalName]; ok {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||
|
@ -692,12 +721,6 @@ func Asset(name string) ([]byte, error) {
|
|||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// AssetString returns the asset contents as a string (instead of a []byte).
|
||||
func AssetString(name string) (string, error) {
|
||||
data, err := Asset(name)
|
||||
return string(data), err
|
||||
}
|
||||
|
||||
// MustAsset is like Asset but panics when Asset would return an error.
|
||||
// It simplifies safe initialization of global variables.
|
||||
func MustAsset(name string) []byte {
|
||||
|
@ -709,18 +732,12 @@ func MustAsset(name string) []byte {
|
|||
return a
|
||||
}
|
||||
|
||||
// MustAssetString is like AssetString but panics when Asset would return an
|
||||
// error. It simplifies safe initialization of global variables.
|
||||
func MustAssetString(name string) string {
|
||||
return string(MustAsset(name))
|
||||
}
|
||||
|
||||
// AssetInfo loads and returns the asset info for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func AssetInfo(name string) (os.FileInfo, error) {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[canonicalName]; ok {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||
|
@ -730,33 +747,6 @@ func AssetInfo(name string) (os.FileInfo, error) {
|
|||
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||
}
|
||||
|
||||
// AssetDigest returns the digest of the file with the given name. It returns an
|
||||
// error if the asset could not be found or the digest could not be loaded.
|
||||
func AssetDigest(name string) ([sha256.Size]byte, error) {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[canonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.digest, nil
|
||||
}
|
||||
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name)
|
||||
}
|
||||
|
||||
// Digests returns a map of all known files and their checksums.
|
||||
func Digests() (map[string][sha256.Size]byte, error) {
|
||||
mp := make(map[string][sha256.Size]byte, len(_bindata))
|
||||
for name := range _bindata {
|
||||
a, err := _bindata[name]()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp[name] = a.digest
|
||||
}
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
|
@ -768,63 +758,36 @@ func AssetNames() []string {
|
|||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"000001_init.down.db.sql": _000001_initDownDbSql,
|
||||
|
||||
"000001_init.up.db.sql": _000001_initUpDbSql,
|
||||
|
||||
"000002_add_last_ens_clock_value.up.sql": _000002_add_last_ens_clock_valueUpSql,
|
||||
|
||||
"1586358095_add_replace.up.sql": _1586358095_add_replaceUpSql,
|
||||
|
||||
"1588665364_add_image_data.up.sql": _1588665364_add_image_dataUpSql,
|
||||
|
||||
"1589365189_add_pow_target.up.sql": _1589365189_add_pow_targetUpSql,
|
||||
|
||||
"1591277220_add_index_messages.up.sql": _1591277220_add_index_messagesUpSql,
|
||||
|
||||
"1593087212_add_mute_chat_and_raw_message_fields.up.sql": _1593087212_add_mute_chat_and_raw_message_fieldsUpSql,
|
||||
|
||||
"1595862781_add_audio_data.up.sql": _1595862781_add_audio_dataUpSql,
|
||||
|
||||
"1595865249_create_emoji_reactions_table.up.sql": _1595865249_create_emoji_reactions_tableUpSql,
|
||||
|
||||
"1596805115_create_group_chat_invitations_table.up.sql": _1596805115_create_group_chat_invitations_tableUpSql,
|
||||
|
||||
"1597322655_add_invitation_admin_chat_field.up.sql": _1597322655_add_invitation_admin_chat_fieldUpSql,
|
||||
|
||||
"1597757544_add_nickname.up.sql": _1597757544_add_nicknameUpSql,
|
||||
|
||||
"1598955122_add_mentions.up.sql": _1598955122_add_mentionsUpSql,
|
||||
|
||||
"1599641390_add_emoji_reactions_index.up.sql": _1599641390_add_emoji_reactions_indexUpSql,
|
||||
|
||||
"1599720851_add_seen_index_remove_long_messages.up.sql": _1599720851_add_seen_index_remove_long_messagesUpSql,
|
||||
|
||||
"1603198582_add_profile_chat_field.up.sql": _1603198582_add_profile_chat_fieldUpSql,
|
||||
|
||||
"1603816533_add_links.up.sql": _1603816533_add_linksUpSql,
|
||||
|
||||
"000001_init.down.db.sql": _000001_initDownDbSql,
|
||||
"000001_init.up.db.sql": _000001_initUpDbSql,
|
||||
"000002_add_last_ens_clock_value.up.sql": _000002_add_last_ens_clock_valueUpSql,
|
||||
"1586358095_add_replace.up.sql": _1586358095_add_replaceUpSql,
|
||||
"1588665364_add_image_data.up.sql": _1588665364_add_image_dataUpSql,
|
||||
"1589365189_add_pow_target.up.sql": _1589365189_add_pow_targetUpSql,
|
||||
"1591277220_add_index_messages.up.sql": _1591277220_add_index_messagesUpSql,
|
||||
"1593087212_add_mute_chat_and_raw_message_fields.up.sql": _1593087212_add_mute_chat_and_raw_message_fieldsUpSql,
|
||||
"1595862781_add_audio_data.up.sql": _1595862781_add_audio_dataUpSql,
|
||||
"1595865249_create_emoji_reactions_table.up.sql": _1595865249_create_emoji_reactions_tableUpSql,
|
||||
"1596805115_create_group_chat_invitations_table.up.sql": _1596805115_create_group_chat_invitations_tableUpSql,
|
||||
"1597322655_add_invitation_admin_chat_field.up.sql": _1597322655_add_invitation_admin_chat_fieldUpSql,
|
||||
"1597757544_add_nickname.up.sql": _1597757544_add_nicknameUpSql,
|
||||
"1598955122_add_mentions.up.sql": _1598955122_add_mentionsUpSql,
|
||||
"1599641390_add_emoji_reactions_index.up.sql": _1599641390_add_emoji_reactions_indexUpSql,
|
||||
"1599720851_add_seen_index_remove_long_messages.up.sql": _1599720851_add_seen_index_remove_long_messagesUpSql,
|
||||
"1603198582_add_profile_chat_field.up.sql": _1603198582_add_profile_chat_fieldUpSql,
|
||||
"1603816533_add_links.up.sql": _1603816533_add_linksUpSql,
|
||||
"1603888149_create_chat_identity_last_published_table.up.sql": _1603888149_create_chat_identity_last_published_tableUpSql,
|
||||
|
||||
"1605075346_add_communities.up.sql": _1605075346_add_communitiesUpSql,
|
||||
|
||||
"1610117927_add_message_cache.up.sql": _1610117927_add_message_cacheUpSql,
|
||||
|
||||
"1610959908_add_dont_wrap_to_raw_messages.up.sql": _1610959908_add_dont_wrap_to_raw_messagesUpSql,
|
||||
|
||||
"1610960912_add_send_on_personal_topic.up.sql": _1610960912_add_send_on_personal_topicUpSql,
|
||||
|
||||
"1612870480_add_datasync_id.up.sql": _1612870480_add_datasync_idUpSql,
|
||||
|
||||
"1614152139_add_communities_request_to_join.up.sql": _1614152139_add_communities_request_to_joinUpSql,
|
||||
|
||||
"1615374373_add_confirmations.up.sql": _1615374373_add_confirmationsUpSql,
|
||||
|
||||
"1617694931_add_notification_center.up.sql": _1617694931_add_notification_centerUpSql,
|
||||
|
||||
"README.md": readmeMd,
|
||||
|
||||
"doc.go": docGo,
|
||||
"1605075346_add_communities.up.sql": _1605075346_add_communitiesUpSql,
|
||||
"1610117927_add_message_cache.up.sql": _1610117927_add_message_cacheUpSql,
|
||||
"1610959908_add_dont_wrap_to_raw_messages.up.sql": _1610959908_add_dont_wrap_to_raw_messagesUpSql,
|
||||
"1610960912_add_send_on_personal_topic.up.sql": _1610960912_add_send_on_personal_topicUpSql,
|
||||
"1612870480_add_datasync_id.up.sql": _1612870480_add_datasync_idUpSql,
|
||||
"1614152139_add_communities_request_to_join.up.sql": _1614152139_add_communities_request_to_joinUpSql,
|
||||
"1615374373_add_confirmations.up.sql": _1615374373_add_confirmationsUpSql,
|
||||
"1617694931_add_notification_center.up.sql": _1617694931_add_notification_centerUpSql,
|
||||
"1618923660_create_pin_messages.up.sql": _1618923660_create_pin_messagesUpSql,
|
||||
"README.md": readmeMd,
|
||||
"doc.go": docGo,
|
||||
}
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
|
@ -836,15 +799,15 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"},
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"},
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(canonicalName, "/")
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(cannonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
|
@ -895,11 +858,12 @@ var _bintree = &bintree{nil, map[string]*bintree{
|
|||
"1614152139_add_communities_request_to_join.up.sql": &bintree{_1614152139_add_communities_request_to_joinUpSql, map[string]*bintree{}},
|
||||
"1615374373_add_confirmations.up.sql": &bintree{_1615374373_add_confirmationsUpSql, map[string]*bintree{}},
|
||||
"1617694931_add_notification_center.up.sql": &bintree{_1617694931_add_notification_centerUpSql, map[string]*bintree{}},
|
||||
"README.md": &bintree{readmeMd, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
"1618923660_create_pin_messages.up.sql": &bintree{_1618923660_create_pin_messagesUpSql, map[string]*bintree{}},
|
||||
"README.md": &bintree{readmeMd, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory.
|
||||
// RestoreAsset restores an asset under the given directory
|
||||
func RestoreAsset(dir, name string) error {
|
||||
data, err := Asset(name)
|
||||
if err != nil {
|
||||
|
@ -917,10 +881,14 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreAssets restores an asset under the given directory recursively.
|
||||
// RestoreAssets restores an asset under the given directory recursively
|
||||
func RestoreAssets(dir, name string) error {
|
||||
children, err := AssetDir(name)
|
||||
// File
|
||||
|
@ -938,6 +906,6 @@ func RestoreAssets(dir, name string) error {
|
|||
}
|
||||
|
||||
func _filePath(dir, name string) string {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...)
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
CREATE TABLE IF NOT EXISTS pin_messages (
|
||||
id VARCHAR PRIMARY KEY NOT NULL,
|
||||
message_id VARCHAR NOT NULL,
|
||||
whisper_timestamp INTEGER NOT NULL,
|
||||
chat_id VARCHAR NOT NULL,
|
||||
local_chat_id VARCHAR NOT NULL,
|
||||
clock_value INT NOT NULL,
|
||||
pinned BOOLEAN NOT NULL
|
||||
);
|
|
@ -181,6 +181,119 @@ func TestMessageByChatID(t *testing.T) {
|
|||
)
|
||||
}
|
||||
|
||||
func TestPinMessageByChatID(t *testing.T) {
|
||||
db, err := openTestDB()
|
||||
require.NoError(t, err)
|
||||
p := sqlitePersistence{db: db}
|
||||
chatID := "chat-with-pinned-messages"
|
||||
messagesCount := 1000
|
||||
pageSize := 5
|
||||
pinnedMessagesCount := 0
|
||||
|
||||
var messages []*common.Message
|
||||
var pinMessages []*common.PinMessage
|
||||
for i := 0; i < messagesCount; i++ {
|
||||
messages = append(messages, &common.Message{
|
||||
ID: strconv.Itoa(i),
|
||||
LocalChatID: chatID,
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
Clock: uint64(i),
|
||||
},
|
||||
From: "me",
|
||||
})
|
||||
|
||||
// Pin this message
|
||||
if i%100 == 0 {
|
||||
pinMessage := &common.PinMessage{
|
||||
ID: strconv.Itoa(i),
|
||||
LocalChatID: chatID,
|
||||
From: "me",
|
||||
}
|
||||
|
||||
pinMessage.MessageId = strconv.Itoa(i)
|
||||
pinMessage.Clock = 111
|
||||
pinMessage.Pinned = true
|
||||
pinMessages = append(pinMessages, pinMessage)
|
||||
pinnedMessagesCount++
|
||||
|
||||
if i%200 == 0 {
|
||||
// unpin a message
|
||||
unpinMessage := &common.PinMessage{
|
||||
ID: strconv.Itoa(i),
|
||||
LocalChatID: chatID,
|
||||
From: "me",
|
||||
}
|
||||
pinMessage.MessageId = strconv.Itoa(i)
|
||||
unpinMessage.Clock = 333
|
||||
unpinMessage.Pinned = false
|
||||
pinMessages = append(pinMessages, unpinMessage)
|
||||
pinnedMessagesCount--
|
||||
|
||||
// pinned before the unpin
|
||||
pinMessage2 := &common.PinMessage{
|
||||
ID: strconv.Itoa(i),
|
||||
LocalChatID: chatID,
|
||||
From: "me",
|
||||
}
|
||||
pinMessage2.MessageId = strconv.Itoa(i)
|
||||
pinMessage2.Clock = 222
|
||||
pinMessage2.Pinned = true
|
||||
pinMessages = append(pinMessages, pinMessage2)
|
||||
}
|
||||
}
|
||||
|
||||
// Add some other chats.
|
||||
if i%5 == 0 {
|
||||
messages = append(messages, &common.Message{
|
||||
ID: strconv.Itoa(messagesCount + i),
|
||||
LocalChatID: "chat-without-pinned-messages",
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
Clock: uint64(i),
|
||||
},
|
||||
|
||||
From: "me",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
err = p.SaveMessages(messages)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.SavePinMessages(pinMessages)
|
||||
require.NoError(t, err)
|
||||
|
||||
var (
|
||||
result []*common.PinnedMessage
|
||||
cursor string
|
||||
iter int
|
||||
)
|
||||
for {
|
||||
var (
|
||||
items []*common.PinnedMessage
|
||||
err error
|
||||
)
|
||||
|
||||
items, cursor, err = p.PinnedMessageByChatID(chatID, cursor, pageSize)
|
||||
require.NoError(t, err)
|
||||
result = append(result, items...)
|
||||
|
||||
iter++
|
||||
if len(cursor) == 0 || iter > messagesCount {
|
||||
break
|
||||
}
|
||||
}
|
||||
require.Equal(t, "", cursor) // for loop should exit because of cursor being empty
|
||||
require.EqualValues(t, pinnedMessagesCount, len(result))
|
||||
require.EqualValues(t, math.Ceil(float64(pinnedMessagesCount)/float64(pageSize)), iter)
|
||||
require.True(
|
||||
t,
|
||||
// Verify descending order.
|
||||
sort.SliceIsSorted(result, func(i, j int) bool {
|
||||
return result[i].Clock > result[j].Clock
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func TestMessageReplies(t *testing.T) {
|
||||
db, err := openTestDB()
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -51,6 +51,7 @@ const (
|
|||
ApplicationMetadataMessage_COMMUNITY_DESCRIPTION ApplicationMetadataMessage_Type = 25
|
||||
ApplicationMetadataMessage_COMMUNITY_INVITATION ApplicationMetadataMessage_Type = 26
|
||||
ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN ApplicationMetadataMessage_Type = 27
|
||||
ApplicationMetadataMessage_PIN_MESSAGE ApplicationMetadataMessage_Type = 28
|
||||
)
|
||||
|
||||
var ApplicationMetadataMessage_Type_name = map[int32]string{
|
||||
|
@ -82,6 +83,7 @@ var ApplicationMetadataMessage_Type_name = map[int32]string{
|
|||
25: "COMMUNITY_DESCRIPTION",
|
||||
26: "COMMUNITY_INVITATION",
|
||||
27: "COMMUNITY_REQUEST_TO_JOIN",
|
||||
28: "PIN_MESSAGE",
|
||||
}
|
||||
|
||||
var ApplicationMetadataMessage_Type_value = map[string]int32{
|
||||
|
@ -113,6 +115,7 @@ var ApplicationMetadataMessage_Type_value = map[string]int32{
|
|||
"COMMUNITY_DESCRIPTION": 25,
|
||||
"COMMUNITY_INVITATION": 26,
|
||||
"COMMUNITY_REQUEST_TO_JOIN": 27,
|
||||
"PIN_MESSAGE": 28,
|
||||
}
|
||||
|
||||
func (x ApplicationMetadataMessage_Type) String() string {
|
||||
|
@ -191,39 +194,40 @@ func init() {
|
|||
}
|
||||
|
||||
var fileDescriptor_ad09a6406fcf24c7 = []byte{
|
||||
// 539 bytes of a gzipped FileDescriptorProto
|
||||
// 546 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0x4d, 0x53, 0xdb, 0x3e,
|
||||
0x10, 0xc6, 0xff, 0x01, 0xfe, 0x04, 0x96, 0x97, 0x8a, 0x05, 0x8a, 0x81, 0xf2, 0xd2, 0xb4, 0xd3,
|
||||
0xd2, 0x76, 0x26, 0x87, 0xf6, 0xdc, 0x83, 0x90, 0x17, 0x10, 0x8d, 0x25, 0x23, 0xc9, 0x74, 0x72,
|
||||
0xd2, 0x98, 0xe2, 0x32, 0xcc, 0x00, 0xf1, 0x80, 0x39, 0xf0, 0xe5, 0xfa, 0x29, 0xfa, 0x81, 0x3a,
|
||||
0x76, 0x12, 0x02, 0x4d, 0x28, 0x27, 0x8f, 0x9e, 0xe7, 0xb7, 0x2b, 0xef, 0xb3, 0x36, 0x34, 0xd2,
|
||||
0x3c, 0xbf, 0x38, 0xff, 0x91, 0x16, 0xe7, 0x9d, 0x2b, 0x7f, 0x99, 0x15, 0xe9, 0x69, 0x5a, 0xa4,
|
||||
0xfe, 0x32, 0xbb, 0xb9, 0x49, 0xcf, 0xb2, 0x66, 0x7e, 0xdd, 0x29, 0x3a, 0x38, 0x55, 0x3d, 0x4e,
|
||||
0x6e, 0x7f, 0x36, 0x7e, 0xd7, 0x61, 0x8d, 0x0f, 0x0a, 0xa2, 0x1e, 0x1f, 0x75, 0x71, 0x7c, 0x05,
|
||||
0xd3, 0x37, 0xe7, 0x67, 0x57, 0x69, 0x71, 0x7b, 0x9d, 0x05, 0xb5, 0xed, 0xda, 0xce, 0xac, 0x19,
|
||||
0x08, 0x18, 0x40, 0x3d, 0x4f, 0xef, 0x2e, 0x3a, 0xe9, 0x69, 0x30, 0x56, 0x79, 0xfd, 0x23, 0x7e,
|
||||
0x85, 0x89, 0xe2, 0x2e, 0xcf, 0x82, 0xf1, 0xed, 0xda, 0xce, 0xfc, 0xe7, 0x0f, 0xcd, 0xfe, 0x7d,
|
||||
0xcd, 0xa7, 0xef, 0x6a, 0xba, 0xbb, 0x3c, 0x33, 0x55, 0x59, 0xe3, 0xd7, 0x24, 0x4c, 0x94, 0x47,
|
||||
0x9c, 0x81, 0x7a, 0xa2, 0xbe, 0x29, 0xfd, 0x5d, 0xb1, 0xff, 0x90, 0xc1, 0xac, 0x38, 0xe0, 0xce,
|
||||
0x47, 0x64, 0x2d, 0xdf, 0x27, 0x56, 0x43, 0x84, 0x79, 0xa1, 0x95, 0xe3, 0xc2, 0xf9, 0x24, 0x0e,
|
||||
0xb9, 0x23, 0x36, 0x86, 0x1b, 0xb0, 0x1a, 0x51, 0xb4, 0x4b, 0xc6, 0x1e, 0xc8, 0xb8, 0x27, 0xdf,
|
||||
0x97, 0x8c, 0xe3, 0x32, 0x2c, 0xc4, 0x5c, 0x1a, 0x2f, 0x95, 0x75, 0xbc, 0xd5, 0xe2, 0x4e, 0x6a,
|
||||
0xc5, 0x26, 0x4a, 0xd9, 0xb6, 0x95, 0x78, 0x2c, 0xff, 0x8f, 0x6f, 0x60, 0xcb, 0xd0, 0x51, 0x42,
|
||||
0xd6, 0x79, 0x1e, 0x86, 0x86, 0xac, 0xf5, 0x7b, 0xda, 0x78, 0x67, 0xb8, 0xb2, 0x5c, 0x54, 0xd0,
|
||||
0x24, 0x7e, 0x84, 0x77, 0x5c, 0x08, 0x8a, 0x9d, 0x7f, 0x8e, 0xad, 0xe3, 0x27, 0x78, 0x1f, 0x92,
|
||||
0x68, 0x49, 0x45, 0xcf, 0xc2, 0x53, 0xb8, 0x02, 0x8b, 0x7d, 0xe8, 0xa1, 0x31, 0x8d, 0x4b, 0xc0,
|
||||
0x2c, 0xa9, 0xf0, 0x91, 0x0a, 0xb8, 0x05, 0xeb, 0x7f, 0xf7, 0x7e, 0x08, 0xcc, 0x94, 0xd1, 0x0c,
|
||||
0x0d, 0xe9, 0x7b, 0x01, 0xb2, 0xd9, 0xd1, 0x36, 0x17, 0x42, 0x27, 0xca, 0xb1, 0x39, 0x7c, 0x0d,
|
||||
0x1b, 0xc3, 0x76, 0x9c, 0xec, 0xb6, 0xa4, 0xf0, 0xe5, 0x5e, 0xd8, 0x3c, 0x6e, 0xc2, 0x5a, 0x7f,
|
||||
0x1f, 0x42, 0x87, 0xe4, 0x79, 0x78, 0x4c, 0xc6, 0x49, 0x4b, 0x11, 0x29, 0xc7, 0x5e, 0x60, 0x03,
|
||||
0x36, 0xe3, 0xc4, 0x1e, 0x78, 0xa5, 0x9d, 0xdc, 0x93, 0xa2, 0xdb, 0xc2, 0xd0, 0xbe, 0xb4, 0xce,
|
||||
0x74, 0x23, 0x67, 0x65, 0x42, 0xff, 0x66, 0xbc, 0x21, 0x1b, 0x6b, 0x65, 0x89, 0x2d, 0xe0, 0x3a,
|
||||
0xac, 0x0c, 0xc3, 0x47, 0x09, 0x99, 0x36, 0x43, 0x7c, 0x0b, 0xdb, 0x4f, 0x98, 0x83, 0x16, 0x8b,
|
||||
0xe5, 0xd4, 0xa3, 0xee, 0xab, 0xf2, 0x63, 0x4b, 0xe5, 0x48, 0xa3, 0xec, 0x5e, 0xf9, 0x72, 0xf9,
|
||||
0x09, 0x52, 0xa4, 0x0f, 0xa5, 0x37, 0xd4, 0xcb, 0xf9, 0x25, 0xae, 0xc2, 0xf2, 0xbe, 0xd1, 0x49,
|
||||
0x5c, 0xc5, 0xe2, 0xa5, 0x3a, 0x96, 0xae, 0x3b, 0xdd, 0x0a, 0x2e, 0xc0, 0x5c, 0x57, 0x0c, 0x49,
|
||||
0x39, 0xe9, 0xda, 0x2c, 0x28, 0x69, 0xa1, 0xa3, 0x28, 0x51, 0xd2, 0xb5, 0x7d, 0x48, 0x56, 0x18,
|
||||
0x19, 0x57, 0xf4, 0x2a, 0x06, 0xb0, 0x34, 0xb0, 0x1e, 0xf4, 0x59, 0x2b, 0xdf, 0x7a, 0xe0, 0xdc,
|
||||
0x6f, 0x5b, 0xfb, 0x43, 0x2d, 0x15, 0x5b, 0x3f, 0x99, 0xac, 0x7e, 0xb8, 0x2f, 0x7f, 0x02, 0x00,
|
||||
0x00, 0xff, 0xff, 0xf0, 0x9e, 0xc6, 0x34, 0x0d, 0x04, 0x00, 0x00,
|
||||
0x10, 0xc6, 0xff, 0x01, 0xfe, 0x04, 0x96, 0x37, 0xb1, 0x40, 0x31, 0xef, 0x34, 0xed, 0xb4, 0xb4,
|
||||
0x9d, 0xc9, 0xa1, 0x3d, 0xf7, 0x20, 0xe4, 0x05, 0x44, 0x63, 0xc9, 0x48, 0x32, 0x9d, 0x9c, 0x34,
|
||||
0xa6, 0xb8, 0x0c, 0x33, 0x40, 0x3c, 0x60, 0x0e, 0x7c, 0xca, 0x7e, 0x8a, 0x7e, 0x8f, 0x8e, 0x9d,
|
||||
0x84, 0x40, 0x09, 0xe5, 0x94, 0xd1, 0xf3, 0xfc, 0x76, 0x95, 0x7d, 0x56, 0x86, 0x46, 0x9a, 0xe7,
|
||||
0x17, 0xe7, 0x3f, 0xd2, 0xe2, 0xbc, 0x73, 0xe5, 0x2f, 0xb3, 0x22, 0x3d, 0x4d, 0x8b, 0xd4, 0x5f,
|
||||
0x66, 0x37, 0x37, 0xe9, 0x59, 0xd6, 0xcc, 0xaf, 0x3b, 0x45, 0x07, 0x27, 0xaa, 0x9f, 0x93, 0xdb,
|
||||
0x9f, 0x8d, 0xdf, 0x75, 0x58, 0xe5, 0x83, 0x82, 0xa8, 0xc7, 0x47, 0x5d, 0x1c, 0xd7, 0x61, 0xf2,
|
||||
0xe6, 0xfc, 0xec, 0x2a, 0x2d, 0x6e, 0xaf, 0xb3, 0xa0, 0xb6, 0x5d, 0xdb, 0x99, 0x36, 0x03, 0x01,
|
||||
0x03, 0xa8, 0xe7, 0xe9, 0xdd, 0x45, 0x27, 0x3d, 0x0d, 0x46, 0x2a, 0xaf, 0x7f, 0xc4, 0xaf, 0x30,
|
||||
0x56, 0xdc, 0xe5, 0x59, 0x30, 0xba, 0x5d, 0xdb, 0x99, 0xfd, 0xfc, 0xa1, 0xd9, 0xbf, 0xaf, 0xf9,
|
||||
0xfc, 0x5d, 0x4d, 0x77, 0x97, 0x67, 0xa6, 0x2a, 0x6b, 0xfc, 0x1a, 0x87, 0xb1, 0xf2, 0x88, 0x53,
|
||||
0x50, 0x4f, 0xd4, 0x37, 0xa5, 0xbf, 0x2b, 0xf6, 0x1f, 0x32, 0x98, 0x16, 0x07, 0xdc, 0xf9, 0x88,
|
||||
0xac, 0xe5, 0xfb, 0xc4, 0x6a, 0x88, 0x30, 0x2b, 0xb4, 0x72, 0x5c, 0x38, 0x9f, 0xc4, 0x21, 0x77,
|
||||
0xc4, 0x46, 0x70, 0x03, 0x56, 0x22, 0x8a, 0x76, 0xc9, 0xd8, 0x03, 0x19, 0xf7, 0xe4, 0xfb, 0x92,
|
||||
0x51, 0x5c, 0x82, 0xf9, 0x98, 0x4b, 0xe3, 0xa5, 0xb2, 0x8e, 0xb7, 0x5a, 0xdc, 0x49, 0xad, 0xd8,
|
||||
0x58, 0x29, 0xdb, 0xb6, 0x12, 0x8f, 0xe5, 0xff, 0xf1, 0x0d, 0x6c, 0x19, 0x3a, 0x4a, 0xc8, 0x3a,
|
||||
0xcf, 0xc3, 0xd0, 0x90, 0xb5, 0x7e, 0x4f, 0x1b, 0xef, 0x0c, 0x57, 0x96, 0x8b, 0x0a, 0x1a, 0xc7,
|
||||
0x8f, 0xf0, 0x8e, 0x0b, 0x41, 0xb1, 0xf3, 0x2f, 0xb1, 0x75, 0xfc, 0x04, 0xef, 0x43, 0x12, 0x2d,
|
||||
0xa9, 0xe8, 0x45, 0x78, 0x02, 0x97, 0x61, 0xa1, 0x0f, 0x3d, 0x34, 0x26, 0x71, 0x11, 0x98, 0x25,
|
||||
0x15, 0x3e, 0x52, 0x01, 0xb7, 0x60, 0xed, 0xef, 0xde, 0x0f, 0x81, 0xa9, 0x32, 0x9a, 0x27, 0x43,
|
||||
0xfa, 0x5e, 0x80, 0x6c, 0x7a, 0xb8, 0xcd, 0x85, 0xd0, 0x89, 0x72, 0x6c, 0x06, 0x5f, 0xc3, 0xc6,
|
||||
0x53, 0x3b, 0x4e, 0x76, 0x5b, 0x52, 0xf8, 0x72, 0x2f, 0x6c, 0x16, 0x37, 0x61, 0xb5, 0xbf, 0x0f,
|
||||
0xa1, 0x43, 0xf2, 0x3c, 0x3c, 0x26, 0xe3, 0xa4, 0xa5, 0x88, 0x94, 0x63, 0x73, 0xd8, 0x80, 0xcd,
|
||||
0x38, 0xb1, 0x07, 0x5e, 0x69, 0x27, 0xf7, 0xa4, 0xe8, 0xb6, 0x30, 0xb4, 0x2f, 0xad, 0x33, 0xdd,
|
||||
0xc8, 0x59, 0x99, 0xd0, 0xbf, 0x19, 0x6f, 0xc8, 0xc6, 0x5a, 0x59, 0x62, 0xf3, 0xb8, 0x06, 0xcb,
|
||||
0x4f, 0xe1, 0xa3, 0x84, 0x4c, 0x9b, 0x21, 0xbe, 0x85, 0xed, 0x67, 0xcc, 0x41, 0x8b, 0x85, 0x72,
|
||||
0xea, 0x61, 0xf7, 0x55, 0xf9, 0xb1, 0xc5, 0x72, 0xa4, 0x61, 0x76, 0xaf, 0x7c, 0xa9, 0x7c, 0x82,
|
||||
0x14, 0xe9, 0x43, 0xe9, 0x0d, 0xf5, 0x72, 0x7e, 0x85, 0x2b, 0xb0, 0xb4, 0x6f, 0x74, 0x12, 0x57,
|
||||
0xb1, 0x78, 0xa9, 0x8e, 0xa5, 0xeb, 0x4e, 0xb7, 0x8c, 0xf3, 0x30, 0xd3, 0x15, 0x43, 0x52, 0x4e,
|
||||
0xba, 0x36, 0x0b, 0x4a, 0x5a, 0xe8, 0x28, 0x4a, 0x94, 0x74, 0x6d, 0x1f, 0x92, 0x15, 0x46, 0xc6,
|
||||
0x15, 0xbd, 0x82, 0x01, 0x2c, 0x0e, 0xac, 0x07, 0x7d, 0x56, 0xcb, 0x7f, 0x3d, 0x70, 0xee, 0xb7,
|
||||
0xad, 0xfd, 0xa1, 0x96, 0x8a, 0xad, 0xe1, 0x1c, 0x4c, 0xc5, 0x52, 0xdd, 0x3f, 0xfb, 0xf5, 0x93,
|
||||
0xf1, 0xea, 0x0b, 0xfc, 0xf2, 0x27, 0x00, 0x00, 0xff, 0xff, 0xe4, 0xe4, 0x0e, 0xb6, 0x1e, 0x04,
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -40,5 +40,6 @@ message ApplicationMetadataMessage {
|
|||
COMMUNITY_DESCRIPTION = 25;
|
||||
COMMUNITY_INVITATION = 26;
|
||||
COMMUNITY_REQUEST_TO_JOIN = 27;
|
||||
PIN_MESSAGE = 28;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: pin_message.proto
|
||||
|
||||
package protobuf
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type PinMessage struct {
|
||||
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
|
||||
MessageId string `protobuf:"bytes,2,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"`
|
||||
ChatId string `protobuf:"bytes,3,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
|
||||
Pinned bool `protobuf:"varint,4,opt,name=pinned,proto3" json:"pinned,omitempty"`
|
||||
// The type of message (public/one-to-one/private-group-chat)
|
||||
MessageType MessageType `protobuf:"varint,5,opt,name=message_type,json=messageType,proto3,enum=protobuf.MessageType" json:"message_type,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PinMessage) Reset() { *m = PinMessage{} }
|
||||
func (m *PinMessage) String() string { return proto.CompactTextString(m) }
|
||||
func (*PinMessage) ProtoMessage() {}
|
||||
func (*PinMessage) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_b3c2ad1be7128a0a, []int{0}
|
||||
}
|
||||
|
||||
func (m *PinMessage) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_PinMessage.Unmarshal(m, b)
|
||||
}
|
||||
func (m *PinMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_PinMessage.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *PinMessage) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PinMessage.Merge(m, src)
|
||||
}
|
||||
func (m *PinMessage) XXX_Size() int {
|
||||
return xxx_messageInfo_PinMessage.Size(m)
|
||||
}
|
||||
func (m *PinMessage) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PinMessage.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PinMessage proto.InternalMessageInfo
|
||||
|
||||
func (m *PinMessage) GetClock() uint64 {
|
||||
if m != nil {
|
||||
return m.Clock
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *PinMessage) GetMessageId() string {
|
||||
if m != nil {
|
||||
return m.MessageId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PinMessage) GetChatId() string {
|
||||
if m != nil {
|
||||
return m.ChatId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PinMessage) GetPinned() bool {
|
||||
if m != nil {
|
||||
return m.Pinned
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *PinMessage) GetMessageType() MessageType {
|
||||
if m != nil {
|
||||
return m.MessageType
|
||||
}
|
||||
return MessageType_UNKNOWN_MESSAGE_TYPE
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*PinMessage)(nil), "protobuf.PinMessage")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("pin_message.proto", fileDescriptor_b3c2ad1be7128a0a)
|
||||
}
|
||||
|
||||
var fileDescriptor_b3c2ad1be7128a0a = []byte{
|
||||
// 183 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0xc8, 0xcc, 0x8b,
|
||||
0xcf, 0x4d, 0x2d, 0x2e, 0x4e, 0x4c, 0x4f, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x00,
|
||||
0x53, 0x49, 0xa5, 0x69, 0x52, 0xdc, 0xa9, 0x79, 0xa5, 0xb9, 0xc5, 0x10, 0x61, 0xa5, 0x35, 0x8c,
|
||||
0x5c, 0x5c, 0x01, 0x99, 0x79, 0xbe, 0x10, 0xb5, 0x42, 0x22, 0x5c, 0xac, 0xc9, 0x39, 0xf9, 0xc9,
|
||||
0xd9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x2c, 0x41, 0x10, 0x8e, 0x90, 0x2c, 0x17, 0x17, 0xd4, 0xb0,
|
||||
0xf8, 0xcc, 0x14, 0x09, 0x26, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x4e, 0xa8, 0x88, 0x67, 0x8a, 0x90,
|
||||
0x38, 0x17, 0x7b, 0x72, 0x46, 0x62, 0x09, 0x48, 0x8e, 0x19, 0x2c, 0xc7, 0x06, 0xe2, 0x7a, 0xa6,
|
||||
0x08, 0x89, 0x71, 0xb1, 0x15, 0x64, 0xe6, 0xe5, 0xa5, 0xa6, 0x48, 0xb0, 0x28, 0x30, 0x6a, 0x70,
|
||||
0x04, 0x41, 0x79, 0x42, 0x16, 0x5c, 0x3c, 0x30, 0xf3, 0x4a, 0x2a, 0x0b, 0x52, 0x25, 0x58, 0x15,
|
||||
0x18, 0x35, 0xf8, 0x8c, 0x44, 0xf5, 0x60, 0x4e, 0xd4, 0x83, 0x3a, 0x27, 0xa4, 0xb2, 0x20, 0x35,
|
||||
0x88, 0x3b, 0x17, 0xc1, 0x49, 0x62, 0x03, 0x2b, 0x31, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x3d,
|
||||
0x9f, 0x5d, 0x9f, 0xe1, 0x00, 0x00, 0x00,
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package protobuf;
|
||||
|
||||
import "enums.proto";
|
||||
|
||||
message PinMessage {
|
||||
uint64 clock = 1;
|
||||
string message_id = 2;
|
||||
string chat_id = 3;
|
||||
bool pinned = 4;
|
||||
// The type of message (public/one-to-one/private-group-chat)
|
||||
MessageType message_type = 5;
|
||||
}
|
|
@ -190,6 +190,9 @@ func (m *StatusMessage) HandleApplication() error {
|
|||
case protobuf.ApplicationMetadataMessage_CONTACT_UPDATE:
|
||||
return m.unmarshalProtobufData(new(protobuf.ContactUpdate))
|
||||
|
||||
case protobuf.ApplicationMetadataMessage_PIN_MESSAGE:
|
||||
return m.unmarshalProtobufData(new(protobuf.PinMessage))
|
||||
|
||||
case protobuf.ApplicationMetadataMessage_SYNC_INSTALLATION:
|
||||
return m.unmarshalProtobufData(new(protobuf.SyncInstallation))
|
||||
|
||||
|
|
|
@ -423,6 +423,11 @@ type ApplicationMessagesResponse struct {
|
|||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
type ApplicationPinnedMessagesResponse struct {
|
||||
Messages []*common.PinnedMessage `json:"messages"`
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
func (api *PublicAPI) ChatMessages(chatID, cursor string, limit int) (*ApplicationMessagesResponse, error) {
|
||||
messages, cursor, err := api.service.messenger.MessageByChatID(chatID, cursor, limit)
|
||||
if err != nil {
|
||||
|
@ -435,6 +440,18 @@ func (api *PublicAPI) ChatMessages(chatID, cursor string, limit int) (*Applicati
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (api *PublicAPI) ChatPinnedMessages(chatID, cursor string, limit int) (*ApplicationPinnedMessagesResponse, error) {
|
||||
messages, cursor, err := api.service.messenger.PinnedMessageByChatID(chatID, cursor, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ApplicationPinnedMessagesResponse{
|
||||
Messages: messages,
|
||||
Cursor: cursor,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (api *PublicAPI) StartMessenger() (*protocol.MessengerResponse, error) {
|
||||
return api.service.StartMessenger()
|
||||
}
|
||||
|
@ -487,6 +504,10 @@ func (api *PublicAPI) SendChatMessages(ctx context.Context, messages []*common.M
|
|||
return api.service.messenger.SendChatMessages(ctx, messages)
|
||||
}
|
||||
|
||||
func (api *PublicAPI) SendPinMessage(ctx context.Context, message *common.PinMessage) (*protocol.MessengerResponse, error) {
|
||||
return api.service.messenger.SendPinMessage(ctx, message)
|
||||
}
|
||||
|
||||
func (api *PublicAPI) RequestTransaction(ctx context.Context, chatID, value, contract, address string) (*protocol.MessengerResponse, error) {
|
||||
return api.service.messenger.RequestTransaction(ctx, chatID, value, contract, address)
|
||||
}
|
||||
|
|
|
@ -507,6 +507,10 @@ func (api *NimbusPublicAPI) SendChatMessage(ctx context.Context, message *common
|
|||
return api.service.messenger.SendChatMessage(ctx, message)
|
||||
}
|
||||
|
||||
func (api *NimbusPublicAPI) SendPinMessage(ctx context.Context, message *common.PinMessage) (*protocol.MessengerResponse, error) {
|
||||
return api.service.messenger.SendPinMessage(ctx, message)
|
||||
}
|
||||
|
||||
func (api *NimbusPublicAPI) ReSendChatMessage(ctx context.Context, messageID string) error {
|
||||
return api.service.messenger.ReSendChatMessage(ctx, messageID)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue