mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-21 23:22:34 +01:00
Add zero-dependency SQLite mode so users can run Erupe without
PostgreSQL. A transparent db.DB wrapper auto-translates PostgreSQL
SQL ($N placeholders, now(), ::casts, ILIKE, public. prefix,
TRUNCATE) for SQLite at runtime — all 28 repo files use the wrapper
with no per-query changes needed.
Setup wizard gains two new steps: quest file detection with download
link, and gameplay presets (solo/small/community/rebalanced). The API
server gets a /dashboard endpoint with auto-refreshing stats.
CI release workflow now builds and pushes Docker images to GHCR
alongside binary artifacts on tag push.
Key changes:
- common/db: DB/Tx wrapper with 6 SQL translation rules
- server/migrations/sqlite: full SQLite schema (0001-0005)
- config: Database.Driver field ("postgres" or "sqlite")
- main.go: SQLite connection with WAL mode, single writer
- server/setup: quest check + preset selection steps
- server/api: /dashboard with live stats
- .github/workflows: Docker in release, deduplicate docker.yml
96 lines
3.4 KiB
Go
96 lines
3.4 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
dbutil "erupe-ce/common/db"
|
|
)
|
|
|
|
// EventQuest represents a row from the event_quests table.
|
|
type EventQuest struct {
|
|
ID uint32 `db:"id"`
|
|
MaxPlayers uint8 `db:"max_players"`
|
|
QuestType uint8 `db:"quest_type"`
|
|
QuestID int `db:"quest_id"`
|
|
Mark uint32 `db:"mark"`
|
|
Flags int `db:"flags"`
|
|
StartTime time.Time `db:"start_time"`
|
|
ActiveDays int `db:"active_days"`
|
|
InactiveDays int `db:"inactive_days"`
|
|
}
|
|
|
|
// EventRepository centralizes all database access for event-related tables.
|
|
type EventRepository struct {
|
|
db *dbutil.DB
|
|
}
|
|
|
|
// NewEventRepository creates a new EventRepository.
|
|
func NewEventRepository(db *dbutil.DB) *EventRepository {
|
|
return &EventRepository{db: db}
|
|
}
|
|
|
|
// GetFeatureWeapon returns the featured weapon bitfield for a given start time.
|
|
func (r *EventRepository) GetFeatureWeapon(startTime time.Time) (activeFeature, error) {
|
|
var af activeFeature
|
|
err := r.db.QueryRowx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1`, startTime).StructScan(&af)
|
|
return af, err
|
|
}
|
|
|
|
// InsertFeatureWeapon stores a new featured weapon entry.
|
|
func (r *EventRepository) InsertFeatureWeapon(startTime time.Time, features uint32) error {
|
|
_, err := r.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, startTime, features)
|
|
return err
|
|
}
|
|
|
|
// GetLoginBoosts returns all login boost rows for a character, ordered by week_req.
|
|
func (r *EventRepository) GetLoginBoosts(charID uint32) ([]loginBoost, error) {
|
|
var result []loginBoost
|
|
err := r.db.Select(&result, "SELECT week_req, expiration, reset FROM login_boost WHERE char_id=$1 ORDER BY week_req", charID)
|
|
return result, err
|
|
}
|
|
|
|
// InsertLoginBoost creates a new login boost entry.
|
|
func (r *EventRepository) InsertLoginBoost(charID uint32, weekReq uint8, expiration, reset time.Time) error {
|
|
_, err := r.db.Exec(`INSERT INTO login_boost VALUES ($1, $2, $3, $4)`, charID, weekReq, expiration, reset)
|
|
return err
|
|
}
|
|
|
|
// UpdateLoginBoost updates expiration and reset for a login boost entry.
|
|
func (r *EventRepository) UpdateLoginBoost(charID uint32, weekReq uint8, expiration, reset time.Time) error {
|
|
_, err := r.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, expiration, reset, charID, weekReq)
|
|
return err
|
|
}
|
|
|
|
// GetEventQuests returns all event quest rows ordered by quest_id.
|
|
func (r *EventRepository) GetEventQuests() ([]EventQuest, error) {
|
|
var result []EventQuest
|
|
err := r.db.Select(&result, "SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark, COALESCE(flags, -1) AS flags, start_time, COALESCE(active_days, 0) AS active_days, COALESCE(inactive_days, 0) AS inactive_days FROM event_quests ORDER BY quest_id")
|
|
return result, err
|
|
}
|
|
|
|
// EventQuestUpdate pairs a quest ID with its new start time.
|
|
type EventQuestUpdate struct {
|
|
ID uint32
|
|
StartTime time.Time
|
|
}
|
|
|
|
// UpdateEventQuestStartTimes batch-updates start times within a single transaction.
|
|
func (r *EventRepository) UpdateEventQuestStartTimes(updates []EventQuestUpdate) error {
|
|
if len(updates) == 0 {
|
|
return nil
|
|
}
|
|
tx, err := r.db.BeginTxx(context.Background(), nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() { _ = tx.Rollback() }()
|
|
|
|
for _, u := range updates {
|
|
if _, err := tx.Exec("UPDATE event_quests SET start_time = $1 WHERE id = $2", u.StartTime, u.ID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return tx.Commit()
|
|
}
|