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 ro bool t1 time.Time } func (h handler) load(tmpl string, data interface{}) { var err error h.t1 = time.Now() fmt := h.r.FormValue("fmt") switch fmt { case "rss": err = loadRss(h.w, tmpl, 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) } } func (h handler) booksInSubmission(bookIDs []string, submissionID string) bool { submissions, err := h.db.GetSubmission(submissionID) if err != nil { return false } for _, bookID := range bookIDs { if bookID == "" { continue } found := false for _, s := range submissions { if s.BookID == bookID && !s.Book.Active { found = true break } } if !found { return false } } return true } type StatsGatherer struct { db database.DB store storage.Store template *Template instrument instrument.Instrument channel chan statsRequest ro bool } func InitStats(database database.DB, store storage.Store, template *Template, ro bool) *StatsGatherer { in := instrument.Init() sg := StatsGatherer{ channel: make(chan statsRequest, statsChanSize), db: database, store: store, instrument: in, template: template, 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, w: w, r: r, sess: GetSession(r, sg.db), ro: sg.ro, } t0 := time.Now() function(h) if h.t1.IsZero() { h.t1 = time.Now() } pattern := strings.Split(r.URL.Path, "/") section := "/" if len(pattern) > 1 && pattern[1] != "" { section = pattern[1] } sg.channel <- statsRequest{ id: mux.Vars(r)["id"], search: strings.Join(r.Form["q"], " "), fmt: r.FormValue("fmt"), section: section, duration: h.t1.Sub(t0), } } } type statsRequest struct { id string search string fmt string section string duration time.Duration } func (sg StatsGatherer) worker() { for req := range sg.channel { sg.save(req) } } func (sg StatsGatherer) save(req statsRequest) { sg.instrument.Request(instrument.RequestData{ Section: req.section, ID: req.id, Search: req.search, Fmt: req.fmt, Duration: req.duration, }) _, err := sg.db.GetBookID(req.id) if err != nil { return } switch req.section { case "download": err = sg.db.IncDownloads(req.id) case "book": err = sg.db.IncViews(req.id) case "read": err = sg.db.IncViews(req.id) } if err != nil { log.Warn("Problem incrementing visits: ", err) } }