-
-
Notifications
You must be signed in to change notification settings - Fork 253
/
check.go
204 lines (166 loc) · 4.38 KB
/
check.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package handlers
import (
"container/heap"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"github.com/dgraph-io/badger/v2"
"github.com/gojp/goreportcard/download"
)
const (
// RepoPrefix is the badger prefix for repos
RepoPrefix string = "repos-"
)
// CheckHandler handles the request for checking a repo
func CheckHandler(w http.ResponseWriter, r *http.Request, db *badger.DB) {
w.Header().Set("Content-Type", "application/json")
repo := download.Clean(r.FormValue("repo"))
c := download.NewProxyClient("https://proxy.golang.org")
moduleName, err := c.ModuleName(repo)
if err != nil {
log.Println("ERROR: could not get module name:", err)
}
if moduleName != "" {
repo = moduleName
}
log.Printf("Checking repo %q...", repo)
forceRefresh := r.Method != "GET" // if this is a GET request, try to fetch from cached version in badger first
_, err = newChecksResp(db, repo, forceRefresh)
if err != nil {
log.Println("ERROR: from newChecksResp:", err)
http.Error(w, "Could not analyze the repository: "+err.Error(), http.StatusBadRequest)
return
}
b, err := json.Marshal(map[string]string{"redirect": "/report/" + repo})
if err != nil {
log.Println("JSON marshal error:", err)
}
w.WriteHeader(http.StatusOK)
w.Write(b)
}
func updateHighScores(txn *badger.Txn, resp checksResp, repo string) error {
// check if we need to update the high score list
if resp.Files < 100 {
// only repos with >= 100 files are considered for the high score list
return nil
}
var scoreBytes []byte
// start updating high score list
item, err := txn.Get([]byte("scores"))
if err != nil && err != badger.ErrKeyNotFound {
return err
}
if item == nil {
scoreBytes, _ = json.Marshal([]ScoreHeap{})
}
if item != nil {
item.Value(func(val []byte) error {
scoreBytes = val
return nil
})
}
scores := &ScoreHeap{}
json.Unmarshal(scoreBytes, scores)
heap.Init(scores)
if len(*scores) > 0 && (*scores)[0].Score > resp.Average*100.0 && len(*scores) == 50 {
// lowest score on list is higher than this repo's score, so no need to add, unless
// we do not have 50 high scores yet
return nil
}
// if this repo is already in the list, remove the original entry:
for i := range *scores {
if strings.EqualFold((*scores)[i].Repo, repo) {
heap.Remove(scores, i)
break
}
}
// now we can safely push it onto the heap
heap.Push(scores, scoreItem{
Repo: repo,
Score: resp.Average * 100.0,
Files: resp.Files,
})
if len(*scores) > 50 {
// trim heap if it's grown to over 50
*scores = (*scores)[1:51]
}
scoreBytes, err = json.Marshal(&scores)
if err != nil {
return err
}
return txn.Set([]byte("scores"), scoreBytes)
}
func updateReposCount(txn *badger.Txn, repo string) error {
log.Printf("New repo %q, adding to repo count...", repo)
totalInt := 0
item, err := txn.Get([]byte("total_repos"))
if err != nil && err != badger.ErrKeyNotFound {
return err
}
if item != nil {
err := item.Value(func(val []byte) error {
err = json.Unmarshal(val, &totalInt)
if err != nil {
return fmt.Errorf("could not unmarshal total repos count: %v", err)
}
return nil
})
if err != nil {
return err
}
}
totalInt++ // increase repo count
total, err := json.Marshal(totalInt)
if err != nil {
return fmt.Errorf("could not marshal total repos count: %v", err)
}
err = txn.Set([]byte("total_repos"), total)
if err != nil {
return err
}
log.Println("Repo count is now", totalInt)
return nil
}
type recentItem struct {
Repo string
}
func updateRecentlyViewed(txn *badger.Txn, repo string) error {
var recent []recentItem
item, err := txn.Get([]byte("recent"))
if err != nil && err != badger.ErrKeyNotFound {
return err
}
if item != nil {
item.Value(func(val []byte) error {
return json.Unmarshal(val, &recent)
})
}
// add it to the slice, if it is not in there already
for i := range recent {
if recent[i].Repo == repo {
return nil
}
}
recent = append(recent, recentItem{Repo: repo})
if len(recent) > 5 {
// trim recent if it's grown to over 5
recent = (recent)[1:6]
}
b, err := json.Marshal(&recent)
if err != nil {
return err
}
return txn.Set([]byte("recent"), b)
}
func updateMetadata(txn *badger.Txn, resp checksResp, repo string, isNewRepo bool) error {
// update total repos count
if isNewRepo {
err := updateReposCount(txn, repo)
if err != nil {
return err
}
}
return updateHighScores(txn, resp, repo)
}