aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorAnhgelus Morhtuuzh <william@herges.fr>2025-12-22 18:34:02 +0100
committerAnhgelus Morhtuuzh <william@herges.fr>2025-12-22 18:34:02 +0100
commitcbd5c09c5e1403709d4aabf91051443f147689e5 (patch)
tree5add0c1a15df56ec121a77f3d4bd895c7d5f19df /backend
parent9bba6dcbb2e83fe53604d38b89fb79ce47eacddd (diff)
refactor(backend): move db related in new package
Diffstat (limited to 'backend')
-rw-r--r--backend/admin.go53
-rw-r--r--backend/router.go6
-rw-r--r--backend/storage/db.go (renamed from backend/db.go)6
-rw-r--r--backend/storage/migrations/000_init.sql (renamed from backend/migrations/000_init.sql)0
-rw-r--r--backend/storage/stats.go (renamed from backend/stats.go)78
5 files changed, 76 insertions, 67 deletions
diff --git a/backend/admin.go b/backend/admin.go
new file mode 100644
index 0000000..087a3ea
--- /dev/null
+++ b/backend/admin.go
@@ -0,0 +1,53 @@
+package backend
+
+import (
+ "log/slog"
+ "net/http"
+ "strconv"
+
+ "git.anhgelus.world/anhgelus/small-web/backend/storage"
+ "github.com/go-chi/chi/v5"
+)
+
+type adminData struct {
+ *data
+ Visits []storage.StatsRow
+ Rows []storage.StatsRow
+ PagesNumber int
+ CurrentPage int
+}
+
+func HandleAdmin(r *chi.Mux) {
+ r.Get("/admin", func(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ if !ctx.Value(loginKey).(bool) {
+ w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
+ return
+ }
+ d := new(adminData)
+ d.data = new(data)
+ rawPage := r.URL.Query().Get("page")
+ page := 1
+ var err error
+ if rawPage != "" {
+ page, err = strconv.Atoi(rawPage)
+ if err != nil || page < 1 {
+ slog.Warn("invalid page number", "rawPage", rawPage)
+ http.Error(w, "Bad request", http.StatusBadRequest)
+ return
+ }
+ }
+ d.Rows, err = storage.GetStatsRows(ctx, uint(page))
+ if err != nil {
+ panic(err)
+ }
+ d.Visits, err = storage.GetUnionStatsRows(ctx)
+ if err != nil {
+ panic(err)
+ }
+ d.PagesNumber = page + max(len(d.Rows)-storage.StatsPerPage+1, 0)
+ d.CurrentPage = page
+ d.handleGeneric(w, r, "admin", d)
+ })
+}
diff --git a/backend/router.go b/backend/router.go
index f2ed775..161433d 100644
--- a/backend/router.go
+++ b/backend/router.go
@@ -14,6 +14,7 @@ import (
"strings"
"time"
+ "git.anhgelus.world/anhgelus/small-web/backend/storage"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/httplog/v3"
@@ -24,7 +25,6 @@ const (
configKey = "config"
assetsFSKey = "assets_fs"
debugKey = "debug"
- dbKey = "db"
loginKey = "login"
)
@@ -95,7 +95,7 @@ func NewRouter(debug bool, cfg *Config, db *sql.DB, assets fs.FS) *chi.Mux {
ctx = context.WithValue(ctx, configKey, cfg)
ctx = context.WithValue(ctx, assetsFSKey, assets)
ctx = context.WithValue(ctx, debugKey, debug)
- return context.WithValue(ctx, dbKey, db)
+ return context.WithValue(ctx, storage.DBKey, db)
}
r.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -108,7 +108,7 @@ func NewRouter(debug bool, cfg *Config, db *sql.DB, assets fs.FS) *chi.Mux {
go func(r *http.Request) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
- if err := UpdateStats(setContext(ctx), r); err != nil {
+ if err := storage.UpdateStats(setContext(ctx), r, cfg.Domain); err != nil {
slog.Error("updating stats", "error", err)
}
}(r)
diff --git a/backend/db.go b/backend/storage/db.go
index 3828880..7a7c6e0 100644
--- a/backend/db.go
+++ b/backend/storage/db.go
@@ -1,4 +1,4 @@
-package backend
+package storage
import (
"context"
@@ -18,8 +18,8 @@ var migrations embed.FS
var nameReg = regexp.MustCompile(`(\d{3})_[a-zA-Z_-]+.sql`)
-func ConnectDatabase(cfg *Config) *sql.DB {
- db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared", cfg.Database))
+func ConnectDatabase(file string) *sql.DB {
+ db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared", file))
if err != nil {
panic(err)
}
diff --git a/backend/migrations/000_init.sql b/backend/storage/migrations/000_init.sql
index 6dd385c..6dd385c 100644
--- a/backend/migrations/000_init.sql
+++ b/backend/storage/migrations/000_init.sql
diff --git a/backend/stats.go b/backend/storage/stats.go
index f081194..757168d 100644
--- a/backend/stats.go
+++ b/backend/storage/stats.go
@@ -1,4 +1,4 @@
-package backend
+package storage
import (
"context"
@@ -8,14 +8,13 @@ import (
"net/http"
"regexp"
"slices"
- "strconv"
"strings"
"sync"
"time"
-
- "github.com/go-chi/chi/v5"
)
+const DBKey = "db"
+
type loaded struct {
data map[string]struct{}
mu *sync.RWMutex
@@ -52,10 +51,10 @@ var trimRefererReg = regexp.MustCompile(`https?://([a-z-0-9.]+(:\d+)?)/.*`)
var load = newLoaded()
func getDB(ctx context.Context) *sql.DB {
- return ctx.Value(dbKey).(*sql.DB)
+ return ctx.Value(DBKey).(*sql.DB)
}
-func UpdateStats(ctx context.Context, r *http.Request) error {
+func UpdateStats(ctx context.Context, r *http.Request, domain string) error {
target := r.URL.Path
if strings.HasPrefix(target, "/static") || strings.HasPrefix(target, "/admin") {
return nil
@@ -69,7 +68,7 @@ func UpdateStats(ctx context.Context, r *http.Request) error {
return nil
}
ref = subs[1]
- if ref == ctx.Value(configKey).(*Config).Domain || ref == fmt.Sprintf("localhost:%d", 8000) {
+ if ref == domain || ref == fmt.Sprintf("localhost:%d", 8000) {
ref = subs[0][strings.Index(subs[0], ref)+len(ref):]
if ref == target || strings.HasPrefix(ref, "/admin") || ref == "/favicon.ico" {
return nil
@@ -116,28 +115,28 @@ func UpdateStats(ctx context.Context, r *http.Request) error {
return err
}
-type statRow struct {
+type StatsRow struct {
Origin string
Target string
Visit uint
}
-const statPerPage = 25
+const StatsPerPage = 25
-func GetStatRows(ctx context.Context, page uint) ([]statRow, error) {
+func GetStatsRows(ctx context.Context, page uint) ([]StatsRow, error) {
rows, err := getDB(ctx).QueryContext(
ctx,
"SELECT origin, target, visit FROM stats ORDER BY visit DESC LIMIT ? OFFSET ?",
- statPerPage, (page-1)*statPerPage,
+ StatsPerPage, (page-1)*StatsPerPage,
)
if err != nil {
return nil, err
}
defer rows.Close()
- statRows := make([]statRow, statPerPage)
+ statRows := make([]StatsRow, StatsPerPage)
var i uint8
for i = 0; rows.Next(); i++ {
- var stat statRow
+ var stat StatsRow
err = rows.Scan(&stat.Origin, &stat.Target, &stat.Visit)
if err != nil {
return nil, err
@@ -150,7 +149,7 @@ func GetStatRows(ctx context.Context, page uint) ([]statRow, error) {
return statRows[:i], nil
}
-func GetUnionStatRows(ctx context.Context) ([]statRow, error) {
+func GetUnionStatsRows(ctx context.Context) ([]StatsRow, error) {
rows, err := getDB(ctx).QueryContext(ctx, "SELECT target, visit FROM stats ORDER BY visit DESC")
if err != nil {
return nil, err
@@ -158,7 +157,7 @@ func GetUnionStatRows(ctx context.Context) ([]statRow, error) {
defer rows.Close()
data := make(map[string]uint)
for rows.Next() {
- var stat statRow
+ var stat StatsRow
err = rows.Scan(&stat.Target, &stat.Visit)
if err != nil {
return nil, err
@@ -169,58 +168,15 @@ func GetUnionStatRows(ctx context.Context) ([]statRow, error) {
data[stat.Target] += stat.Visit
}
}
- var statRows []statRow
+ var statRows []StatsRow
for k, v := range data {
- statRows = append(statRows, statRow{
+ statRows = append(statRows, StatsRow{
Target: k,
Visit: v,
})
}
- slices.SortFunc(statRows, func(a, b statRow) int {
+ slices.SortFunc(statRows, func(a, b StatsRow) int {
return int(b.Visit) - int(a.Visit)
})
return statRows, nil
}
-
-type adminData struct {
- *data
- Visits []statRow
- Rows []statRow
- PagesNumber int
- CurrentPage int
-}
-
-func HandleAdmin(r *chi.Mux) {
- r.Get("/admin", func(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- if !ctx.Value(loginKey).(bool) {
- w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
- http.Error(w, "Unauthorized", http.StatusUnauthorized)
- return
- }
- d := new(adminData)
- d.data = new(data)
- rawPage := r.URL.Query().Get("page")
- page := 1
- var err error
- if rawPage != "" {
- page, err = strconv.Atoi(rawPage)
- if err != nil || page < 1 {
- slog.Warn("invalid page number", "rawPage", rawPage)
- http.Error(w, "Bad request", http.StatusBadRequest)
- return
- }
- }
- d.Rows, err = GetStatRows(ctx, uint(page))
- if err != nil {
- panic(err)
- }
- d.Visits, err = GetUnionStatRows(ctx)
- if err != nil {
- panic(err)
- }
- d.PagesNumber = page + max(len(d.Rows)-statPerPage+1, 0)
- d.CurrentPage = page
- d.handleGeneric(w, r, "admin", d)
- })
-}