forked from mautrix/go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstore.go
162 lines (141 loc) · 4.41 KB
/
store.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package mautrix
import (
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
)
// Storer is an interface which must be satisfied to store client data.
//
// You can either write a struct which persists this data to disk, or you can use the
// provided "InMemoryStore" which just keeps data around in-memory which is lost on
// restarts.
type Storer interface {
SaveFilterID(userID id.UserID, filterID string)
LoadFilterID(userID id.UserID) string
SaveNextBatch(userID id.UserID, nextBatchToken string)
LoadNextBatch(userID id.UserID) string
SaveRoom(room *Room)
LoadRoom(roomID id.RoomID) *Room
}
// InMemoryStore implements the Storer interface.
//
// Everything is persisted in-memory as maps. It is not safe to load/save filter IDs
// or next batch tokens on any goroutine other than the syncing goroutine: the one
// which called Client.Sync().
type InMemoryStore struct {
Filters map[id.UserID]string
NextBatch map[id.UserID]string
Rooms map[id.RoomID]*Room
}
// SaveFilterID to memory.
func (s *InMemoryStore) SaveFilterID(userID id.UserID, filterID string) {
s.Filters[userID] = filterID
}
// LoadFilterID from memory.
func (s *InMemoryStore) LoadFilterID(userID id.UserID) string {
return s.Filters[userID]
}
// SaveNextBatch to memory.
func (s *InMemoryStore) SaveNextBatch(userID id.UserID, nextBatchToken string) {
s.NextBatch[userID] = nextBatchToken
}
// LoadNextBatch from memory.
func (s *InMemoryStore) LoadNextBatch(userID id.UserID) string {
return s.NextBatch[userID]
}
// SaveRoom to memory.
func (s *InMemoryStore) SaveRoom(room *Room) {
s.Rooms[room.ID] = room
}
// LoadRoom from memory.
func (s *InMemoryStore) LoadRoom(roomID id.RoomID) *Room {
return s.Rooms[roomID]
}
// UpdateState stores a state event. This can be passed to DefaultSyncer.OnEvent to keep all room state cached.
func (s *InMemoryStore) UpdateState(_ EventSource, evt *event.Event) {
if !evt.Type.IsState() {
return
}
room := s.LoadRoom(evt.RoomID)
if room == nil {
room = NewRoom(evt.RoomID)
s.SaveRoom(room)
}
room.UpdateState(evt)
}
// NewInMemoryStore constructs a new InMemoryStore.
func NewInMemoryStore() *InMemoryStore {
return &InMemoryStore{
Filters: make(map[id.UserID]string),
NextBatch: make(map[id.UserID]string),
Rooms: make(map[id.RoomID]*Room),
}
}
// AccountDataStore uses account data to store the next batch token, and
// reuses the InMemoryStore for all other operations.
type AccountDataStore struct {
*InMemoryStore
eventType string
client *Client
}
type accountData struct {
NextBatch string `json:"next_batch"`
}
// SaveNextBatch to account data.
func (s *AccountDataStore) SaveNextBatch(userID id.UserID, nextBatchToken string) {
if userID.String() != s.client.UserID.String() {
panic("AccountDataStore must only be used with bots")
}
data := accountData{
NextBatch: nextBatchToken,
}
err := s.client.SetAccountData(s.eventType, data)
if err != nil {
if s.client.Logger != nil {
s.client.Logger.Debugfln("failed to save next batch token to account data: %s", err.Error())
}
}
}
// LoadNextBatch from account data.
func (s *AccountDataStore) LoadNextBatch(userID id.UserID) string {
if userID.String() != s.client.UserID.String() {
panic("AccountDataStore must only be used with bots")
}
data := &accountData{}
err := s.client.GetAccountData(s.eventType, data)
if err != nil {
if s.client.Logger != nil {
s.client.Logger.Debugfln("failed to load next batch token to account data: %s", err.Error())
}
return ""
}
return data.NextBatch
}
// NewAccountDataStore returns a new AccountDataStore, which stores
// the next_batch token as a custom event in account data in the
// homeserver.
//
// AccountDataStore is only appropriate for bots, not appservices.
//
// eventType should be a reversed DNS name like tld.domain.sub.internal and
// must be unique for a client. The data stored in it is considered internal
// and must not be modified through outside means. You should also add a filter
// for account data changes of this event type, to avoid ending up in a sync
// loop:
//
// mautrix.Filter{
// AccountData: mautrix.FilterPart{
// Limit: 20,
// NotTypes: []event.Type{
// event.NewEventType(eventType),
// },
// },
// }
// mautrix.Client.CreateFilter(...)
//
func NewAccountDataStore(eventType string, client *Client) *AccountDataStore {
return &AccountDataStore{
InMemoryStore: NewInMemoryStore(),
eventType: eventType,
client: client,
}
}