first commit
This commit is contained in:
223
dataBase.go
Normal file
223
dataBase.go
Normal file
@ -0,0 +1,223 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
type dbLayer struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func connectToDataBase(host string, port uint32, user string, password string, dbName string) (*dbLayer, error) {
|
||||
db, err := sql.Open("postgres",
|
||||
fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
|
||||
host, port, user, password, dbName,
|
||||
),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to connect to database")
|
||||
}
|
||||
|
||||
return &dbLayer{
|
||||
db: db,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (db *dbLayer) execInTransaction(ctx context.Context, query string, args ...interface{}) error {
|
||||
tx, err := db.db.BeginTx(ctx, &sql.TxOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to begin transaction")
|
||||
}
|
||||
|
||||
getLogger(ctx).Debugf("[Run sql query]: %s, [%v]", query, args)
|
||||
|
||||
_, err = tx.ExecContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
|
||||
return errors.Wrapf(err, "Failed to run db query [%s] [%v]", query, args)
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to commit transaction")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
id string
|
||||
name string
|
||||
lastOnline time.Time
|
||||
onlineDuration time.Duration
|
||||
deaths int
|
||||
level int
|
||||
}
|
||||
|
||||
func fetchPlayer(r *sql.Rows, p *Player) error {
|
||||
var (
|
||||
err error
|
||||
lastOnline string
|
||||
onlineDuration int
|
||||
)
|
||||
|
||||
err = r.Scan(&p.id, &p.name, &lastOnline, &onlineDuration, &p.deaths, &p.level)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to fetch data base")
|
||||
}
|
||||
|
||||
p.lastOnline, err = time.Parse(time.RFC3339, lastOnline)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to parse date [%s]", lastOnline)
|
||||
}
|
||||
|
||||
p.onlineDuration = time.Second * time.Duration(onlineDuration)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *dbLayer) getPlayers(ctx context.Context) ([]Player, error) {
|
||||
var players []Player
|
||||
|
||||
query := "SELECT id, name, last_login, online_duration, deaths, level FROM players"
|
||||
|
||||
rows, err := db.db.QueryContext(ctx, query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to run db query [%s]", query)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
p := Player{}
|
||||
|
||||
err = fetchPlayer(rows, &p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
players = append(players, p)
|
||||
}
|
||||
|
||||
return players, nil
|
||||
}
|
||||
|
||||
func (db *dbLayer) getPlayerByID(ctx context.Context, id string) (*Player, error) {
|
||||
query := "SELECT id, name, last_login, online_duration, deaths, level FROM players WHERE id = $1"
|
||||
|
||||
rows, err := db.db.QueryContext(ctx, query, id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to run db query [%s]", query)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
var p Player
|
||||
|
||||
err = fetchPlayer(rows, &p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (db *dbLayer) getPlayerByName(ctx context.Context, name string) (*Player, error) {
|
||||
query := "SELECT id, name, last_login, online_duration, deaths, level FROM players WHERE name = $1 LIMIT 1"
|
||||
|
||||
rows, err := db.db.QueryContext(ctx, query, name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to run db query [%s]", query)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
var p Player
|
||||
|
||||
err = fetchPlayer(rows, &p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (db *dbLayer) createPlayer(ctx context.Context, name string, lastOnline time.Time) (*Player, error) {
|
||||
id := uuid()
|
||||
|
||||
err := db.execInTransaction(ctx, "INSERT INTO players (id, name, last_login) VALUES ($1, $2, $3)", id, name, lastOnline.Format(time.RFC3339))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Player{
|
||||
id: id,
|
||||
name: name,
|
||||
lastOnline: lastOnline,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (db *dbLayer) increasePlayerOnlineDuration(ctx context.Context, playerID string, d time.Duration) error {
|
||||
onlineDurationSecond := int(d / time.Second)
|
||||
if onlineDurationSecond == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return db.execInTransaction(ctx, "UPDATE players SET online_duration = online_duration + $2 WHERE id = $1", playerID, onlineDurationSecond)
|
||||
}
|
||||
|
||||
func (db *dbLayer) updatePlayerLastOnline(ctx context.Context, playerID string, lastOnline time.Time) error {
|
||||
return db.execInTransaction(ctx, "UPDATE players SET last_login = $2 WHERE id = $1", playerID, lastOnline.Format(time.RFC3339))
|
||||
}
|
||||
|
||||
func (db *dbLayer) increasePlayerDeath(ctx context.Context, playerID string, deaths int) error {
|
||||
return db.execInTransaction(ctx, "UPDATE players SET deaths = deaths + $2 WHERE id = $1", playerID, deaths)
|
||||
}
|
||||
|
||||
func (db *dbLayer) increasePlayerEntryKills(ctx context.Context, playerID string, entity string, count int) error {
|
||||
return db.execInTransaction(ctx,
|
||||
"INSERT INTO killings (player_id, entity, count) VALUES ($1, $2, $3) ON CONFLICT (player_id, entity) DO UPDATE SET count = killings.count + excluded.count",
|
||||
playerID, entity, count,
|
||||
)
|
||||
}
|
||||
|
||||
func (db *dbLayer) updatePlayerLevel(ctx context.Context, playerID string, level int) error {
|
||||
return db.execInTransaction(ctx, "UPDATE players SET level = $2 WHERE id = $1", playerID, level)
|
||||
}
|
||||
|
||||
func uuid() string {
|
||||
token := make([]byte, 18)
|
||||
rand.Read(token)
|
||||
result := make([]byte, 36)
|
||||
hex.Encode(result, token)
|
||||
|
||||
result[8] = 45
|
||||
result[13] = 45
|
||||
result[18] = 45
|
||||
result[23] = 45
|
||||
|
||||
return string(result)
|
||||
}
|
Reference in New Issue
Block a user