package trantor import ( log "github.com/cihub/seelog" "net/http" "strings" "time" "github.com/gorilla/mux" "gitlab.com/trantor/trantor/lib/database" "gitlab.com/trantor/trantor/lib/instrument" "gitlab.com/trantor/trantor/lib/storage" ) const ( statsChanSize = 100 ) type handler struct { w http.ResponseWriter r *http.Request sess *Session db database.DB store storage.Store template *Template hostname string ro bool } func (h handler) load(tmpl string, data interface{}) { var err error fmt := h.r.FormValue("fmt") switch fmt { case "rss": err = h.template.rss.ExecuteTemplate(h.w, tmpl+".rss", data) case "opds": err = h.template.opds.ExecuteTemplate(h.w, tmpl+".opds", data) case "json": err = loadJson(h.w, tmpl, data) default: err = h.template.html.ExecuteTemplate(h.w, tmpl+".html", data) } if err != nil { h.template.html.ExecuteTemplate(h.w, "404.html", data) log.Warn("An error ocurred loading the template ", tmpl, ".", fmt, ": ", err) } } type StatsGatherer struct { db database.DB store storage.Store template *Template instrument instrument.Instrument hostname string channel chan statsRequest ro bool } func InitStats(database database.DB, store storage.Store, hostname string, template *Template, ro bool) *StatsGatherer { in := instrument.Init() sg := StatsGatherer{ channel: make(chan statsRequest, statsChanSize), db: database, store: store, instrument: in, template: template, hostname: hostname, ro: ro, } go sg.worker() return &sg } func (sg StatsGatherer) Gather(function func(handler)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { log.Info("Query ", r.Method, " ", r.RequestURI) h := handler{ store: sg.store, db: sg.db, template: sg.template, hostname: sg.hostname, w: w, r: r, sess: GetSession(r, sg.db), ro: sg.ro, } t0 := time.Now() function(h) t1 := time.Now() sg.channel <- statsRequest{r, t1.Sub(t0)} } } type statsRequest struct { r *http.Request duration time.Duration } func (sg StatsGatherer) worker() { for req := range sg.channel { var err error id := mux.Vars(req.r)["id"] search := strings.Join(req.r.Form["q"], " ") fmt := req.r.FormValue("fmt") pattern := strings.Split(req.r.URL.Path, "/") section := "/" if len(pattern) > 1 && pattern[1] != "" { section = pattern[1] } sg.instrument.Visit(section, id, search, fmt) sg.instrument.Duration(section, req.duration*time.Microsecond) switch section { case "download": err = sg.db.IncDownloads(id) case "book": err = sg.db.IncViews(id) case "read": err = sg.db.IncViews(id) } if err != nil { log.Warn("Problem incrementing visits: ", err) } } }