/
cache.go
executable file
·123 lines (116 loc) · 2.61 KB
/
cache.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
package mongo
import (
"context"
"fmt"
"time"
"github.com/pkg/errors"
"github.com/thavlik/t4vd/seer/pkg/infocache"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func getRecency(
col *mongo.Collection,
id string,
) (time.Time, error) {
doc := make(map[string]interface{})
if err := col.FindOne(
context.Background(),
map[string]interface{}{
"_id": id,
},
).Decode(&doc); err == mongo.ErrNoDocuments {
return time.Time{}, infocache.ErrCacheUnavailable
} else if err != nil {
return time.Time{}, errors.Wrap(err, "mongo")
}
v, ok := doc["updated"].(int64)
if !ok {
return time.Time{}, fmt.Errorf("invalid type for field 'updated': %T", doc["updated"])
}
updated := time.Unix(0, v)
return updated, nil
}
func checkCacheRecency(
col *mongo.Collection,
id string,
) (bool, error) {
updated, err := getRecency(col, id)
if err == infocache.ErrCacheUnavailable {
return false, nil
} else if err != nil {
return false, errors.Wrap(err, "getCacheRecency")
}
return time.Since(updated) < infocache.CacheRecency, nil
}
func getVideoIDs(
ctx context.Context,
joins *mongo.Collection,
keyName string,
value string,
) ([]string, error) {
cursor, err := joins.Find(
ctx,
map[string]interface{}{
keyName: value,
})
if err != nil {
return nil, errors.Wrap(err, "mongo")
}
var docs []map[string]interface{}
if err := cursor.All(ctx, &docs); err != nil {
return nil, errors.Wrap(err, "mongo")
}
if len(docs) == 0 {
return nil, infocache.ErrCacheUnavailable
}
videoIDs := make([]string, len(docs))
for i, doc := range docs {
videoIDs[i] = doc["v"].(string)
}
return videoIDs, nil
}
func refreshCache(
col *mongo.Collection,
id string,
timestamp time.Time,
) error {
if _, err := col.UpdateOne(
context.Background(),
map[string]interface{}{
"_id": id,
},
map[string]interface{}{
"$set": map[string]interface{}{
"updated": timestamp.UnixNano(),
},
},
options.Update().SetUpsert(true),
); err != nil {
return errors.Wrap(err, "mongo")
}
return nil
}
func setVideoIDs(
joins *mongo.Collection,
originKey string,
originValue string,
videoIDs []string,
) error {
operations := make([]mongo.WriteModel, len(videoIDs)+1)
operations[0] = mongo.NewDeleteManyModel().
SetFilter(map[string]interface{}{
originKey: originValue,
})
for i, videoID := range videoIDs {
operations[i+1] = mongo.NewInsertOneModel().
SetDocument(map[string]interface{}{
originKey: originValue,
"v": videoID,
})
}
_, err := joins.BulkWrite(context.Background(), operations)
if err != nil {
return errors.Wrap(err, "mongo")
}
return nil
}