mirror of
https://github.com/renorris/openfsd
synced 2026-03-22 23:05:36 +08:00
Changes:
- Implement bootstrapping library for managing several concurrent internal services
- Refactor concurrency model for connections/logical clients and their associated I/O
- Refactor server context singleton
- Refactor error handling
- Most errors are now gracefully sent to the FSD client directly encoded as an $ER packet,
enhancing visibility and debugging
- Most errors are now rightfully treated as non-fatal
- Refactor package/dependency graph
- Refactor calling conventions/interfaces for many packages
- Refactor database package
- Refactor post office
Features:
- Add VATSIM-esque HTTP/JSON "data feed"
- Add ephemeral in-memory database option
- Add user management REST API
- Add improved web interface
- Add MySQL support (drop SQLite support)
103 lines
2.3 KiB
Go
103 lines
2.3 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"database/sql"
|
|
"encoding/hex"
|
|
"github.com/renorris/openfsd/protocol"
|
|
"io"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
const createUsersTableStatement = `
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
cid INT PRIMARY KEY AUTO_INCREMENT,
|
|
email VARCHAR(255),
|
|
first_name VARCHAR(255),
|
|
last_name VARCHAR(255),
|
|
password CHAR(60) NOT NULL,
|
|
fsd_password CHAR(60) NOT NULL,
|
|
network_rating INT NOT NULL,
|
|
pilot_rating INT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
)
|
|
`
|
|
|
|
// Initialize initializes a database `db`
|
|
func Initialize(db *sql.DB) error {
|
|
if err := initializeUserTable(db); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func initializeUserTable(db *sql.DB) error {
|
|
ctx, cancelCtx := context.WithTimeout(context.Background(), 60*time.Second)
|
|
defer cancelCtx()
|
|
|
|
// Execute create users table if not exists
|
|
var err error
|
|
if _, err = db.ExecContext(ctx, createUsersTableStatement); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set auto_increment to the initial CID value
|
|
if _, err = db.ExecContext(ctx, "ALTER TABLE users AUTO_INCREMENT 100000"); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Check if the table is empty
|
|
var emptyCheckStmt *sql.Stmt
|
|
if emptyCheckStmt, err = db.PrepareContext(ctx, "SELECT EXISTS (SELECT 1 FROM users)"); err != nil {
|
|
return err
|
|
}
|
|
|
|
var exists int64
|
|
if err = emptyCheckStmt.QueryRowContext(ctx).Scan(&exists); err != nil {
|
|
return err
|
|
}
|
|
if exists == 0 {
|
|
// Generate a default user if the table is empty
|
|
randBytes := make([]byte, 32)
|
|
if _, err = io.ReadFull(rand.Reader, randBytes); err != nil {
|
|
return err
|
|
}
|
|
|
|
primaryPassword := hex.EncodeToString(randBytes[0:16])
|
|
fsdPassword := hex.EncodeToString(randBytes[16:32])
|
|
|
|
defaultUser := FSDUserRecord{
|
|
FirstName: "Default Administrator",
|
|
Password: primaryPassword,
|
|
FSDPassword: fsdPassword,
|
|
NetworkRating: protocol.NetworkRatingADM,
|
|
PilotRating: protocol.PilotRatingFE,
|
|
}
|
|
|
|
var cid int
|
|
if cid, err = defaultUser.Insert(db); err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf(`
|
|
|
|
DEFAULT ADMINISTRATOR USER:
|
|
CID: %d
|
|
PRIMARY PASSWORD: %s
|
|
FSD PASSWORD: %s
|
|
|
|
`, cid, primaryPassword, fsdPassword)
|
|
|
|
var testRecord FSDUserRecord
|
|
if err = testRecord.LoadByCID(db, cid); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|