diff --git a/cmd/server/svg-server.go b/cmd/server/svg-server.go index b93547d..bfeee85 100644 --- a/cmd/server/svg-server.go +++ b/cmd/server/svg-server.go @@ -1,7 +1,6 @@ package main import ( - "math/rand" "net/http" "strconv" "time" @@ -14,17 +13,10 @@ import ( type DayCount [366]int -func init() { - rand.Seed(time.Now().UnixMilli()) -} - func main() { r := mux.NewRouter() r.HandleFunc("/weekly.svg", func(w http.ResponseWriter, r *http.Request) { freq := []int{} - for i := 0; i < 7; i++ { - freq = append(freq, rand.Int()) - } w.Header().Add("Content-Type", "text/html") svg := svg.GetWeekSVG(freq) svg.WriteTo(w) diff --git a/commits/commits.go b/commits/commits.go index f0c39ba..a367c3a 100644 --- a/commits/commits.go +++ b/commits/commits.go @@ -1,9 +1,13 @@ package commits import ( + "crypto/md5" "errors" + "fmt" "os" "regexp" + "sort" + "strings" "sync" "time" @@ -16,6 +20,71 @@ import ( type Repo git.Repository +var ( + mapTex sync.RWMutex + hashCache map[int]map[string]map[string]types.ExpYearFreq +) + +func init() { + hashCache = make(map[int]map[string]map[string]types.ExpYearFreq) +} + +func hashSlice(in []string) string { + sort.Strings(in) + sb := strings.Builder{} + for _, s := range in { + sb.WriteString(s) + } + h := md5.New() + h.Write([]byte(sb.String())) + b := h.Sum(nil) + return fmt.Sprintf("%x\n", b) +} + +func GetCachedGraph(year int, authors []string, repoPaths []string) (types.YearFreq, bool) { + a := hashSlice(authors) + r := hashSlice(repoPaths) + mapTex.RLock() + defer mapTex.RUnlock() + if m1, ok := hashCache[year]; !ok { + return types.YearFreq{}, false + } else { + if m2, ok := m1[a]; !ok { + return types.YearFreq{}, false + } else { + if freq, ok := m2[r]; !ok { + return types.YearFreq{}, false + } else { + if freq.Created.Before(time.Now().Add(-15 * time.Minute)) { + return types.YearFreq{}, false + } else { + return freq.YearFreq, true + } + } + } + } +} + +func CacheGraph(year int, authors, repoPaths []string, freq types.YearFreq) { + a := hashSlice(authors) + r := hashSlice(repoPaths) + mapTex.Lock() + defer mapTex.Unlock() + if _, ok := hashCache[year]; !ok { + hashCache[year] = make(map[string]map[string]types.ExpYearFreq) + } + if _, ok := hashCache[year][a]; !ok { + hashCache[year][a] = make(map[string]types.ExpYearFreq) + } + hashCache[year][a][r] = types.ExpYearFreq{YearFreq: freq, Created: time.Now()} + go func() { + time.Sleep(time.Minute * 15) + mapTex.Lock() + defer mapTex.Unlock() + delete(hashCache[year][a], r) + }() +} + func GlobalFrequencyChan(year int, authors []string) (types.YearFreq, error) { yearLength := 365 if year%4 == 0 { @@ -26,6 +95,10 @@ func GlobalFrequencyChan(year int, authors []string) (types.YearFreq, error) { return types.YearFreq{}, err } paths := mrconf.GetRepoPaths() + cache, ok := GetCachedGraph(year, authors, paths) + if ok { + return cache, nil + } outChan := make(chan types.Commit, 10) var wg sync.WaitGroup for _, p := range paths { @@ -55,7 +128,7 @@ func GlobalFrequencyChan(year int, authors []string) (types.YearFreq, error) { close(outChan) }() freq := YearFreqFromChan(outChan, year) - + CacheGraph(year, authors, paths, freq) return freq, nil } diff --git a/types/types.go b/types/types.go index 395b6dd..35be914 100644 --- a/types/types.go +++ b/types/types.go @@ -14,9 +14,13 @@ type ( Repo string `json:"repo,omitempty"` Path string `json:"path,omitempty"` } - DataSet map[time.Time]WorkDay - YearFreq []int - WorkDay struct { + DataSet map[time.Time]WorkDay + YearFreq []int + ExpYearFreq struct { + YearFreq YearFreq + Created time.Time + } + WorkDay struct { Day time.Time `json:"day"` Count int `json:"count"` Commits []Commit `json:"commits,omitempty"`