First pass of writing to and loading from bolt

This commit is contained in:
Herman Schaaf
2016-02-04 20:43:57 +08:00
parent 804baf6c91
commit ecd6fda134
4 changed files with 119 additions and 67 deletions

View File

@@ -2,12 +2,21 @@ package handlers
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"time"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"github.com/boltdb/bolt"
)
const (
// DBPath is the relative (or absolute) path to the bolt database file
DBPath string = "goreportcard.db"
// RepoBucket is the bucket in which repos will be cached in the bolt DB
RepoBucket string = "repos"
)
// CheckHandler handles the request for checking a repo
@@ -31,26 +40,34 @@ func CheckHandler(w http.ResponseWriter, r *http.Request) {
return
}
b, err := json.Marshal(resp)
respBytes, err := json.Marshal(resp)
if err != nil {
log.Println("ERROR: could not marshal json:", err)
http.Error(w, err.Error(), 500)
return
}
w.Write(b)
w.Write(respBytes)
// write to mongo
session, err := mgo.Dial(mongoURL)
// write to boltdb
db, err := bolt.Open(DBPath, 0755, &bolt.Options{Timeout: 1 * time.Second})
if err != nil {
log.Println("Failed to get mongo collection: ", err)
log.Println("Failed to open bolt database: ", err)
return
}
defer session.Close()
coll := session.DB(mongoDatabase).C(mongoCollection)
log.Printf("Upserting repo %s...", repo)
_, err = coll.Upsert(bson.M{"repo": repo}, resp)
defer db.Close()
log.Printf("Saving repo %q to cache...", repo)
err = db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(RepoBucket))
if b == nil {
return fmt.Errorf("Repo bucket not found")
}
return b.Put([]byte(repo), respBytes)
})
if err != nil {
log.Println("Mongo writing error:", err)
return
log.Println("Bolt writing error:", err)
}
return
}

View File

@@ -1,6 +1,9 @@
package handlers
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"log"
"os"
@@ -8,36 +11,51 @@ import (
"strings"
"time"
"github.com/boltdb/bolt"
"github.com/gojp/goreportcard/check"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
var (
mongoURL = "mongodb://127.0.0.1:27017"
mongoDatabase = "goreportcard"
mongoCollection = "reports"
)
func getFromCache(repo string) (checksResp, error) {
// try and fetch from mongo
session, err := mgo.Dial(mongoURL)
// try and fetch from boltdb
db, err := bolt.Open(DBPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
if err != nil {
return checksResp{}, fmt.Errorf("Failed to get mongo collection during GET: %v", err)
return checksResp{}, fmt.Errorf("Failed to open bolt database during GET: %v", err)
}
defer session.Close()
coll := session.DB(mongoDatabase).C(mongoCollection)
defer db.Close()
resp := checksResp{}
err = coll.Find(bson.M{"repo": repo}).One(&resp)
err = db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(RepoBucket))
if b == nil {
return errors.New("No repo bucket")
}
cached := b.Get([]byte(repo))
if cached == nil {
return fmt.Errorf("%q not found in cache", repo)
}
err = json.Unmarshal(cached, &resp)
if err != nil {
return fmt.Errorf("failed to parse JSON for %q in cache", repo)
}
return nil
})
if err != nil {
return checksResp{}, fmt.Errorf("Failed to fetch %q from mongo: %v", repo, err)
return resp, err
}
resp.LastRefresh = resp.LastRefresh.UTC()
return resp, nil
}
// itob returns an 8-byte big endian representation of v.
func itob(v int) []byte {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(v))
return b
}
type score struct {
Name string `json:"name"`
Description string `json:"description"`

View File

@@ -2,13 +2,7 @@ package handlers
import (
"fmt"
"log"
"net/http"
"text/template"
"github.com/dustin/go-humanize"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
func add(x, y int) int {
@@ -21,36 +15,36 @@ func formatScore(x float64) string {
// HighScoresHandler handles the stats page
func HighScoresHandler(w http.ResponseWriter, r *http.Request) {
session, err := mgo.Dial(mongoURL)
if err != nil {
log.Println("ERROR: could not get collection:", err)
http.Error(w, err.Error(), 500)
return
}
defer session.Close()
coll := session.DB(mongoDatabase).C(mongoCollection)
var highScores []struct {
Repo string
Files int
Average float64
}
err = coll.Find(bson.M{"files": bson.M{"$gt": 100}}).Sort("-average").Limit(50).All(&highScores)
if err != nil {
log.Println("ERROR: could not get high scores: ", err)
http.Error(w, err.Error(), 500)
return
}
count, err := coll.Count()
if err != nil {
log.Println("ERROR: could not get count of high scores: ", err)
http.Error(w, err.Error(), 500)
return
}
funcs := template.FuncMap{"add": add, "formatScore": formatScore}
t := template.Must(template.New("high_scores.html").Funcs(funcs).ParseFiles("templates/high_scores.html"))
t.Execute(w, map[string]interface{}{"HighScores": highScores, "Count": humanize.Comma(int64(count))})
// session, err := mgo.Dial(mongoURL)
// if err != nil {
// log.Println("ERROR: could not get collection:", err)
// http.Error(w, err.Error(), 500)
// return
// }
// defer session.Close()
// coll := session.DB(mongoDatabase).C(mongoCollection)
//
// var highScores []struct {
// Repo string
// Files int
// Average float64
// }
// err = coll.Find(bson.M{"files": bson.M{"$gt": 100}}).Sort("-average").Limit(50).All(&highScores)
// if err != nil {
// log.Println("ERROR: could not get high scores: ", err)
// http.Error(w, err.Error(), 500)
// return
// }
//
// count, err := coll.Count()
// if err != nil {
// log.Println("ERROR: could not get count of high scores: ", err)
// http.Error(w, err.Error(), 500)
// return
// }
//
// funcs := template.FuncMap{"add": add, "formatScore": formatScore}
// t := template.Must(template.New("high_scores.html").Funcs(funcs).ParseFiles("templates/high_scores.html"))
//
// t.Execute(w, map[string]interface{}{"HighScores": highScores, "Count": humanize.Comma(int64(count))})
}

23
main.go
View File

@@ -6,7 +6,9 @@ import (
"net/http"
"os"
"regexp"
"time"
"github.com/boltdb/bolt"
"github.com/gojp/goreportcard/handlers"
)
@@ -31,11 +33,32 @@ func makeHandler(name string, fn func(http.ResponseWriter, *http.Request, string
}
}
// initDB opens the bolt database file (or creates it if it does not exist), and creates
// a bucket for saving the repos, also only if it does not exist.
func initDB() error {
db, err := bolt.Open(handlers.DBPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
if err != nil {
return err
}
defer db.Close()
err = db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(handlers.RepoBucket))
return err
})
return err
}
func main() {
if err := os.MkdirAll("repos/src/github.com", 0755); err != nil && !os.IsExist(err) {
log.Fatal("ERROR: could not create repos dir: ", err)
}
// initialize database
if err := initDB(); err != nil {
log.Fatal("ERROR: could not open bolt db: ", err)
}
http.HandleFunc("/assets/", handlers.AssetsHandler)
http.HandleFunc("/checks", handlers.CheckHandler)
http.HandleFunc("/report/", makeHandler("report", handlers.ReportHandler))