-
Notifications
You must be signed in to change notification settings - Fork 1
/
userDBCache.go
105 lines (83 loc) · 2.68 KB
/
userDBCache.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
package wsHelpers
import (
"context"
"sync"
"github.com/pixlise/core/v4/api/dbCollections"
"github.com/pixlise/core/v4/core/timestamper"
protos "github.com/pixlise/core/v4/generated-protos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
func GetDBUser(userId string, db *mongo.Database) (*protos.UserDBItem, error) {
// opts := options.FindOne().SetProjection(bson.D{
// {Key: "_id", Value: true},
// {Key: "info.id", Value: true},
// {Key: "info.name", Value: true},
// {Key: "info.email", Value: true},
// {Key: "datacollectionversion", Value: true},
// {Key: "notificationsettings", Value: true},
// })
userResult := db.Collection(dbCollections.UsersName).FindOne(context.TODO(), bson.M{"_id": userId})
if userResult.Err() != nil {
return nil, userResult.Err()
}
userDBItem := protos.UserDBItem{}
err := userResult.Decode(&userDBItem)
if err != nil {
return nil, err
}
if userDBItem.NotificationSettings == nil {
userDBItem.NotificationSettings = &protos.UserNotificationSettings{
TopicSettings: map[string]protos.NotificationMethod{},
}
}
return &userDBItem, nil
}
// This uses a cache as it may be reading the same thing many times in bursts.
// Cache is told when user info changes, and also has a time stamp so we don't
// keep reading from cache forever
type userCacheItem struct {
cachedInfo *protos.UserInfo
timestampUnixSec int64
}
var userInfoCache = map[string]userCacheItem{}
var userInfoCacheLock = sync.Mutex{}
const maxUserCacheAgeSec = 60 * 5
func getUserInfo(userId string, db *mongo.Database, ts timestamper.ITimeStamper) (*protos.UserInfo, error) {
user := getUserInfoFromCache(userId, ts)
if user != nil {
return user, nil
}
userDBItem, err := GetDBUser(userId, db)
if err != nil {
return nil, err
}
// Cache this for future
userInfoCacheLock.Lock()
defer userInfoCacheLock.Unlock()
userInfoCache[userId] = userCacheItem{
cachedInfo: userDBItem.Info,
timestampUnixSec: ts.GetTimeNowSec(),
}
return userDBItem.Info, nil
}
func getUserInfoFromCache(userId string, ts timestamper.ITimeStamper) *protos.UserInfo {
now := ts.GetTimeNowSec()
userInfoCacheLock.Lock()
defer userInfoCacheLock.Unlock()
if user, ok := userInfoCache[userId]; ok {
// We found cached item, use if not too old
if user.timestampUnixSec > now-maxUserCacheAgeSec {
return user.cachedInfo
}
// Otherwise, do a DB read again and overwrite our cached item
}
return nil
}
func NotifyUserInfoChange(userId string) {
userInfoCacheLock.Lock()
defer userInfoCacheLock.Unlock()
// Delete this item from our cache
// This will ensure it is read fresh the next time this user is accessed
delete(userInfoCache, userId)
}