Remove statistics and add frequent tags in memory
This commit is contained in:
parent
284b649b69
commit
18baa2938b
10 changed files with 35 additions and 256 deletions
|
@ -24,8 +24,6 @@ type Book struct {
|
|||
Tsv string
|
||||
}
|
||||
|
||||
// TODO: missing history
|
||||
|
||||
// AddBook to the database
|
||||
func (db *pgDB) AddBook(book Book) error {
|
||||
emptyTime := time.Time{}
|
||||
|
|
|
@ -22,22 +22,17 @@ type DB interface {
|
|||
GetNews(num int, days int) (news []New, err error)
|
||||
AddStats(stats interface{}) error
|
||||
GetVisitedBooks() (books []Book, err error)
|
||||
UpdateMostVisited() error
|
||||
GetDownloadedBooks() (books []Book, err error)
|
||||
UpdateDownloadedBooks() error
|
||||
GetTags() ([]string, error)
|
||||
UpdateTags() error
|
||||
GetVisits(visitType VisitType) ([]Visits, error)
|
||||
UpdateHourVisits() error
|
||||
UpdateDayVisits() error
|
||||
UpdateMonthVisits() error
|
||||
UpdateHourDownloads() error
|
||||
UpdateDayDownloads() error
|
||||
UpdateMonthDownloads() error
|
||||
}
|
||||
|
||||
const (
|
||||
tagsDisplay = 50
|
||||
)
|
||||
|
||||
type pgDB struct {
|
||||
sql *pg.DB
|
||||
sql *pg.DB
|
||||
tags []string
|
||||
}
|
||||
|
||||
// Options for the database
|
||||
|
@ -57,7 +52,11 @@ func Init(options Options) (DB, error) {
|
|||
Database: options.Name,
|
||||
})
|
||||
// TODO: create db
|
||||
return &pgDB{sql}, nil
|
||||
|
||||
db := pgDB{sql, []string{}}
|
||||
go db.tagUpdater()
|
||||
|
||||
return &db, nil
|
||||
}
|
||||
|
||||
// Close the database connection
|
||||
|
|
|
@ -76,50 +76,10 @@ func (db *roDB) GetVisitedBooks() (books []Book, err error) {
|
|||
return db.db.GetVisitedBooks()
|
||||
}
|
||||
|
||||
func (db *roDB) UpdateMostVisited() error {
|
||||
return errors.New("RO database")
|
||||
}
|
||||
|
||||
func (db *roDB) GetDownloadedBooks() (books []Book, err error) {
|
||||
return db.db.GetDownloadedBooks()
|
||||
}
|
||||
|
||||
func (db *roDB) UpdateDownloadedBooks() error {
|
||||
return errors.New("RO database")
|
||||
}
|
||||
|
||||
func (db *roDB) GetTags() ([]string, error) {
|
||||
return db.db.GetTags()
|
||||
}
|
||||
|
||||
func (db *roDB) UpdateTags() error {
|
||||
return errors.New("RO database")
|
||||
}
|
||||
|
||||
func (db *roDB) GetVisits(visitType VisitType) ([]Visits, error) {
|
||||
return db.db.GetVisits(visitType)
|
||||
}
|
||||
|
||||
func (db *roDB) UpdateHourVisits() error {
|
||||
return errors.New("RO database")
|
||||
}
|
||||
|
||||
func (db *roDB) UpdateDayVisits() error {
|
||||
return errors.New("RO database")
|
||||
}
|
||||
|
||||
func (db *roDB) UpdateMonthVisits() error {
|
||||
return errors.New("RO database")
|
||||
}
|
||||
|
||||
func (db *roDB) UpdateHourDownloads() error {
|
||||
return errors.New("RO database")
|
||||
}
|
||||
|
||||
func (db *roDB) UpdateDayDownloads() error {
|
||||
return errors.New("RO database")
|
||||
}
|
||||
|
||||
func (db *roDB) UpdateMonthDownloads() error {
|
||||
return errors.New("RO database")
|
||||
}
|
||||
|
|
|
@ -3,24 +3,10 @@ package database
|
|||
|
||||
import (
|
||||
"time"
|
||||
|
||||
log "github.com/cihub/seelog"
|
||||
)
|
||||
|
||||
type VisitType int
|
||||
|
||||
const (
|
||||
Hourly_visits = iota
|
||||
Daily_visits
|
||||
Monthly_visits
|
||||
Hourly_downloads
|
||||
Daily_downloads
|
||||
Monthly_downloads
|
||||
)
|
||||
|
||||
type Visits struct {
|
||||
Date time.Time "date"
|
||||
Count int "count"
|
||||
}
|
||||
|
||||
func (db *pgDB) AddStats(stats interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -31,52 +17,34 @@ func (db *pgDB) GetVisitedBooks() (books []Book, err error) {
|
|||
return []Book{}, nil
|
||||
}
|
||||
|
||||
func (db *pgDB) UpdateMostVisited() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
/* Get the most downloaded books
|
||||
*/
|
||||
func (db *pgDB) GetDownloadedBooks() (books []Book, err error) {
|
||||
return []Book{}, nil
|
||||
}
|
||||
|
||||
func (db *pgDB) UpdateDownloadedBooks() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *pgDB) GetTags() ([]string, error) {
|
||||
return []string{}, nil
|
||||
return db.tags, nil
|
||||
}
|
||||
|
||||
func (db *pgDB) UpdateTags() error {
|
||||
return nil
|
||||
func (db *pgDB) updateTags() {
|
||||
err := db.sql.Model(&Book{}).
|
||||
ColumnExpr("unnest(tags) as tag").
|
||||
Where("active = true").
|
||||
Group("tag").
|
||||
Order("count(*) DESC").
|
||||
Limit(tagsDisplay).
|
||||
Select(&db.tags)
|
||||
if err != nil {
|
||||
log.Error("Error updating tags: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (db *pgDB) GetVisits(visitType VisitType) ([]Visits, error) {
|
||||
return []Visits{}, nil
|
||||
}
|
||||
func (db *pgDB) tagUpdater() {
|
||||
periodicity := 57 * time.Minute
|
||||
|
||||
func (db *pgDB) UpdateHourVisits() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *pgDB) UpdateDayVisits() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *pgDB) UpdateMonthVisits() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *pgDB) UpdateHourDownloads() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *pgDB) UpdateDayDownloads() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *pgDB) UpdateMonthDownloads() error {
|
||||
return nil
|
||||
for true {
|
||||
db.updateTags()
|
||||
time.Sleep(periodicity)
|
||||
}
|
||||
}
|
||||
|
|
60
lib/stats.go
60
lib/stats.go
|
@ -4,7 +4,6 @@ import (
|
|||
log "github.com/cihub/seelog"
|
||||
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -93,65 +92,6 @@ func (sg StatsGatherer) worker() {
|
|||
}
|
||||
}
|
||||
|
||||
func statsHandler(h handler) {
|
||||
data := statsData{
|
||||
S: GetStatus(h),
|
||||
HVisits: getVisits(hourlyLabel, h.db, database.Hourly_visits),
|
||||
DVisits: getVisits(dailyLabel, h.db, database.Daily_visits),
|
||||
MVisits: getVisits(monthlyLabel, h.db, database.Monthly_visits),
|
||||
HDownloads: getVisits(hourlyLabel, h.db, database.Hourly_downloads),
|
||||
DDownloads: getVisits(dailyLabel, h.db, database.Daily_downloads),
|
||||
MDownloads: getVisits(monthlyLabel, h.db, database.Monthly_downloads),
|
||||
}
|
||||
data.S.Title = "Stats -- " + data.S.Title
|
||||
data.S.Stats = true
|
||||
h.template.load(h, "stats", data)
|
||||
}
|
||||
|
||||
type statsData struct {
|
||||
S Status
|
||||
HVisits []visitData
|
||||
DVisits []visitData
|
||||
MVisits []visitData
|
||||
HDownloads []visitData
|
||||
DDownloads []visitData
|
||||
MDownloads []visitData
|
||||
}
|
||||
|
||||
type visitData struct {
|
||||
Label string
|
||||
Count int
|
||||
}
|
||||
|
||||
func hourlyLabel(date time.Time) string {
|
||||
return strconv.Itoa(date.Hour() + 1)
|
||||
}
|
||||
|
||||
func dailyLabel(date time.Time) string {
|
||||
return strconv.Itoa(date.Day())
|
||||
}
|
||||
|
||||
func monthlyLabel(date time.Time) string {
|
||||
return date.Month().String()
|
||||
}
|
||||
|
||||
func getVisits(funcLabel func(time.Time) string, db database.DB, visitType database.VisitType) []visitData {
|
||||
var visits []visitData
|
||||
|
||||
visit, err := db.GetVisits(visitType)
|
||||
if err != nil {
|
||||
log.Warn("GetVisits error (", visitType, "): ", err)
|
||||
}
|
||||
for _, v := range visit {
|
||||
var elem visitData
|
||||
elem.Label = funcLabel(v.Date.UTC())
|
||||
elem.Count = v.Count
|
||||
visits = append(visits, elem)
|
||||
}
|
||||
|
||||
return visits
|
||||
}
|
||||
|
||||
func appendFiles(r *http.Request, stats map[string]interface{}) {
|
||||
if r.Method == "POST" && r.MultipartForm != nil {
|
||||
files := r.MultipartForm.File
|
||||
|
|
|
@ -9,40 +9,19 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
minutesUpdateTags = 11
|
||||
minutesUpdateVisited = 41
|
||||
minutesUpdateDownloaded = 47
|
||||
minutesUpdateHourlyV = 31
|
||||
minutesUpdateDailyV = 60*12 + 7
|
||||
minutesUpdateMonthlyV = 60*24 + 11
|
||||
minutesUpdateHourlyD = 29
|
||||
minutesUpdateDailyD = 60*12 + 13
|
||||
minutesUpdateMontlyD = 60*24 + 17
|
||||
minutesUpdateLogger = 5
|
||||
minutesUpdateLogger = 5
|
||||
)
|
||||
|
||||
func InitTasks(db database.DB, loggerConfig string) {
|
||||
updateLogger := func() error {
|
||||
return UpdateLogger(loggerConfig)
|
||||
}
|
||||
periodicTask(updateLogger, minutesUpdateLogger*time.Minute)
|
||||
|
||||
periodicTask(db.UpdateTags, minutesUpdateTags*time.Minute)
|
||||
periodicTask(db.UpdateMostVisited, minutesUpdateVisited*time.Minute)
|
||||
periodicTask(db.UpdateDownloadedBooks, minutesUpdateDownloaded*time.Minute)
|
||||
periodicTask(db.UpdateHourVisits, minutesUpdateHourlyV*time.Minute)
|
||||
periodicTask(db.UpdateDayVisits, minutesUpdateDailyV*time.Minute)
|
||||
periodicTask(db.UpdateMonthVisits, minutesUpdateMonthlyV*time.Minute)
|
||||
periodicTask(db.UpdateHourDownloads, minutesUpdateHourlyD*time.Minute)
|
||||
periodicTask(db.UpdateDayDownloads, minutesUpdateDailyD*time.Minute)
|
||||
periodicTask(db.UpdateMonthDownloads, minutesUpdateMontlyD*time.Minute)
|
||||
go tasker(updateLogger, minutesUpdateLogger)
|
||||
}
|
||||
|
||||
func periodicTask(task func() error, periodicity time.Duration) {
|
||||
go tasker(task, periodicity)
|
||||
}
|
||||
func tasker(task func() error, minutes int) {
|
||||
periodicity := time.Duration(minutes) * time.Minute
|
||||
|
||||
func tasker(task func() error, periodicity time.Duration) {
|
||||
for true {
|
||||
time.Sleep(periodicity)
|
||||
err := task()
|
||||
|
|
|
@ -73,7 +73,6 @@ func InitTemplate(assetsPath string) *Template {
|
|||
path.Join(templatePath, "edit.html"),
|
||||
path.Join(templatePath, "dashboard.html"),
|
||||
path.Join(templatePath, "settings.html"),
|
||||
path.Join(templatePath, "stats.html"),
|
||||
path.Join(templatePath, "help.html"),
|
||||
))
|
||||
|
||||
|
|
|
@ -178,7 +178,6 @@ func InitRouter(db database.DB, sg *StatsGatherer, assetsPath string) {
|
|||
r.HandleFunc("/help/", sg.Gather(helpHandler))
|
||||
r.HandleFunc("/download/{id:"+idPattern+"}/{epub:.*}", sg.Gather(downloadHandler))
|
||||
r.HandleFunc("/cover/{id:"+idPattern+"}/{size}/{img:.*}", sg.Gather(coverHandler))
|
||||
r.HandleFunc("/stats/", sg.Gather(statsHandler))
|
||||
|
||||
r.HandleFunc("/login/", sg.Gather(loginHandler)).Methods("GET")
|
||||
r.HandleFunc("/login/", sg.Gather(loginPostHandler)).Methods("POST")
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
<li {{if .About}}class="active"{{end}}><a href="/about/">About</a></li>
|
||||
<li {{if .News}}class="active"{{end}}><a href="/news/">News</a></li>
|
||||
<li {{if .Upload}}class="active"{{end}}><a href="/upload/">Upload</a></li>
|
||||
<li {{if .Stats}}class="active"{{end}}><a href="/stats/">Statistics</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav pull-right">
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
{{template "header.html" .S}}
|
||||
|
||||
<script src="/js/Chart.min.js"></script>
|
||||
|
||||
<div class="row">
|
||||
<div id="visits" class="span6">
|
||||
<h2>Visits</h2>
|
||||
<h4>Hourly:</h4>
|
||||
<canvas id="hvisits" height="400" width="500"></canvas>
|
||||
<h4>Daily:</h4>
|
||||
<canvas id="dvisits" height="400" width="500"></canvas>
|
||||
<h4>Monthly:</h4>
|
||||
<canvas id="mvisits" height="400" width="500"></canvas>
|
||||
</div>
|
||||
<div id="downloads" class="span6">
|
||||
<h2>Downloads</h2>
|
||||
<h4>Hourly:</h4>
|
||||
<canvas id="hdownloads" height="400" width="500"></canvas>
|
||||
<h4>Daily:</h4>
|
||||
<canvas id="ddownloads" height="400" width="500"></canvas>
|
||||
<h4>Monthly:</h4>
|
||||
<canvas id="mdownlodas" height="400" width="500"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
function chart(id, labels, counts) {
|
||||
var data = {
|
||||
labels : labels,
|
||||
datasets : [
|
||||
{
|
||||
fillColor : "rgba(151,187,205,0.5)",
|
||||
strokeColor : "rgba(151,187,205,1)",
|
||||
pointColor : "rgba(151,187,205,1)",
|
||||
pointStrokeColor : "#fff",
|
||||
data : counts
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
var ctx = $(id).get(0).getContext("2d");
|
||||
new Chart(ctx).Line(data);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
chart("#hvisits", [{{range .HVisits}}"{{.Label}}",{{end}}],
|
||||
[{{range .HVisits}}{{.Count}},{{end}}])
|
||||
chart("#dvisits", [{{range .DVisits}}"{{.Label}}",{{end}}],
|
||||
[{{range .DVisits}}{{.Count}},{{end}}])
|
||||
chart("#mvisits", [{{range .MVisits}}"{{.Label}}",{{end}}],
|
||||
[{{range .MVisits}}{{.Count}},{{end}}])
|
||||
|
||||
chart("#hdownloads", [{{range .HDownloads}}"{{.Label}}",{{end}}],
|
||||
[{{range .HDownloads}}{{.Count}},{{end}}])
|
||||
chart("#ddownloads", [{{range .DDownloads}}"{{.Label}}",{{end}}],
|
||||
[{{range .DDownloads}}{{.Count}},{{end}}])
|
||||
chart("#mdownlodas", [{{range .MDownloads}}"{{.Label}}",{{end}}],
|
||||
[{{range .MDownloads}}{{.Count}},{{end}}])
|
||||
})
|
||||
</script>
|
||||
|
||||
{{template "footer.html"}}
|
Reference in a new issue