timeline
This commit is contained in:
parent
fa136ebaa7
commit
6f207def2b
|
@ -29,6 +29,7 @@ const (
|
||||||
ChatTypePublic
|
ChatTypePublic
|
||||||
ChatTypePrivateGroupChat
|
ChatTypePrivateGroupChat
|
||||||
ChatTypeProfile
|
ChatTypeProfile
|
||||||
|
ChatTypeTimeline
|
||||||
)
|
)
|
||||||
|
|
||||||
type Chat struct {
|
type Chat struct {
|
||||||
|
@ -99,6 +100,10 @@ func (c *Chat) ProfileUpdates() bool {
|
||||||
return c.ChatType == ChatTypeProfile
|
return c.ChatType == ChatTypeProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Chat) Timeline() bool {
|
||||||
|
return c.ChatType == ChatTypeTimeline
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Chat) OneToOne() bool {
|
func (c *Chat) OneToOne() bool {
|
||||||
return c.ChatType == ChatTypeOneToOne
|
return c.ChatType == ChatTypeOneToOne
|
||||||
}
|
}
|
||||||
|
|
|
@ -530,6 +530,78 @@ func (db sqlitePersistence) MessageByChatID(chatID string, currCursor string, li
|
||||||
return result, newCursor, nil
|
return result, newCursor, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (db sqlitePersistence) MessageByChatIDs(chatIDs []string, currCursor string, limit int) ([]*common.Message, string, error) {
|
||||||
|
cursorWhere := ""
|
||||||
|
if currCursor != "" {
|
||||||
|
cursorWhere = "AND cursor <= ?"
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
substr('0000000000000000000000000000000000000000000000000000000000000000' || m1.clock_value, -64, 64) || m1.id as cursor
|
||||||
|
FROM
|
||||||
|
user_messages m1
|
||||||
|
LEFT JOIN
|
||||||
|
user_messages m2
|
||||||
|
ON
|
||||||
|
m1.response_to = m2.id
|
||||||
|
|
||||||
|
LEFT JOIN
|
||||||
|
contacts c
|
||||||
|
ON
|
||||||
|
|
||||||
|
m1.source = c.id
|
||||||
|
WHERE
|
||||||
|
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.Message
|
||||||
|
cursors []string
|
||||||
|
)
|
||||||
|
for rows.Next() {
|
||||||
|
var (
|
||||||
|
message common.Message
|
||||||
|
cursor string
|
||||||
|
)
|
||||||
|
if err := db.tableUserMessagesScanAllFields(rows, &message, &cursor); err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
result = append(result, &message)
|
||||||
|
cursors = append(cursors, cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
var newCursor string
|
||||||
|
if len(result) > limit {
|
||||||
|
newCursor = cursors[limit]
|
||||||
|
result = result[:limit]
|
||||||
|
}
|
||||||
|
return result, newCursor, nil
|
||||||
|
}
|
||||||
|
|
||||||
// EmojiReactionsByChatID returns the emoji reactions for the queried messages, up to a maximum of 100, as it's a potentially unbound number.
|
// EmojiReactionsByChatID returns the emoji reactions for the queried messages, up to a maximum of 100, as it's a potentially unbound number.
|
||||||
// NOTE: This is not completely accurate, as the messages in the database might have change since the last call to `MessageByChatID`.
|
// NOTE: This is not completely accurate, as the messages in the database might have change since the last call to `MessageByChatID`.
|
||||||
func (db sqlitePersistence) EmojiReactionsByChatID(chatID string, currCursor string, limit int) ([]*EmojiReaction, error) {
|
func (db sqlitePersistence) EmojiReactionsByChatID(chatID string, currCursor string, limit int) ([]*EmojiReaction, error) {
|
||||||
|
|
|
@ -673,7 +673,7 @@ func (m *Messenger) Join(chat Chat) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return m.transport.JoinGroup(members)
|
return m.transport.JoinGroup(members)
|
||||||
case ChatTypePublic, ChatTypeProfile:
|
case ChatTypePublic, ChatTypeProfile, ChatTypeTimeline:
|
||||||
return m.transport.JoinPublic(chat.ID)
|
return m.transport.JoinPublic(chat.ID)
|
||||||
default:
|
default:
|
||||||
return errors.New("chat is neither public nor private")
|
return errors.New("chat is neither public nor private")
|
||||||
|
@ -696,7 +696,7 @@ func (m *Messenger) Leave(chat Chat) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return m.transport.LeaveGroup(members)
|
return m.transport.LeaveGroup(members)
|
||||||
case ChatTypePublic, ChatTypeProfile:
|
case ChatTypePublic, ChatTypeProfile, ChatTypeTimeline:
|
||||||
return m.transport.LeavePublic(chat.Name)
|
return m.transport.LeavePublic(chat.Name)
|
||||||
default:
|
default:
|
||||||
return errors.New("chat is neither public nor private")
|
return errors.New("chat is neither public nor private")
|
||||||
|
@ -2587,7 +2587,22 @@ func (m *Messenger) MessagesExist(ids []string) (map[string]bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) MessageByChatID(chatID, cursor string, limit int) ([]*common.Message, string, error) {
|
func (m *Messenger) MessageByChatID(chatID, cursor string, limit int) ([]*common.Message, string, error) {
|
||||||
return m.persistence.MessageByChatID(chatID, cursor, limit)
|
chat, err := m.persistence.Chat(chatID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if chat.Timeline() {
|
||||||
|
var chatIDs = []string{"@" + contactIDFromPublicKey(&m.identity.PublicKey)}
|
||||||
|
for _, contact := range m.allContacts {
|
||||||
|
if contact.IsAdded() {
|
||||||
|
chatIDs = append(chatIDs, "@"+contact.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.persistence.MessageByChatIDs(chatIDs, cursor, limit)
|
||||||
|
} else {
|
||||||
|
return m.persistence.MessageByChatID(chatID, cursor, limit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) SaveMessages(messages []*common.Message) error {
|
func (m *Messenger) SaveMessages(messages []*common.Message) error {
|
||||||
|
|
Loading…
Reference in New Issue