forked from matrix-org/sliding-sync
-
Notifications
You must be signed in to change notification settings - Fork 0
/
response.go
143 lines (123 loc) · 3.26 KB
/
response.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package sync3
import (
"encoding/json"
"strconv"
"github.com/matrix-org/sliding-sync/sync3/extensions"
"github.com/tidwall/gjson"
)
const (
OpSync = "SYNC"
OpInvalidate = "INVALIDATE"
OpInsert = "INSERT"
OpDelete = "DELETE"
)
type Response struct {
Lists map[string]ResponseList `json:"lists"`
Rooms map[string]Room `json:"rooms"`
Extensions extensions.Response `json:"extensions"`
Pos string `json:"pos"`
TxnID string `json:"txn_id,omitempty"`
}
type ResponseList struct {
Ops []ResponseOp `json:"ops,omitempty"`
Count int `json:"count"`
}
func (r *Response) PosInt() int64 {
p, _ := strconv.ParseInt(r.Pos, 10, 64)
return p
}
func (r *Response) ListOps() int {
num := 0
for _, l := range r.Lists {
if len(l.Ops) > 0 {
num = len(l.Ops)
}
}
return num
}
func (r *Response) RoomIDsToTimelineEventIDs() map[string][]string {
includedRoomIDs := make(map[string][]string)
for roomID := range r.Rooms {
eventIDs := make([]string, len(r.Rooms[roomID].Timeline))
for i := range eventIDs {
eventIDs[i] = gjson.ParseBytes(r.Rooms[roomID].Timeline[i]).Get("event_id").Str
}
includedRoomIDs[roomID] = eventIDs
}
return includedRoomIDs
}
// Custom unmarshal so we can dynamically create the right ResponseOp for Ops
func (r *Response) UnmarshalJSON(b []byte) error {
temporary := struct {
Rooms map[string]Room `json:"rooms"`
Lists map[string]struct {
Ops []json.RawMessage `json:"ops"`
Count int `json:"count"`
} `json:"lists"`
Extensions extensions.Response `json:"extensions"`
Pos string `json:"pos"`
TxnID string `json:"txn_id,omitempty"`
}{}
if err := json.Unmarshal(b, &temporary); err != nil {
return err
}
r.Rooms = temporary.Rooms
r.Pos = temporary.Pos
r.TxnID = temporary.TxnID
r.Extensions = temporary.Extensions
r.Lists = make(map[string]ResponseList, len(temporary.Lists))
for listKey, l := range temporary.Lists {
var list ResponseList
list.Count = l.Count
for _, op := range l.Ops {
if gjson.GetBytes(op, "range").Exists() {
var oper ResponseOpRange
if err := json.Unmarshal(op, &oper); err != nil {
return err
}
list.Ops = append(list.Ops, &oper)
} else {
var oper ResponseOpSingle
if err := json.Unmarshal(op, &oper); err != nil {
return err
}
list.Ops = append(list.Ops, &oper)
}
}
r.Lists[listKey] = list
}
return nil
}
type ResponseOp interface {
Op() string
// which rooms are we giving data about
IncludedRoomIDs() []string
}
type ResponseOpRange struct {
Operation string `json:"op"`
Range [2]int64 `json:"range,omitempty"`
RoomIDs []string `json:"room_ids,omitempty"`
}
func (r *ResponseOpRange) Op() string {
return r.Operation
}
func (r *ResponseOpRange) IncludedRoomIDs() []string {
if r.Op() == OpInvalidate {
return nil // the rooms are being excluded
}
return r.RoomIDs
}
type ResponseOpSingle struct {
Operation string `json:"op"`
Index *int `json:"index,omitempty"` // 0 is a valid value, hence *int
RoomID string `json:"room_id,omitempty"`
}
func (r *ResponseOpSingle) Op() string {
return r.Operation
}
func (r *ResponseOpSingle) IncludedRoomIDs() []string {
if r.Op() == OpDelete || r.RoomID == "" {
return nil // the room is being excluded
}
return []string{r.RoomID}
}