diff --git a/Dockerfile b/Dockerfile index 4679adb..8377f22 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,17 @@ FROM golang:alpine AS builder +# go-sqlite3 is a cgo package, so it needs a C toolchain +RUN apk add --no-cache gcc musl-dev + WORKDIR /app COPY go.mod go.sum ./ -COPY *.go ./ +RUN go mod download +COPY *.go ./ +COPY seed.sql ./ + +ENV CGO_ENABLED=1 RUN go build -o server . FROM alpine:latest diff --git a/connections.go b/connections.go index fed51b2..2be8246 100644 --- a/connections.go +++ b/connections.go @@ -2,12 +2,15 @@ package main import ( "database/sql" - "log" + _ "embed" "time" _ "github.com/mattn/go-sqlite3" ) +//go:embed seed.sql +var seedSQL string + // logs level=('debug', 'info', 'warning', 'error') type logs struct { level string @@ -20,22 +23,25 @@ type dbStruct struct { db *sql.DB } +// Seed runs the schema in seed.sql. Idempotent via CREATE TABLE IF NOT EXISTS, +// so it's safe to call on every startup. +func (app *dbStruct) Seed() error { + _, err := app.db.Exec(seedSQL) + return err +} + // InsertLog() : database method, only inserts level + traceback -func (app *dbStruct) InsertLog(lg logs) { +func (app *dbStruct) InsertLog(lg logs) error { query := `INSERT INTO logs (level, traceback) VALUES (?, ?)` _, err := app.db.Exec(query, lg.level, lg.traceback) - if err != nil { - log.Fatal(err) - } + return err } -// InsertLog() : database method, logs level + Ip -func (app *dbStruct) LogIp(lg logs) { +// LogIp() : database method, logs level + Ip +func (app *dbStruct) LogIp(lg logs) error { query := `INSERT INTO logs (level, ip) VALUES (?, ?)` _, err := app.db.Exec(query, lg.level, lg.ip) - if err != nil { - log.Fatal(err) - } + return err } diff --git a/docker-compose.yml b/docker-compose.yml index 52849c2..bc6e69e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,8 @@ services: website: env_file: .env + environment: + DB_PATH: /app/data/zum.db build: context: . dockerfile: Dockerfile @@ -8,4 +10,6 @@ services: container_name: acidarchon.com ports: - 8088:8080 + volumes: + - /dockers/acidarchon:/app/data restart: unless-stopped diff --git a/main.go b/main.go index 5793835..91836ae 100644 --- a/main.go +++ b/main.go @@ -52,7 +52,12 @@ func main() { godotenv.Load() mux := http.NewServeMux() - db, err := sql.Open("sqlite3", "zum.db") + dbPath := os.Getenv("DB_PATH") + if dbPath == "" { + dbPath = "zum.db" + } + + db, err := sql.Open("sqlite3", dbPath) if err != nil { slog.Error("err opening db") return @@ -61,6 +66,11 @@ func main() { database := &dbStruct{db: db} + if err := database.Seed(); err != nil { + slog.Error("seeding db", "err", err) + return + } + // routes mux.HandleFunc("/", database.handleRoot) mux.HandleFunc("/robots.txt", serveRobots) @@ -79,7 +89,9 @@ func (app *dbStruct) handleRoot(w http.ResponseWriter, r *http.Request) { templ, err := template.ParseFiles("templates/home.html") if err != nil { http.Error(w, "template not found", http.StatusInternalServerError) - app.InsertLog(logs{level: "error", traceback: "template not found"}) + if logErr := app.InsertLog(logs{level: "error", traceback: "template not found"}); logErr != nil { + slog.Error("failed to write log", "err", logErr) + } return } @@ -97,7 +109,9 @@ func (app *dbStruct) handleRoot(w http.ResponseWriter, r *http.Request) { dox := callApi(host) dox2 := secondApi(host) - app.LogIp(logs{level: "info", ip: dox.IP}) + if logErr := app.LogIp(logs{level: "info", ip: dox.IP}); logErr != nil { + slog.Error("failed to write log", "err", logErr) + } templ.Execute(w, TemolateData{Ip: dox, IP2: *dox2}) } diff --git a/seed.sql b/seed.sql index 0ce9ac0..c574724 100644 --- a/seed.sql +++ b/seed.sql @@ -3,5 +3,5 @@ CREATE TABLE IF NOT EXISTS logs ( level TEXT NOT NULL CHECK(level IN ('debug', 'info', 'warning', 'error')), ip TEXT, traceback TEXT, - date DATETIME DEFAULT (datetime('now', 'localtime')), + date DATETIME DEFAULT (datetime('now', 'localtime')) );