Compare commits

..

No commits in common. '3bdc35e197d669ca27e20680aaa788f551247172' and 'c069782f32d44af92beed25b3e09f4f7e2e17472' have entirely different histories.

@ -1,69 +0,0 @@
package main
import (
"context"
"database/sql"
_ "embed"
"log"
_ "modernc.org/sqlite"
models "code.ndumas.com/ndumas/muddy/db"
)
//go:embed schema.sql
var ddl string
func run() error {
return nil
}
func main() {
ctx := context.Background()
db, err := sql.Open("sqlite", ":memory:")
if err != nil {
log.Printf("error opening sqlite db: %s\n", err)
return
}
// create tables
if _, err := db.ExecContext(ctx, ddl); err != nil {
log.Printf("error creating tables: %s\n", err)
return
}
queries := models.New(db)
obsvID, err := queries.CreateObservable(
ctx,
models.CreateObservableParams{
Name: "The Crossroads",
Description: "You stand at the intersection of two well trod roads. You don't remember how you got here, where you were going, or who you were. All you know is that you must go forward.",
},
)
if err != nil {
log.Printf("error creating room observable: %s\n", err)
return
}
if err != nil {
log.Printf("error creating room observable: %s\n", err)
return
}
locID, err := queries.CreateLocation(
ctx,
models.CreateLocationParams{
X: 0,
Y: 0,
Z: 0,
World: 0,
Observable: obsvID,
},
)
log.Printf("created room: %d\n", locID)
}

@ -1,32 +0,0 @@
CREATE TABLE locations (
id INTEGER PRIMARY KEY,
x INTEGER NOT NULL,
y INTEGER NOT NULL,
z INTEGER NOT NULL,
world INTEGER NOT NULL,
observable INTEGER NOT NULL references observables(id)
);
CREATE TABLE observables (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
description TEXT NOT NULL
);
CREATE TABLE inventories (
id INTEGER PRIMARY KEY
);
CREATE TABLE pools (
id INTEGER PRIMARY KEY,
type INTEGER NOT NULL
);
CREATE TABLE exits (
id INTEGER PRIMARY KEY,
origin INTEGER NOT NULL,
dest INTEGER NOT NULL,
FOREIGN KEY (origin) REFERENCES locations (id),
FOREIGN KEY (dest) REFERENCES locations (id)
);

@ -1,57 +0,0 @@
package main
import (
"context"
"flag"
"io"
"log/slog"
"os"
"os/signal"
"syscall"
"time"
"code.ndumas.com/ndumas/muddy/core"
)
func main() {
var (
level string
logFile string
)
flag.StringVar(&level, "level", "INFO", "Log level: INFO/info, DEBUG/debug, or ERROR/error.")
flag.StringVar(&logFile, "log", "out.log", "Path to log file.")
flag.Parse()
f, err := os.Create(logFile)
if err != nil {
slog.With(
slog.Any("error", err),
).Error("could not open log file")
os.Exit(1)
}
appConfig := core.AppConfig{
Port: ":3001",
LogDest: io.MultiWriter(f, os.Stderr),
LogLevel: level,
TickInterval: time.Millisecond * 30,
}
app := core.New(appConfig)
ctx, cancel := context.WithCancel(context.Background())
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
app.L.Info("shutting down")
cancel()
}()
app.Run(ctx)
}

@ -1,37 +1,24 @@
package core package core
import ( import (
"bufio"
"context" "context"
"io" "io"
"log/slog" "log/slog"
"os"
"time" "time"
"github.com/EngoEngine/ecs" "github.com/EngoEngine/ecs"
) )
type Printer struct {
}
type AppConfig struct {
LogDest io.Writer
LogLevel string
Port string
TickInterval time.Duration
World *ecs.World
}
type App struct { type App struct {
Config AppConfig
W *ecs.World W *ecs.World
L *slog.Logger L *slog.Logger
} }
func New(ac AppConfig) *App { func New(level string, logFile io.Writer) *App {
var logLevel slog.Level var logLevel slog.Level
switch ac.LogLevel { switch level {
case "INFO", "info": case "INFO", "info":
logLevel = slog.LevelInfo logLevel = slog.LevelInfo
case "DEBUG", "debug": case "DEBUG", "debug":
@ -41,40 +28,43 @@ func New(ac AppConfig) *App {
} }
l := slog.New(slog.NewTextHandler( l := slog.New(slog.NewTextHandler(
ac.LogDest, &slog.HandlerOptions{ logFile, &slog.HandlerOptions{
Level: logLevel, Level: logLevel,
}, },
), ),
) )
world := &ecs.World{} world := &ecs.World{}
ac.World = world
return &App{ return &App{
L: l, L: l,
W: world, W: world,
Config: ac,
} }
} }
func (a *App) Run(ctx context.Context) { func (a *App) Run(ctx context.Context) {
go func() { go func() {
t := time.NewTicker(a.Config.TickInterval) t := time.NewTicker(time.Millisecond * 30)
for range t.C { for range t.C {
a.W.Update(1) a.W.Update(1)
} }
}() }()
s := NewServer(ctx, a.L, a.Config.Port, world) scanner := bufio.NewScanner(os.Stdin)
go s.Start() var line string
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
a.L.Error("cancelled")
return return
case session := <-s.Sessions: default:
go session.Start() if scanner.Scan() {
line = scanner.Text()
} }
a.L.Info("scanning input")
a.L.With(slog.String("input", line)).Info("received command")
} }
}
} }

@ -1,68 +0,0 @@
package core
import (
"context"
"log/slog"
"net"
"time"
"github.com/EngoEngine/ecs"
)
type Server struct {
l *slog.Logger
port string
ctx context.Context
Sessions chan *Session
ln net.Listener
w *ecs.World
}
func NewServer(ctx context.Context, l *slog.Logger, port string, w *ecs.World) *Server {
var s Server
c := make(chan *Session)
s.Sessions = c
lc := net.ListenConfig{
KeepAlive: 5 * time.Minute,
KeepAliveConfig: net.KeepAliveConfig{
Enable: true,
Idle: 3 * time.Minute,
Interval: 15 * time.Second,
},
}
ln, err := lc.Listen(ctx, "tcp", port)
if err != nil {
s.l.With(
slog.Any("error", err),
).Error("could not start tcp listener")
return &s
}
s.ctx = ctx
s.ln = ln
s.l = l
s.port = port
s.w = w
return &s
}
func (s *Server) Start() {
s.l.Debug("starting telnet server")
for {
select {
case <-s.ctx.Done():
return
default:
conn, err := s.ln.Accept()
if err != nil {
s.l.With(
slog.Any("error", err),
).Error("could not accept tcp connection")
}
s.Sessions <- NewSession(s.ctx, conn, Printer{}, s.l)
}
}
}

@ -1,75 +0,0 @@
package core
import (
"bufio"
"context"
"fmt"
"log/slog"
"net"
"github.com/EngoEngine/ecs"
"github.com/google/uuid"
)
type Session struct {
c net.Conn
ctx context.Context
p Printer
l *slog.Logger
w *ecs.World
sessionID uuid.UUID
userID uint64
}
func NewSession(ctx context.Context, c net.Conn, p Printer, l *slog.Logger, w *ecs.World) *Session {
sid := uuid.New()
return &Session{
ctx: ctx,
l: l.With(slog.String("sid", sid.String())),
c: c,
w: w,
p: p,
sessionID: sid,
}
}
func (s *Session) bufferInput(commands chan string) {
scanner := bufio.NewScanner(s.c)
defer close(commands)
for scanner.Scan() {
err := scanner.Err()
switch err {
case nil:
commands <- scanner.Text()
default:
s.l.With(slog.Any("error", scanner.Err())).Error("error scanning input")
return
}
}
s.l.Debug("session terminated")
}
func (s *Session) Start() {
s.l.Debug("starting telnet session")
fmt.Fprint(s.c, "Welcome to Bing Bong.\n")
commands := make(chan string)
go s.bufferInput(commands)
for command := range commands {
s.l.With(slog.String("command", command)).Debug("command recieved")
_, err := fmt.Fprintf(s.c, "> %q\n", command)
if err != nil {
s.l.With(
slog.Any("error", err),
).Error("connection closed on write")
return
}
}
}

@ -4,32 +4,35 @@
package db package db
import (
"database/sql"
)
type Exit struct { type Exit struct {
ID int64 `db:"id" json:"id"` ID int64
Origin int64 `db:"origin" json:"origin"` To sql.NullInt64
Dest int64 `db:"dest" json:"dest"` From sql.NullInt64
} }
type Inventory struct { type Inventory struct {
ID int64 `db:"id" json:"id"` ID int64
} }
type Location struct { type Location struct {
ID int64 `db:"id" json:"id"` ID int64
X int64 `db:"x" json:"x"` X int64
Y int64 `db:"y" json:"y"` Y int64
Z int64 `db:"z" json:"z"` Z int64
World int64 `db:"world" json:"world"` World int64
Observable int64 `db:"observable" json:"observable"`
} }
type Observable struct { type Observable struct {
ID int64 `db:"id" json:"id"` ID int64
Name string `db:"name" json:"name"` Name string
Description string `db:"description" json:"description"` Description string
} }
type Pool struct { type Pool struct {
ID int64 `db:"id" json:"id"` ID int64
Type int64 `db:"type" json:"type"` Type int64
} }

@ -1,56 +0,0 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
package db
import (
"context"
)
type Querier interface {
// Location
//
// insert INTO locations (x,y,z,world, observable) VALUES (?,?,?,?,?)
CreateLocation(ctx context.Context, arg CreateLocationParams) (int64, error)
// Observable
//
// insert INTO observables (name, description) VALUES (?,?)
CreateObservable(ctx context.Context, arg CreateObservableParams) (int64, error)
//DestroyLocation
//
// delete from locations where id = ?
DestroyLocation(ctx context.Context, id int64) error
// Exit
//
// select id, origin, dest from exits where id = ? LIMIT 1
GetExit(ctx context.Context, id int64) (Exit, error)
//GetLocation
//
// select id, x, y, z, world, observable from locations where id = ? LIMIT 1
GetLocation(ctx context.Context, id int64) (Location, error)
//GetLocationExitsFrom
//
// select id, origin, dest from exits where dest = ?
GetLocationExitsFrom(ctx context.Context, dest int64) ([]Exit, error)
//GetLocationExitsTo
//
// select id, origin, dest from exits where origin = ?
GetLocationExitsTo(ctx context.Context, origin int64) ([]Exit, error)
//GetObservable
//
// select id, name, description from observables where id = ? LIMIT 1
GetObservable(ctx context.Context, id int64) (Observable, error)
//UpdateLocation
//
// update locations SET
// x = ?,
// y = ?,
// z = ?,
// world = ?,
// observable = ?
// where id = ?
UpdateLocation(ctx context.Context, arg UpdateLocationParams) error
}
var _ Querier = (*Queries)(nil)

@ -7,90 +7,34 @@ package db
import ( import (
"context" "context"
"database/sql"
) )
const createLocation = `-- name: CreateLocation :execlastid const createLocation = `-- name: CreateLocation :exec
insert INTO locations (x,y,z,world, observable) VALUES (?,?,?,?,?) insert INTO LOCATIONS (x,y,z,world) VALUES (?,?,?,?)
` `
type CreateLocationParams struct { type CreateLocationParams struct {
X int64 `db:"x" json:"x"` X int64
Y int64 `db:"y" json:"y"` Y int64
Z int64 `db:"z" json:"z"` Z int64
World int64 `db:"world" json:"world"` World int64
Observable int64 `db:"observable" json:"observable"`
} }
// Location func (q *Queries) CreateLocation(ctx context.Context, arg CreateLocationParams) error {
// _, err := q.db.ExecContext(ctx, createLocation,
// insert INTO locations (x,y,z,world, observable) VALUES (?,?,?,?,?)
func (q *Queries) CreateLocation(ctx context.Context, arg CreateLocationParams) (int64, error) {
result, err := q.db.ExecContext(ctx, createLocation,
arg.X, arg.X,
arg.Y, arg.Y,
arg.Z, arg.Z,
arg.World, arg.World,
arg.Observable,
) )
if err != nil {
return 0, err
}
return result.LastInsertId()
}
const createObservable = `-- name: CreateObservable :execlastid
insert INTO observables (name, description) VALUES (?,?)
`
type CreateObservableParams struct {
Name string `db:"name" json:"name"`
Description string `db:"description" json:"description"`
}
// Observable
//
// insert INTO observables (name, description) VALUES (?,?)
func (q *Queries) CreateObservable(ctx context.Context, arg CreateObservableParams) (int64, error) {
result, err := q.db.ExecContext(ctx, createObservable, arg.Name, arg.Description)
if err != nil {
return 0, err
}
return result.LastInsertId()
}
const destroyLocation = `-- name: DestroyLocation :exec
delete from locations where id = ?
`
// DestroyLocation
//
// delete from locations where id = ?
func (q *Queries) DestroyLocation(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, destroyLocation, id)
return err return err
} }
const getExit = `-- name: GetExit :one
select id, origin, dest from exits where id = ? LIMIT 1
`
// Exit
//
// select id, origin, dest from exits where id = ? LIMIT 1
func (q *Queries) GetExit(ctx context.Context, id int64) (Exit, error) {
row := q.db.QueryRowContext(ctx, getExit, id)
var i Exit
err := row.Scan(&i.ID, &i.Origin, &i.Dest)
return i, err
}
const getLocation = `-- name: GetLocation :one const getLocation = `-- name: GetLocation :one
select id, x, y, z, world, observable from locations where id = ? LIMIT 1 select id, x, y, z, world from locations where id = ? LIMIT 1
` `
// GetLocation
//
// select id, x, y, z, world, observable from locations where id = ? LIMIT 1
func (q *Queries) GetLocation(ctx context.Context, id int64) (Location, error) { func (q *Queries) GetLocation(ctx context.Context, id int64) (Location, error) {
row := q.db.QueryRowContext(ctx, getLocation, id) row := q.db.QueryRowContext(ctx, getLocation, id)
var i Location var i Location
@ -100,20 +44,16 @@ func (q *Queries) GetLocation(ctx context.Context, id int64) (Location, error) {
&i.Y, &i.Y,
&i.Z, &i.Z,
&i.World, &i.World,
&i.Observable,
) )
return i, err return i, err
} }
const getLocationExitsFrom = `-- name: GetLocationExitsFrom :many const getLocationExitsFrom = `-- name: GetLocationExitsFrom :many
select id, origin, dest from exits where dest = ? select id, "to", "from" from exits where from = ? LIMIT 1
` `
// GetLocationExitsFrom func (q *Queries) GetLocationExitsFrom(ctx context.Context, from sql.NullInt64) ([]Exit, error) {
// rows, err := q.db.QueryContext(ctx, getLocationExitsFrom, from)
// select id, origin, dest from exits where dest = ?
func (q *Queries) GetLocationExitsFrom(ctx context.Context, dest int64) ([]Exit, error) {
rows, err := q.db.QueryContext(ctx, getLocationExitsFrom, dest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -121,7 +61,7 @@ func (q *Queries) GetLocationExitsFrom(ctx context.Context, dest int64) ([]Exit,
var items []Exit var items []Exit
for rows.Next() { for rows.Next() {
var i Exit var i Exit
if err := rows.Scan(&i.ID, &i.Origin, &i.Dest); err != nil { if err := rows.Scan(&i.ID, &i.To, &i.From); err != nil {
return nil, err return nil, err
} }
items = append(items, i) items = append(items, i)
@ -136,14 +76,11 @@ func (q *Queries) GetLocationExitsFrom(ctx context.Context, dest int64) ([]Exit,
} }
const getLocationExitsTo = `-- name: GetLocationExitsTo :many const getLocationExitsTo = `-- name: GetLocationExitsTo :many
select id, origin, dest from exits where origin = ? select id, "to", "from" from exits where to = ? LIMIT 1
` `
// GetLocationExitsTo func (q *Queries) GetLocationExitsTo(ctx context.Context, to sql.NullInt64) ([]Exit, error) {
// rows, err := q.db.QueryContext(ctx, getLocationExitsTo, to)
// select id, origin, dest from exits where origin = ?
func (q *Queries) GetLocationExitsTo(ctx context.Context, origin int64) ([]Exit, error) {
rows, err := q.db.QueryContext(ctx, getLocationExitsTo, origin)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -151,7 +88,7 @@ func (q *Queries) GetLocationExitsTo(ctx context.Context, origin int64) ([]Exit,
var items []Exit var items []Exit
for rows.Next() { for rows.Next() {
var i Exit var i Exit
if err := rows.Scan(&i.ID, &i.Origin, &i.Dest); err != nil { if err := rows.Scan(&i.ID, &i.To, &i.From); err != nil {
return nil, err return nil, err
} }
items = append(items, i) items = append(items, i)
@ -164,57 +101,3 @@ func (q *Queries) GetLocationExitsTo(ctx context.Context, origin int64) ([]Exit,
} }
return items, nil return items, nil
} }
const getObservable = `-- name: GetObservable :one
select id, name, description from observables where id = ? LIMIT 1
`
// GetObservable
//
// select id, name, description from observables where id = ? LIMIT 1
func (q *Queries) GetObservable(ctx context.Context, id int64) (Observable, error) {
row := q.db.QueryRowContext(ctx, getObservable, id)
var i Observable
err := row.Scan(&i.ID, &i.Name, &i.Description)
return i, err
}
const updateLocation = `-- name: UpdateLocation :exec
update locations SET
x = ?,
y = ?,
z = ?,
world = ?,
observable = ?
where id = ?
`
type UpdateLocationParams struct {
X int64 `db:"x" json:"x"`
Y int64 `db:"y" json:"y"`
Z int64 `db:"z" json:"z"`
World int64 `db:"world" json:"world"`
Observable int64 `db:"observable" json:"observable"`
ID int64 `db:"id" json:"id"`
}
// UpdateLocation
//
// update locations SET
// x = ?,
// y = ?,
// z = ?,
// world = ?,
// observable = ?
// where id = ?
func (q *Queries) UpdateLocation(ctx context.Context, arg UpdateLocationParams) error {
_, err := q.db.ExecContext(ctx, updateLocation,
arg.X,
arg.Y,
arg.Z,
arg.World,
arg.Observable,
arg.ID,
)
return err
}

@ -1,30 +1,11 @@
-- Location -- name: CreateLocation :exec
-- name: CreateLocation :execlastid insert INTO LOCATIONS (x,y,z,world) VALUES (?,?,?,?);
insert INTO locations (x,y,z,world, observable) VALUES (?,?,?,?,?);
-- name: GetLocation :one -- name: GetLocation :one
select * from locations where id = ? LIMIT 1; select * from locations where id = ? LIMIT 1;
-- name: UpdateLocation :exec
update locations SET
x = ?,
y = ?,
z = ?,
world = ?,
observable = ?
where id = ?;
-- name: DestroyLocation :exec
delete from locations where id = ?;
-- Exit
-- name: GetExit :one
select * from exits where id = ? LIMIT 1;
-- name: GetLocationExitsTo :many -- name: GetLocationExitsTo :many
select * from exits where origin = ?; select * from exits where to = ? LIMIT 1;
-- name: GetLocationExitsFrom :many
select * from exits where dest = ?;
-- Observable -- name: GetLocationExitsFrom :many
-- name: CreateObservable :execlastid select * from exits where from = ? LIMIT 1;
insert INTO observables (name, description) VALUES (?,?);
-- name: GetObservable :one
select * from observables where id = ? LIMIT 1;

@ -1,32 +1,28 @@
CREATE TABLE locations ( create TABLE locations (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
x INTEGER NOT NULL, x INTEGER NOT NULL,
y INTEGER NOT NULL, y INTEGER NOT NULL,
z INTEGER NOT NULL, z INTEGER NOT NULL,
world INTEGER NOT NULL, world INTEGER NOT NULL
observable INTEGER NOT NULL references observables(id) )
);
create TABLE exits (
id INTEGER PRIMARY KEY,
to INTEGER REFERENCES locations(id),
from INTEGER REFERENCES locations(id)
)
CREATE TABLE observables ( create TABLE observables (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
name TEXT NOT NULL, name TEXT NOT NULL,
description TEXT NOT NULL description TEXT NOT NULL
); )
CREATE TABLE inventories ( create TABLE inventories (
id INTEGER PRIMARY KEY id INTEGER PRIMARY KEY
); )
CREATE TABLE pools ( create TABLE pools (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
type INTEGER NOT NULL type INTEGER NOT NULL
); )
CREATE TABLE exits (
id INTEGER PRIMARY KEY,
origin INTEGER NOT NULL,
dest INTEGER NOT NULL,
FOREIGN KEY (origin) REFERENCES locations (id),
FOREIGN KEY (dest) REFERENCES locations (id)
);

@ -6,8 +6,5 @@ sql:
gen: gen:
go: go:
emit_db_tags: true emit_db_tags: true
emit_interface: true
emit_json_tags: true
emit_sql_as_comment: true
package: "db" package: "db"
out: "db" out: "db"

Loading…
Cancel
Save