Files
MMGame/backend/internal/database/database.go
T
gmh01 7614e79d12 refactor: rewrite backend in Go, replacing Python FastAPI
Port the FastAPI backend to Go 1.26, preserving all API functionality:
- auth (register/login/guest/logout/profile/history) with JWT + bcrypt
- scripts (list/detail) backed by embedded sample_data.json
- games (create/join/start/chat/phase/clue/vote/state/replay) + WebSocket
- rule-based NPC agent plus DeepSeek/Ollama AI backends
- SQLite persistence via modernc.org/sqlite (pure Go, no cgo)

Frontend and documents are unchanged.
2026-08-03 11:39:53 +08:00

119 lines
2.6 KiB
Go

package database
import (
"database/sql"
"strings"
_ "modernc.org/sqlite"
"mmgame/internal/config"
)
var DB *sql.DB
func normalizeDSN(url string) string {
if url == "" {
return "mmgame.db"
}
for _, prefix := range []string{"sqlite+aiosqlite:///", "sqlite:///"} {
if strings.HasPrefix(url, prefix) {
path := strings.TrimPrefix(url, prefix)
if path == ":memory:" {
return "file::memory:?cache=shared"
}
return path
}
}
return url
}
func Init() error {
dsn := normalizeDSN(config.Cfg.DatabaseURL)
db, err := sql.Open("sqlite", dsn)
if err != nil {
return err
}
db.SetMaxOpenConns(1)
if err := db.Ping(); err != nil {
return err
}
DB = db
return createTables()
}
func createTables() error {
stmts := []string{
`CREATE TABLE IF NOT EXISTS users (
id VARCHAR(36) PRIMARY KEY,
email VARCHAR(255) UNIQUE,
nickname VARCHAR(50),
avatar_url TEXT,
password_hash VARCHAR(255),
role VARCHAR(20) DEFAULT 'player',
is_guest BOOLEAN DEFAULT 0,
game_count INTEGER DEFAULT 0,
token_version INTEGER DEFAULT 0,
created_at TEXT
)`,
`CREATE TABLE IF NOT EXISTS game_sessions (
id VARCHAR(36) PRIMARY KEY,
script_id VARCHAR(36),
status VARCHAR(20) DEFAULT 'waiting',
phase VARCHAR(100) DEFAULT '',
phase_index INTEGER DEFAULT 0,
started_at TEXT,
completed_at TEXT,
config TEXT,
created_at TEXT
)`,
`CREATE TABLE IF NOT EXISTS session_players (
id VARCHAR(36) PRIMARY KEY,
session_id VARCHAR(36),
user_id VARCHAR(36),
role_id VARCHAR(100),
role_name VARCHAR(100) DEFAULT '',
is_human BOOLEAN DEFAULT 1,
is_ready BOOLEAN DEFAULT 0,
avatar_url TEXT,
status VARCHAR(20) DEFAULT 'active',
joined_at TEXT
)`,
`CREATE TABLE IF NOT EXISTS chat_messages (
id VARCHAR(36) PRIMARY KEY,
session_id VARCHAR(36),
sender_role_id VARCHAR(100),
sender_name VARCHAR(100) DEFAULT '',
message_type VARCHAR(20) DEFAULT 'public',
content TEXT,
target_role_id VARCHAR(100),
clue_id VARCHAR(100),
phase_index INTEGER DEFAULT 0,
created_at TEXT
)`,
`CREATE TABLE IF NOT EXISTS clues_state (
id VARCHAR(36) PRIMARY KEY,
session_id VARCHAR(36),
clue_id VARCHAR(100),
status VARCHAR(20) DEFAULT 'unreleased',
revealed_by VARCHAR(100),
released_at TEXT,
created_at TEXT
)`,
`CREATE TABLE IF NOT EXISTS votes (
id VARCHAR(36) PRIMARY KEY,
session_id VARCHAR(36),
round INTEGER DEFAULT 1,
voter_id VARCHAR(36),
target_id VARCHAR(36),
reason TEXT,
created_at TEXT
)`,
}
for _, s := range stmts {
if _, err := DB.Exec(s); err != nil {
return err
}
}
return nil
}