diff options
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/db.go | 5 | ||||
| -rw-r--r-- | backend/migrations/000_init.sql | 8 | ||||
| -rw-r--r-- | backend/router.go | 14 | ||||
| -rw-r--r-- | backend/stats.go | 47 |
4 files changed, 64 insertions, 10 deletions
diff --git a/backend/db.go b/backend/db.go index 3559b9c..3828880 100644 --- a/backend/db.go +++ b/backend/db.go @@ -23,7 +23,6 @@ func ConnectDatabase(cfg *Config) *sql.DB { if err != nil { panic(err) } - db.SetMaxOpenConns(1) return db } @@ -32,10 +31,6 @@ func RunMigration(ctx context.Context, db *sql.DB) error { if err != nil { return err } - type dbConfig struct { - Id int - Migration int - } type runMig struct { val string n int diff --git a/backend/migrations/000_init.sql b/backend/migrations/000_init.sql index 6bd9d3a..6dd385c 100644 --- a/backend/migrations/000_init.sql +++ b/backend/migrations/000_init.sql @@ -1,4 +1,6 @@ -CREATE TABLE IF NOT EXISTS config( - id INTEGER PRIMARY KEY AUTOINCREMENT, - migration INTEGER +CREATE TABLE IF NOT EXISTS stats( + id INTEGER PRIMARY KEY, + visit INTEGER NOT NULL, + origin TEXT NOT NULL, + target TEXT NOT NULL ); diff --git a/backend/router.go b/backend/router.go index b7403cf..7f9de5c 100644 --- a/backend/router.go +++ b/backend/router.go @@ -2,6 +2,7 @@ package backend import ( "context" + "database/sql" "embed" "fmt" "io/fs" @@ -45,7 +46,7 @@ func SetupLogger(debug bool) { slog.SetDefault(logger) } -func NewRouter(debug bool, cfg *Config, assets fs.FS) *chi.Mux { +func NewRouter(debug bool, cfg *Config, db *sql.DB, assets fs.FS) *chi.Mux { r := chi.NewRouter() logLevel := slog.LevelWarn @@ -70,7 +71,7 @@ func NewRouter(debug bool, cfg *Config, assets fs.FS) *chi.Mux { r.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // prevent tracking - w.Header().Add("Referrer-Policy", "no-referrer") + w.Header().Add("Referrer-Policy", "same-origin") // prevent iframe w.Header().Add("X-Frame-Options", "deny") // prevent bad content being parsed @@ -94,6 +95,15 @@ func NewRouter(debug bool, cfg *Config, assets fs.FS) *chi.Mux { next.ServeHTTP(w, r.WithContext(ctx)) }) }) + // stats + r.Use(func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if err := UpdateStats(r.Context(), db, r); err != nil { + slog.Error("updating stats", "error", err) + } + next.ServeHTTP(w, r) + }) + }) return r } diff --git a/backend/stats.go b/backend/stats.go new file mode 100644 index 0000000..e2ad08b --- /dev/null +++ b/backend/stats.go @@ -0,0 +1,47 @@ +package backend + +import ( + "context" + "database/sql" + "net/http" + "regexp" + "strings" +) + +var trimRefererReg = regexp.MustCompile(`https?://([a-z-0-9.]+)(:\d+)?/.*`) + +func UpdateStats(ctx context.Context, db *sql.DB, r *http.Request) error { + target := r.URL.Path + if strings.HasPrefix(target, "/assets") || strings.HasPrefix(target, "/static") { + return nil + } + ref := r.Header.Get("Referer") + if ref == "" { + return nil + } + subs := trimRefererReg.FindStringSubmatch(ref) + if len(subs) < 2 { + return nil + } + ref = subs[1] + if ref == ctx.Value(configKey).(*Config).Domain { + ref = subs[0][strings.Index(subs[0], ref)+len(ref):] + } + rows, err := db.QueryContext(ctx, "SELECT id, visit FROM stats WHERE origin = ? AND target = ?", ref, target) + if err != nil { + return err + } + if !rows.Next() { + _, err = db.ExecContext(ctx, "INSERT INTO stats (origin, target, visit) VALUES (?, ?, 1)", ref, target) + return err + } + var id uint + var nb uint + rows.Scan(&id, &nb) + err = rows.Close() + if err != nil { + return err + } + _, err = db.ExecContext(ctx, "UPDATE stats SET visit = ? WHERE id = ?", nb+1, id) + return err +} |
