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
|
// Copyright (c) 2020 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package event
import (
"encoding/json"
"time"
"maunium.net/go/mautrix/id"
)
// TypingEventContent represents the content of a m.typing ephemeral event.
// https://spec.matrix.org/v1.2/client-server-api/#mtyping
type TypingEventContent struct {
UserIDs []id.UserID `json:"user_ids"`
}
// ReceiptEventContent represents the content of a m.receipt ephemeral event.
// https://spec.matrix.org/v1.2/client-server-api/#mreceipt
type ReceiptEventContent map[id.EventID]Receipts
func (rec ReceiptEventContent) Set(evtID id.EventID, receiptType ReceiptType, userID id.UserID, receipt ReadReceipt) {
rec.GetOrCreate(evtID).GetOrCreate(receiptType).Set(userID, receipt)
}
func (rec ReceiptEventContent) GetOrCreate(evt id.EventID) Receipts {
receipts, ok := rec[evt]
if !ok {
receipts = make(Receipts)
rec[evt] = receipts
}
return receipts
}
type ReceiptType string
const (
ReceiptTypeRead ReceiptType = "m.read"
ReceiptTypeReadPrivate ReceiptType = "m.read.private"
)
type Receipts map[ReceiptType]UserReceipts
func (rps Receipts) GetOrCreate(receiptType ReceiptType) UserReceipts {
read, ok := rps[receiptType]
if !ok {
read = make(UserReceipts)
rps[receiptType] = read
}
return read
}
type UserReceipts map[id.UserID]ReadReceipt
func (ur UserReceipts) Set(userID id.UserID, receipt ReadReceipt) {
ur[userID] = receipt
}
type ThreadID = id.EventID
const ReadReceiptThreadMain ThreadID = "main"
type ReadReceipt struct {
Timestamp time.Time
// Thread ID for thread-specific read receipts from MSC3771
ThreadID ThreadID
// Extra contains any unknown fields in the read receipt event.
// Most servers don't allow clients to set them, so this will be empty in most cases.
Extra map[string]interface{}
}
func (rr *ReadReceipt) UnmarshalJSON(data []byte) error {
// Hacky compatibility hack against crappy clients that send double-encoded read receipts.
// TODO is this actually needed? clients can't currently set custom content in receipts 🤔
if data[0] == '"' && data[len(data)-1] == '"' {
var strData string
err := json.Unmarshal(data, &strData)
if err != nil {
return err
}
data = []byte(strData)
}
var parsed map[string]interface{}
err := json.Unmarshal(data, &parsed)
if err != nil {
return err
}
threadID, _ := parsed["thread_id"].(string)
ts, tsOK := parsed["ts"].(float64)
delete(parsed, "thread_id")
delete(parsed, "ts")
*rr = ReadReceipt{
ThreadID: ThreadID(threadID),
Extra: parsed,
}
if tsOK {
rr.Timestamp = time.UnixMilli(int64(ts))
}
return nil
}
func (rr ReadReceipt) MarshalJSON() ([]byte, error) {
data := rr.Extra
if data == nil {
data = make(map[string]interface{})
}
if rr.ThreadID != "" {
data["thread_id"] = rr.ThreadID
}
if !rr.Timestamp.IsZero() {
data["ts"] = rr.Timestamp.UnixMilli()
}
return json.Marshal(data)
}
type Presence string
const (
PresenceOnline Presence = "online"
PresenceOffline Presence = "offline"
PresenceUnavailable Presence = "unavailable"
)
// PresenceEventContent represents the content of a m.presence ephemeral event.
// https://spec.matrix.org/v1.2/client-server-api/#mpresence
type PresenceEventContent struct {
Presence Presence `json:"presence"`
Displayname string `json:"displayname,omitempty"`
AvatarURL id.ContentURIString `json:"avatar_url,omitempty"`
LastActiveAgo int64 `json:"last_active_ago,omitempty"`
CurrentlyActive bool `json:"currently_active,omitempty"`
StatusMessage string `json:"status_msg,omitempty"`
}
|