mirror of
https://github.com/matrix-org/sliding-sync.git
synced 2025-03-10 13:37:11 +00:00
144 lines
3.3 KiB
Go
144 lines
3.3 KiB
Go
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}
|
|
}
|