-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathclient_cache.go
More file actions
140 lines (130 loc) · 3.18 KB
/
client_cache.go
File metadata and controls
140 lines (130 loc) · 3.18 KB
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
package agentremote
import (
"context"
"fmt"
"maps"
"sync"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid"
)
// EnsureClientMap initializes the connector client cache map when needed.
func EnsureClientMap(mu *sync.Mutex, clients *map[networkid.UserLoginID]bridgev2.NetworkAPI) {
if mu == nil || clients == nil {
return
}
mu.Lock()
if *clients == nil {
*clients = make(map[networkid.UserLoginID]bridgev2.NetworkAPI)
}
mu.Unlock()
}
// LoadOrCreateClient returns a cached client if reusable, otherwise creates and caches a new one.
func LoadOrCreateClient(
mu *sync.Mutex,
clients map[networkid.UserLoginID]bridgev2.NetworkAPI,
loginID networkid.UserLoginID,
reuse func(existing bridgev2.NetworkAPI) bool,
create func() (bridgev2.NetworkAPI, error),
) (bridgev2.NetworkAPI, error) {
if mu == nil {
return create()
}
mu.Lock()
defer mu.Unlock()
if existing := clients[loginID]; existing != nil {
if reuse != nil && reuse(existing) {
return existing, nil
}
delete(clients, loginID)
}
client, err := create()
if err != nil {
return nil, err
}
clients[loginID] = client
return client, nil
}
// LoadOrCreateTypedClient wraps LoadOrCreateClient with typed reuse/create callbacks.
func LoadOrCreateTypedClient[T bridgev2.NetworkAPI](
mu *sync.Mutex,
clients map[networkid.UserLoginID]bridgev2.NetworkAPI,
login *bridgev2.UserLogin,
reuse func(T, *bridgev2.UserLogin),
create func() (T, error),
) (T, error) {
var zero T
if login == nil {
return zero, fmt.Errorf("login is nil")
}
client, err := LoadOrCreateClient(
mu,
clients,
login.ID,
func(existingAPI bridgev2.NetworkAPI) bool {
existing, ok := existingAPI.(T)
if !ok {
return false
}
if reuse != nil {
reuse(existing, login)
}
login.Client = existing
return true
},
func() (bridgev2.NetworkAPI, error) {
client, err := create()
if err != nil {
return nil, err
}
login.Client = client
return client, nil
},
)
if err != nil {
return zero, err
}
typed, ok := client.(T)
if !ok {
return zero, fmt.Errorf("unexpected client type %T", client)
}
return typed, nil
}
// RemoveClientFromCache removes a client from the cache by login ID.
func RemoveClientFromCache(
mu *sync.Mutex,
clients map[networkid.UserLoginID]bridgev2.NetworkAPI,
loginID networkid.UserLoginID,
) {
if mu == nil {
return
}
mu.Lock()
delete(clients, loginID)
mu.Unlock()
}
// StopClients disconnects all cached clients that expose Disconnect().
func StopClients(mu *sync.Mutex, clients *map[networkid.UserLoginID]bridgev2.NetworkAPI) {
if mu == nil || clients == nil {
return
}
mu.Lock()
cloned := maps.Clone(*clients)
mu.Unlock()
for _, client := range cloned {
client.Disconnect()
}
}
// PrimeUserLoginCache preloads all logins into bridgev2's in-memory user/login caches.
func PrimeUserLoginCache(ctx context.Context, br *bridgev2.Bridge) {
if br == nil || br.DB == nil || br.DB.UserLogin == nil {
return
}
userIDs, err := br.DB.UserLogin.GetAllUserIDsWithLogins(ctx)
if err != nil {
br.Log.Warn().Err(err).Msg("Failed to list users with logins for cache priming")
return
}
for _, mxid := range userIDs {
_, _ = br.GetUserByMXID(ctx, mxid)
}
}