-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathreceipts.go
129 lines (117 loc) · 4.35 KB
/
receipts.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package extensions
import (
"context"
"encoding/json"
"github.com/matrix-org/sliding-sync/internal"
"github.com/matrix-org/sliding-sync/state"
"github.com/matrix-org/sliding-sync/sync3/caches"
)
// Client created request params
type ReceiptsRequest struct {
Core
}
func (r *ReceiptsRequest) Name() string {
return "ReceiptsRequest"
}
// Server response
type ReceiptsResponse struct {
// room_id -> m.receipt ephemeral event
Rooms map[string]json.RawMessage `json:"rooms,omitempty"`
}
func (r *ReceiptsResponse) HasData(isInitial bool) bool {
if isInitial {
return true
}
return len(r.Rooms) > 0
}
func (r *ReceiptsRequest) AppendLive(ctx context.Context, res *Response, extCtx Context, up caches.Update) {
switch update := up.(type) {
case *caches.ReceiptUpdate:
if !r.RoomInScope(update.RoomID(), extCtx) {
break
}
// a live receipt event happened, send this back
if res.Receipts == nil {
edu, err := state.PackReceiptsIntoEDU([]internal.Receipt{update.Receipt})
if err != nil {
logger.Err(err).Str("user", extCtx.UserID).Str("room", update.Receipt.RoomID).Msg("failed to pack receipt into new edu")
internal.GetSentryHubFromContextOrDefault(ctx).CaptureException(err)
return
}
res.Receipts = &ReceiptsResponse{
Rooms: map[string]json.RawMessage{
update.RoomID(): edu,
},
}
} else if res.Receipts.Rooms[update.RoomID()] == nil {
// we have receipts already, but not for this room
edu, err := state.PackReceiptsIntoEDU([]internal.Receipt{update.Receipt})
if err != nil {
logger.Err(err).Str("user", extCtx.UserID).Str("room", update.Receipt.RoomID).Msg("failed to pack receipt into edu")
internal.GetSentryHubFromContextOrDefault(ctx).CaptureException(err)
return
}
res.Receipts.Rooms[update.RoomID()] = edu
} else {
// we have receipts already for this room.
// aggregate receipts: we need to unpack then repack annoyingly.
pub, priv, err := state.UnpackReceiptsFromEDU(update.RoomID(), res.Receipts.Rooms[update.RoomID()])
if err != nil {
logger.Err(err).Str("user", extCtx.UserID).Str("room", update.Receipt.RoomID).Msg("failed to pack receipt into edu")
internal.GetSentryHubFromContextOrDefault(ctx).CaptureException(err)
return
}
receipts := append(pub, priv...)
// add the live one
receipts = append(receipts, update.Receipt)
edu, err := state.PackReceiptsIntoEDU(receipts)
if err != nil {
logger.Err(err).Str("user", extCtx.UserID).Str("room", update.Receipt.RoomID).Msg("failed to pack receipt into edu")
internal.GetSentryHubFromContextOrDefault(ctx).CaptureException(err)
return
}
res.Receipts.Rooms[update.RoomID()] = edu
}
}
}
func (r *ReceiptsRequest) ProcessInitial(ctx context.Context, res *Response, extCtx Context) {
// grab receipts for all timelines for all the rooms we're going to return
rooms := make(map[string]json.RawMessage)
interestedRoomIDs := make([]string, 0, len(extCtx.RoomIDToTimeline))
otherReceipts := make(map[string][]internal.Receipt)
for roomID, timeline := range extCtx.RoomIDToTimeline {
if !r.RoomInScope(roomID, extCtx) {
continue
}
receipts, err := extCtx.Store.ReceiptTable.SelectReceiptsForEvents(roomID, timeline)
if err != nil {
logger.Err(err).Str("user", extCtx.UserID).Str("room", roomID).Msg("failed to SelectReceiptsForEvents")
internal.GetSentryHubFromContextOrDefault(ctx).CaptureException(err)
continue
}
otherReceipts[roomID] = receipts
interestedRoomIDs = append(interestedRoomIDs, roomID)
}
// single shot query to pull out our own receipts for these rooms to always include our own receipts
ownReceipts, err := extCtx.Store.ReceiptTable.SelectReceiptsForUser(interestedRoomIDs, extCtx.UserID)
if err != nil {
logger.Err(err).Str("user", extCtx.UserID).Strs("rooms", interestedRoomIDs).Msg("failed to SelectReceiptsForUser")
internal.GetSentryHubFromContextOrDefault(ctx).CaptureException(err)
return
}
// move all own receipts into other receipts so we don't need to handle cases where receipts are in one map but not the other
for roomID, ownRecs := range ownReceipts {
otherReceipts[roomID] = append(otherReceipts[roomID], ownRecs...)
}
for roomID, receipts := range otherReceipts {
if len(receipts) == 0 {
continue
}
rooms[roomID], _ = state.PackReceiptsIntoEDU(receipts)
}
if len(rooms) > 0 {
res.Receipts = &ReceiptsResponse{
Rooms: rooms,
}
}
}