Store statistics on mongodb

This commit is contained in:
Las Zenow 2013-04-22 23:28:00 +02:00
parent c4373c8773
commit 206775fa6a
9 changed files with 159 additions and 52 deletions

View file

@ -13,8 +13,7 @@ type settingsData struct {
S Status
}
func settingsHandler(w http.ResponseWriter, r *http.Request) {
sess := GetSession(r)
func settingsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if sess.User == "" {
http.NotFound(w, r)
return
@ -39,8 +38,7 @@ func settingsHandler(w http.ResponseWriter, r *http.Request) {
loadTemplate(w, "settings", data)
}
func deleteHandler(w http.ResponseWriter, r *http.Request) {
sess := GetSession(r)
func deleteHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if sess.User == "" {
http.NotFound(w, r)
return
@ -80,8 +78,7 @@ func deleteHandler(w http.ResponseWriter, r *http.Request) {
}
}
func editHandler(w http.ResponseWriter, r *http.Request) {
sess := GetSession(r)
func editHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if sess.User == "" {
http.NotFound(w, r)
return
@ -109,8 +106,7 @@ func cleanEmptyStr(s []string) []string {
return res
}
func saveHandler(w http.ResponseWriter, r *http.Request) {
sess := GetSession(r)
func saveHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if sess.User == "" {
http.NotFound(w, r)
return
@ -162,8 +158,7 @@ type newData struct {
Prev string
}
func newHandler(w http.ResponseWriter, r *http.Request) {
sess := GetSession(r)
func newHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if sess.User == "" {
http.NotFound(w, r)
return
@ -206,8 +201,7 @@ func newHandler(w http.ResponseWriter, r *http.Request) {
loadTemplate(w, "new", data)
}
func storeHandler(w http.ResponseWriter, r *http.Request) {
sess := GetSession(r)
func storeHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if sess.User == "" {
http.NotFound(w, r)
return

View file

@ -9,6 +9,7 @@ const (
BOOKS_COLL = "books"
TAGS_COLL = "tags"
USERS_COLL = "users"
STATS_COLL = "statistics"
FS_BOOKS = "fs_books"
FS_IMGS = "fs_imgs"
@ -26,4 +27,6 @@ const (
IMG_WIDTH_BIG = 300
IMG_WIDTH_SMALL = 60
IMG_QUALITY = 80
STATS_CHAN_SIZE = 100
)

View file

@ -44,6 +44,7 @@ type DB struct {
books *mgo.Collection
tags *mgo.Collection
user *mgo.Collection
stats *mgo.Collection
}
func initDB() *DB {
@ -59,6 +60,7 @@ func initDB() *DB {
d.books = database.C(BOOKS_COLL)
d.tags = database.C(TAGS_COLL)
d.user = database.C(USERS_COLL)
d.stats = database.C(STATS_COLL)
return d
}
@ -86,6 +88,10 @@ func (d *DB) UserValid(user string, pass string) bool {
return n != 0
}
func (d *DB) InsertStats(stats interface{}) error {
return d.stats.Insert(stats)
}
func (d *DB) InsertBook(book interface{}) error {
return d.books.Insert(book)
}

View file

@ -127,9 +127,9 @@ func listChapters(nav *epubgo.NavigationIterator, depth int) []chapter {
return chapters
}
func readStartHandler(w http.ResponseWriter, r *http.Request) {
func readStartHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
id := mux.Vars(r)["id"]
e, _ := openReadEpub(w, r)
e, _ := openReadEpub(w, r, sess)
if e == nil {
http.NotFound(w, r)
return
@ -144,10 +144,10 @@ func readStartHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/read/"+id+"/"+it.Url(), http.StatusTemporaryRedirect)
}
func readHandler(w http.ResponseWriter, r *http.Request) {
func readHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
id := mux.Vars(r)["id"]
file := mux.Vars(r)["file"]
e, book := openReadEpub(w, r)
e, book := openReadEpub(w, r, sess)
if e == nil {
http.NotFound(w, r)
return
@ -169,7 +169,7 @@ func readHandler(w http.ResponseWriter, r *http.Request) {
loadTemplate(w, "read", data)
}
func openReadEpub(w http.ResponseWriter, r *http.Request) (*epubgo.Epub, Book) {
func openReadEpub(w http.ResponseWriter, r *http.Request, sess *Session) (*epubgo.Epub, Book) {
var book Book
id := mux.Vars(r)["id"]
books, _, err := db.GetBooks(bson.M{"_id": bson.ObjectIdHex(id)})
@ -179,7 +179,6 @@ func openReadEpub(w http.ResponseWriter, r *http.Request) (*epubgo.Epub, Book) {
book = books[0]
if !book.Active {
sess := GetSession(r)
if sess.User == "" {
return nil, book
}
@ -191,7 +190,7 @@ func openReadEpub(w http.ResponseWriter, r *http.Request) (*epubgo.Epub, Book) {
return e, book
}
func contentHandler(w http.ResponseWriter, r *http.Request) {
func contentHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
vars := mux.Vars(r)
id := vars["id"]
file := vars["file"]
@ -207,7 +206,6 @@ func contentHandler(w http.ResponseWriter, r *http.Request) {
}
book := books[0]
if !book.Active {
sess := GetSession(r)
if sess.User == "" {
http.NotFound(w, r)
return

View file

@ -34,7 +34,7 @@ type searchData struct {
Prev string
}
func searchHandler(w http.ResponseWriter, r *http.Request) {
func searchHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)

View file

@ -1,6 +1,7 @@
package main
import (
"encoding/hex"
"github.com/gorilla/securecookie"
"github.com/gorilla/sessions"
"net/http"
@ -42,6 +43,11 @@ func GetSession(r *http.Request) (s *Session) {
s.User, _ = s.S.Values["user"].(string)
s.Notif = getNotif(s.S)
}
if s.S.IsNew {
s.S.Values["id"] = hex.EncodeToString(securecookie.GenerateRandomKey(16))
}
return
}
@ -63,3 +69,8 @@ func (s *Session) Notify(title, msg, tpe string) {
func (s *Session) Save(w http.ResponseWriter, r *http.Request) {
sesStore.Save(r, w, s.S)
}
func (s *Session) Id() string {
id, _ := s.S.Values["id"].(string)
return id
}

97
stats.go Normal file
View file

@ -0,0 +1,97 @@
package main
import (
"github.com/gorilla/mux"
"labix.org/v2/mgo/bson"
"net/http"
"strings"
"time"
)
func InitStats() {
statsChannel = make(chan statsRequest, STATS_CHAN_SIZE)
go statsWorker()
}
func GatherStats(function func(http.ResponseWriter, *http.Request, *Session)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
sess := GetSession(r)
function(w, r, sess)
statsChannel <- statsRequest{bson.Now(), mux.Vars(r), sess, r}
}
}
var statsChannel chan statsRequest
type statsRequest struct {
date time.Time
vars map[string]string
sess *Session
r *http.Request
}
func statsWorker() {
for req := range statsChannel {
stats := make(map[string]interface{})
appendFiles(req.r, stats)
appendMuxVars(req.vars, stats)
appendUrl(req.r, stats)
appendSession(req.sess, stats)
stats["method"] = req.r.Method
stats["date"] = req.date
db.InsertStats(stats)
}
}
func appendFiles(r *http.Request, stats map[string]interface{}) {
if r.Method == "POST" && r.MultipartForm.File != nil { //FIXM
files := r.MultipartForm.File
for key := range files {
list := make([]string, len(files[key]))
for i, f := range files[key] {
list[i] = f.Filename
}
stats[key] = list
}
}
}
func appendMuxVars(vars map[string]string, stats map[string]interface{}) {
for key, value := range vars {
switch {
case key == "id":
stats["id"] = bson.ObjectIdHex(value)
case key == "ids":
ids := strings.Split(value, "/")
objectIds := make([]bson.ObjectId, len(ids))
for i, id := range ids {
objectIds[i] = bson.ObjectIdHex(id)
}
stats["ids"] = objectIds
stats["id"] = objectIds[0]
default:
stats[key] = value
}
}
}
func appendUrl(r *http.Request, stats map[string]interface{}) {
for key, value := range r.URL.Query() {
stats[key] = value
}
stats["host"] = r.Host
stats["path"] = r.URL.Path
pattern := strings.Split(r.URL.Path, "/")
if len(pattern) > 1 && pattern[1] != "" {
stats["section"] = pattern[1]
} else {
stats["section"] = "/"
}
}
func appendSession(sess *Session, stats map[string]interface{}) {
stats["session"] = sess.Id()
if sess.User != "" {
stats["user"] = sess.User
}
}

View file

@ -12,15 +12,14 @@ type aboutData struct {
S Status
}
func aboutHandler(w http.ResponseWriter, r *http.Request) {
func aboutHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
var data aboutData
data.S = GetStatus(w, r)
data.S.About = true
loadTemplate(w, "about", data)
}
func logoutHandler(w http.ResponseWriter, r *http.Request) {
sess := GetSession(r)
func logoutHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
sess.LogOut()
sess.Notify("Log out!", "Bye bye "+sess.User, "success")
sess.Save(w, r)
@ -28,10 +27,9 @@ func logoutHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", http.StatusFound)
}
func loginHandler(w http.ResponseWriter, r *http.Request) {
func loginHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
user := r.FormValue("user")
pass := r.FormValue("pass")
sess := GetSession(r)
if db.UserValid(user, pass) {
log.Println("User", user, "log in")
sess.LogIn(user)
@ -49,7 +47,7 @@ type bookData struct {
Book Book
}
func bookHandler(w http.ResponseWriter, r *http.Request) {
func bookHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
var data bookData
data.S = GetStatus(w, r)
id := bson.ObjectIdHex(mux.Vars(r)["id"])
@ -63,7 +61,7 @@ func bookHandler(w http.ResponseWriter, r *http.Request) {
loadTemplate(w, "book", data)
}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
func downloadHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
id := bson.ObjectIdHex(mux.Vars(r)["id"])
books, _, err := db.GetBooks(bson.M{"_id": id})
if err != nil || len(books) == 0 {
@ -105,7 +103,7 @@ type indexData struct {
Tags []string
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
func indexHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
var data indexData
data.Tags, _ = db.GetTags(TAGS_DISPLAY)
@ -121,31 +119,33 @@ func main() {
db = initDB()
defer db.Close()
InitStats()
setUpRouter()
panic(http.ListenAndServe(":"+PORT, nil))
}
func setUpRouter() {
r := mux.NewRouter()
r.HandleFunc("/", indexHandler)
r.HandleFunc("/book/{id:[0-9a-fA-F]+}", bookHandler)
r.HandleFunc("/search/", searchHandler)
r.HandleFunc("/upload/", uploadHandler).Methods("GET")
r.HandleFunc("/upload/", uploadPostHandler).Methods("POST")
r.HandleFunc("/login/", loginHandler).Methods("POST")
r.HandleFunc("/logout/", logoutHandler)
r.HandleFunc("/new/", newHandler)
r.HandleFunc("/store/{ids:([0-9a-fA-F]+/)+}", storeHandler)
r.HandleFunc("/delete/{ids:([0-9a-fA-F]+/)+}", deleteHandler)
r.HandleFunc("/read/{id:[0-9a-fA-F]+}", readStartHandler)
r.HandleFunc("/read/{id:[0-9a-fA-F]+}/{file:.*}", readHandler)
r.HandleFunc("/content/{id:[0-9a-fA-F]+}/{file:.*}", contentHandler)
r.HandleFunc("/edit/{id:[0-9a-fA-F]+}", editHandler)
r.HandleFunc("/save/{id:[0-9a-fA-F]+}", saveHandler).Methods("POST")
r.HandleFunc("/about/", aboutHandler)
r.HandleFunc("/download/{id:[0-9a-fA-F]+}/{epub:.*}", downloadHandler)
r.HandleFunc("/", GatherStats(indexHandler))
r.HandleFunc("/book/{id:[0-9a-fA-F]+}", GatherStats(bookHandler))
r.HandleFunc("/search/", GatherStats(searchHandler))
r.HandleFunc("/upload/", GatherStats(uploadHandler)).Methods("GET")
r.HandleFunc("/upload/", GatherStats(uploadPostHandler)).Methods("POST")
r.HandleFunc("/login/", GatherStats(loginHandler)).Methods("POST")
r.HandleFunc("/logout/", GatherStats(logoutHandler))
r.HandleFunc("/new/", GatherStats(newHandler))
r.HandleFunc("/store/{ids:([0-9a-fA-F]+/)+}", GatherStats(storeHandler))
r.HandleFunc("/delete/{ids:([0-9a-fA-F]+/)+}", GatherStats(deleteHandler))
r.HandleFunc("/read/{id:[0-9a-fA-F]+}", GatherStats(readStartHandler))
r.HandleFunc("/read/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(readHandler))
r.HandleFunc("/content/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(contentHandler))
r.HandleFunc("/edit/{id:[0-9a-fA-F]+}", GatherStats(editHandler))
r.HandleFunc("/save/{id:[0-9a-fA-F]+}", GatherStats(saveHandler)).Methods("POST")
r.HandleFunc("/about/", GatherStats(aboutHandler))
r.HandleFunc("/download/{id:[0-9a-fA-F]+}/{epub:.*}", GatherStats(downloadHandler))
r.HandleFunc("/cover/{id:[0-9a-fA-F]+}/{size}/{img:.*}", coverHandler)
r.HandleFunc("/settings/", settingsHandler)
r.HandleFunc("/settings/", GatherStats(settingsHandler))
h := http.FileServer(http.Dir(IMG_PATH))
r.Handle("/img/{img}", http.StripPrefix("/img/", h))
h = http.FileServer(http.Dir(CSS_PATH))

View file

@ -10,9 +10,7 @@ import (
"strings"
)
func uploadPostHandler(w http.ResponseWriter, r *http.Request) {
sess := GetSession(r)
func uploadPostHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
uploaded := ""
r.ParseMultipartForm(20000000)
filesForm := r.MultipartForm.File["epub"]
@ -49,10 +47,10 @@ func uploadPostHandler(w http.ResponseWriter, r *http.Request) {
sess.Notify("Upload successful!", "Added the books:"+uploaded+". Thank you for your contribution", "success")
}
uploadHandler(w, r)
uploadHandler(w, r, sess)
}
func uploadHandler(w http.ResponseWriter, r *http.Request) {
func uploadHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
var data uploadData
data.S = GetStatus(w, r)
data.S.Upload = true