summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-03-10 23:50:58 +0530
committerBobby <[email protected]>2026-03-10 23:50:58 +0530
commitfd9d558154eac3585310626f697b943d90e1bf7f (patch)
tree90f88ce4a0ad68a71d8431990754bb7e04b18101
parenta3a6c652dfdc450f014df0a67b0890acdec4a7ce (diff)
downloadpagoda-fd9d558154eac3585310626f697b943d90e1bf7f.tar.xz
pagoda-fd9d558154eac3585310626f697b943d90e1bf7f.zip
feat: add support for LibSQL database driver and enhance seeding process
-rw-r--r--Dockerfile9
-rw-r--r--scripts/entrypoint.sh21
-rwxr-xr-xscripts/seed.sh56
-rw-r--r--shrine/config/functions.go2
-rw-r--r--shrine/database/database.go10
-rw-r--r--shrine/enums/database.go1
-rw-r--r--shrine/go.mod4
-rw-r--r--shrine/go.sum8
-rw-r--r--shrine/messages/system.go1
9 files changed, 101 insertions, 11 deletions
diff --git a/Dockerfile b/Dockerfile
index cdc3127..a6f8883 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,9 +16,14 @@ FROM debian:bookworm-slim
WORKDIR /shrine
-RUN apt-get update && apt-get install -y ca-certificates tzdata && rm -rf /var/lib/apt/lists/*
+RUN apt-get update && \
+ apt-get install -y ca-certificates tzdata curl sqlite3 apache2-utils && \
+ rm -rf /var/lib/apt/lists/*
COPY --from=builder /shrine/bin/shrine .
COPY --from=builder /shrine/templates ./templates
+COPY scripts/ ./scripts/
+COPY seed/ ./seed/
+RUN chmod +x /shrine/scripts/entrypoint.sh
-CMD ["./shrine"]
+CMD ["bash", "scripts/entrypoint.sh"]
diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh
new file mode 100644
index 0000000..3ff3886
--- /dev/null
+++ b/scripts/entrypoint.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+set -e
+
+./shrine &
+SHRINE_PID=$!
+
+if [ "$SEED" = "true" ]; then
+ RETRIES=0
+ MAX_RETRIES=30
+ until bash -c "echo > /dev/tcp/localhost/${PORT:-3000}" 2>/dev/null; do
+ RETRIES=$((RETRIES + 1))
+ if [ "$RETRIES" -ge "$MAX_RETRIES" ]; then
+ echo "Server failed to start after ${MAX_RETRIES}s"
+ exit 1
+ fi
+ sleep 1
+ done
+ bash scripts/seed.sh
+fi
+
+wait $SHRINE_PID \ No newline at end of file
diff --git a/scripts/seed.sh b/scripts/seed.sh
index 4cded48..c6812d2 100755
--- a/scripts/seed.sh
+++ b/scripts/seed.sh
@@ -1,16 +1,56 @@
#!/bin/bash
set -euo pipefail
-DB_PATH="shrine/pagoda.db"
SEED_DIR="seed"
+DB_DRIVER="${DB_DRIVER:-sqlite}"
+DSN="${DSN:-shrine/pagoda.db}"
-if [ ! -f "$DB_PATH" ]; then
- echo "Database not found at $DB_PATH"
+if [ "$DB_DRIVER" = "libsql" ]; then
+ TURSO_URL=$(echo "$DSN" | sed 's|^libsql://|https://|; s|?.*||')
+ TURSO_TOKEN=$(echo "$DSN" | sed -n 's/.*authToken=\(.*\)/\1/p')
+fi
+
+exec_sql_file() {
+ if [ "$DB_DRIVER" = "sqlite" ]; then
+ sqlite3 "$DSN" < "$1"
+ elif [ "$DB_DRIVER" = "libsql" ]; then
+ local STMTS=""
+ while IFS= read -r line; do
+ line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+ [ -z "$line" ] && continue
+ [ "$line" = "BEGIN TRANSACTION;" ] && continue
+ [ "$line" = "COMMIT;" ] && continue
+ local ESCAPED
+ ESCAPED=$(printf '%s' "$line" | sed 's/\\/\\\\/g; s/"/\\"/g')
+ STMTS="${STMTS}{\"type\":\"execute\",\"stmt\":{\"sql\":\"${ESCAPED}\"}},"
+ done < "$1"
+ STMTS="${STMTS%,}"
+ curl -sf "${TURSO_URL}/v2/pipeline" \
+ -H "Authorization: Bearer ${TURSO_TOKEN}" \
+ -H "Content-Type: application/json" \
+ -d "{\"requests\":[${STMTS},{\"type\":\"close\"}]}" > /dev/null
+ fi
+}
+
+query_sql() {
+ if [ "$DB_DRIVER" = "sqlite" ]; then
+ sqlite3 "$DSN" "$1"
+ elif [ "$DB_DRIVER" = "libsql" ]; then
+ curl -sf "${TURSO_URL}/v2/pipeline" \
+ -H "Authorization: Bearer ${TURSO_TOKEN}" \
+ -H "Content-Type: application/json" \
+ -d "{\"requests\":[{\"type\":\"execute\",\"stmt\":{\"sql\":\"$1\"}},{\"type\":\"close\"}]}" \
+ | sed -n 's/.*"value":"\([^"]*\)".*/\1/p' | head -1
+ fi
+}
+
+if [ "$DB_DRIVER" = "sqlite" ] && [ ! -f "$DSN" ]; then
+ echo "Database not found at $DSN"
exit 1
fi
-EXISTING=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM users;")
-if [ "$EXISTING" -gt 0 ]; then
+EXISTING=$(query_sql "SELECT COUNT(*) FROM users;")
+if [ -n "$EXISTING" ] && [ "$EXISTING" -gt 0 ] 2>/dev/null; then
echo "Database already has $EXISTING users, skipping seed"
exit 0
fi
@@ -273,8 +313,8 @@ done
echo "COMMIT;" >> "$SQL_FILE"
-echo "Inserting into database..."
-sqlite3 "$DB_PATH" < "$SQL_FILE"
+echo "Inserting into database ($DB_DRIVER)..."
+exec_sql_file "$SQL_FILE"
-TOTAL=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM users;")
+TOTAL=$(query_sql "SELECT COUNT(*) FROM users;")
echo "Done. Total users: $TOTAL (admins: $ADMIN_COUNT, mods: $MOD_COUNT, banned: $BANNED_COUNT, disabled: $DISABLED_COUNT, unverified: $UNVERIFIED_COUNT)" \ No newline at end of file
diff --git a/shrine/config/functions.go b/shrine/config/functions.go
index ba55c75..d9fd5e4 100644
--- a/shrine/config/functions.go
+++ b/shrine/config/functions.go
@@ -24,7 +24,7 @@ func verifyConfig() error {
func verifyDatabaseDriver(driver enums.DatabaseDriver) bool {
switch driver {
- case enums.SQLite, enums.Postgres:
+ case enums.SQLite, enums.Postgres, enums.LibSQL:
return true
default:
return false
diff --git a/shrine/database/database.go b/shrine/database/database.go
index 0defd36..fed6232 100644
--- a/shrine/database/database.go
+++ b/shrine/database/database.go
@@ -3,9 +3,13 @@ package database
import (
"shrine/config"
"shrine/enums"
+ "shrine/messages"
"shrine/utils/logger"
"time"
+ "database/sql"
+
+ _ "github.com/tursodatabase/libsql-client-go/libsql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
@@ -28,6 +32,12 @@ func init() {
dialector = sqlite.Open(config.Database.DSN)
case enums.Postgres:
dialector = postgres.Open(config.Database.DSN)
+ case enums.LibSQL:
+ db, err := sql.Open("libsql", config.Database.DSN)
+ if err != nil {
+ logger.Fatalf("Database", messages.FailedLibSQLConnection, err)
+ }
+ dialector = sqlite.Dialector{Conn: db}
default:
logger.Fatalf("Database", "Invalid database driver: %s", config.Database.Driver)
}
diff --git a/shrine/enums/database.go b/shrine/enums/database.go
index d57ef13..bd43b7c 100644
--- a/shrine/enums/database.go
+++ b/shrine/enums/database.go
@@ -5,4 +5,5 @@ type DatabaseDriver string
const (
SQLite DatabaseDriver = "sqlite"
Postgres DatabaseDriver = "postgres"
+ LibSQL DatabaseDriver = "libsql"
)
diff --git a/shrine/go.mod b/shrine/go.mod
index 47861c0..a8bad64 100644
--- a/shrine/go.mod
+++ b/shrine/go.mod
@@ -17,10 +17,12 @@ require (
require (
github.com/andybalholm/brotli v1.1.0 // indirect
+ github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327 // indirect
github.com/chromedp/chromedp v0.14.2 // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
+ github.com/coder/websocket v1.8.12 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2 // indirect
@@ -50,11 +52,13 @@ require (
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/tinylib/msgp v1.6.1 // indirect
+ github.com/tursodatabase/libsql-client-go v0.0.0-20251219100830-236aa1ff8acc // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
+ golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/image v0.36.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sync v0.19.0 // indirect
diff --git a/shrine/go.sum b/shrine/go.sum
index 4e9e7ae..518450b 100644
--- a/shrine/go.sum
+++ b/shrine/go.sum
@@ -1,5 +1,7 @@
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
+github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
+github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327 h1:UQ4AU+BGti3Sy/aLU8KVseYKNALcX9UXY6DfpwQ6J8E=
@@ -8,6 +10,8 @@ github.com/chromedp/chromedp v0.14.2 h1:r3b/WtwM50RsBZHMUm9fsNhhzRStTHrKdr2zmwbZ
github.com/chromedp/chromedp v0.14.2/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
+github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
+github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -92,6 +96,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tinylib/msgp v1.6.1 h1:ESRv8eL3u+DNHUoSAAQRE50Hm162zqAnBoGv9PzScPY=
github.com/tinylib/msgp v1.6.1/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
+github.com/tursodatabase/libsql-client-go v0.0.0-20251219100830-236aa1ff8acc h1:lzi/5fg2EfinRlh3v//YyIhnc4tY7BTqazQGwb1ar+0=
+github.com/tursodatabase/libsql-client-go v0.0.0-20251219100830-236aa1ff8acc/go.mod h1:08inkKyguB6CGGssc/JzhmQWwBgFQBgjlYFjxjRh7nU=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
@@ -108,6 +114,8 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
+golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
+golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
diff --git a/shrine/messages/system.go b/shrine/messages/system.go
index e6fe442..5275e99 100644
--- a/shrine/messages/system.go
+++ b/shrine/messages/system.go
@@ -10,4 +10,5 @@ const (
CannotActionSelf = "You cannot %s yourself."
CannotActionOwner = "You cannot %s the owner."
OnlyOwnerCanActionAdmin = "Only the owner can %s an administrator."
+ FailedLibSQLConnection = "Failed to open libsql connection: %v."
) \ No newline at end of file