-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsync.go
128 lines (107 loc) · 4.04 KB
/
sync.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
package linkpearl
import (
"context"
"strings"
"time"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
)
// OnEventType allows callers to be notified when there are new events for the given event type.
// There are no duplicate checks.
func (l *Linkpearl) OnEventType(eventType event.Type, callback mautrix.EventHandler) {
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEventType(eventType, callback) //nolint:forcetypeassert,errcheck // we know it's an ExtensibleSyncer
}
// OnSync shortcut to mautrix.DefaultSyncer.OnSync
func (l *Linkpearl) OnSync(callback mautrix.SyncHandler) {
l.api.Syncer.(mautrix.ExtensibleSyncer).OnSync(callback) //nolint:forcetypeassert,errcheck // we know it's an ExtensibleSyncer
}
// OnEvent shortcut to mautrix.DefaultSyncer.OnEvent
func (l *Linkpearl) OnEvent(callback mautrix.EventHandler) {
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEvent(callback) //nolint:forcetypeassert,errcheck // we know it's an ExtensibleSyncer
}
func (l *Linkpearl) initSync() {
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEventType( //nolint:forcetypeassert,errcheck // we know it's an ExtensibleSyncer
event.StateEncryption,
func(ctx context.Context, evt *event.Event) {
go l.onEncryption(ctx, evt)
},
)
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEventType( //nolint:forcetypeassert,errcheck // we know it's an ExtensibleSyncer
event.StateMember,
func(ctx context.Context, evt *event.Event) {
go l.onMembership(ctx, evt)
},
)
}
func (l *Linkpearl) onMembership(ctx context.Context, evt *event.Event) {
l.ch.Machine().HandleMemberEvent(ctx, evt)
if err := l.api.StateStore.SetMembership(ctx, evt.RoomID, id.UserID(evt.GetStateKey()), evt.Content.AsMember().Membership); err != nil {
l.log.Error().Err(err).Str("roomID", evt.RoomID.String()).Str("userID", evt.GetStateKey()).Msg("cannot set membership")
}
// potentially autoaccept invites
l.onInvite(ctx, evt)
// autoleave empty rooms
l.onEmpty(ctx, evt)
}
func (l *Linkpearl) onInvite(ctx context.Context, evt *event.Event) {
userID := l.api.UserID.String()
invite := evt.Content.AsMember().Membership == event.MembershipInvite
if !invite || evt.GetStateKey() != userID {
return
}
if l.joinPermit(ctx, evt) {
l.tryJoin(ctx, evt.RoomID, 0)
return
}
l.tryLeave(ctx, evt.RoomID, 0)
}
func (l *Linkpearl) tryJoin(ctx context.Context, roomID id.RoomID, retry int) {
if retry >= l.maxretries {
return
}
_, err := l.api.JoinRoom(ctx, roomID.String(), nil)
err = UnwrapError(err)
if err != nil {
l.log.Error().Err(err).Str("roomID", roomID.String()).Msg("cannot join room")
if strings.HasPrefix(err.Error(), "403") || strings.HasPrefix(err.Error(), "M_FORBIDDEN") { // no permission to join, no need to retry
return
}
time.Sleep(5 * time.Second)
l.log.Error().Err(err).Str("roomID", roomID.String()).Int("retry", retry+1).Msg("trying to join again")
l.tryJoin(ctx, roomID, retry+1)
}
}
func (l *Linkpearl) tryLeave(ctx context.Context, roomID id.RoomID, retry int) {
if retry >= l.maxretries {
return
}
_, err := l.api.LeaveRoom(ctx, roomID)
err = UnwrapError(err)
if err != nil {
l.log.Error().Err(err).Str("roomID", roomID.String()).Msg("cannot leave room")
time.Sleep(5 * time.Second)
l.log.Error().Err(err).Str("roomID", roomID.String()).Int("retry", retry+1).Msg("trying to leave again")
l.tryLeave(ctx, roomID, retry+1)
}
}
func (l *Linkpearl) onEmpty(ctx context.Context, evt *event.Event) {
if !l.autoleave {
return
}
members, err := l.api.StateStore.GetRoomJoinedOrInvitedMembers(ctx, evt.RoomID)
err = UnwrapError(err)
if err != nil {
l.log.Error().Err(err).Str("roomID", evt.RoomID.String()).Msg("cannot get joined or invited members")
return
}
if len(members) >= 1 && members[0] != l.api.UserID {
return
}
l.tryLeave(ctx, evt.RoomID, 0)
}
func (l *Linkpearl) onEncryption(ctx context.Context, evt *event.Event) {
if err := l.api.StateStore.SetEncryptionEvent(ctx, evt.RoomID, evt.Content.AsEncryption()); err != nil {
l.log.Error().Err(err).Str("roomID", evt.RoomID.String()).Msg("cannot set encryption event")
}
}