all repos — felt @ e59f3e1609f9715c90291be2e950b6f8ce393461

virtual tabletop for dungeons and dragons (and similar) using Go, MongoDB, and websockets

gofmt, rid code of typescript confusion, little bit of db code
Iris Lightshard nilix@nilfm.cc
PGP Signature
-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEEkFh6dA+k/6CXFXU4O3+8IhROY5gFAmNt5OUACgkQO3+8IhRO
Y5ir3A/8DLGMsDUo/jKOFr2tyx33YDzNpbGd5453yimnQ7+LweWlJ1SqTzAGYv0d
fuphLPIJCZfmSfelCD4oGmAeQbfpqfoJ85WIGB/qc/DweX5aJqTw4wMD3K481j1t
FoMvppoN3HZ8m0knQhYd6kHfxDoPeUG9yjxn4cxlaZOY003tL7Yew5/zcLtO3lim
SCDLCD3pcDoOBJwZ3vtuwbgCwy7MLrKWxgOWgM9+OhVlY+p+ZWfzQvqWHWj4Tico
yzq0Ga6p33TYAoSsG1u+xrZSSv7gtcnXG/a/axVZB0fmqxydxW+dGxaOqOciKx9z
TrbFRZeIq5/Sx/2/BG94usr2vjFnTUgoKkXt3mX9B2zU1Wpaxxtlzhqzb1j46zdZ
GRiGHlTlC1wD1fXTXsMSFVbiF8okt4aG48OjsCoKEO7lzbzCeuhgKQCvMfTEJ6CA
J+QFVZM6ouC9rzIH4DA3wiuZsoXaCWQUwVQZnjL4KRJIXMg/d8J9Qnjo8jzVsBaI
szoqZlWc64Ps/pZWecsOTiLOqMZkJNR99bf11/1/2om3PJfrn4wSLFxVj/ukJSst
xHL6sIL0Dxd6O3eSuFxR9NObBIJG8aT2AZDh38A/DnJu15/qXtWoVBS5bChxiXE2
oCd6fKk8FICQR2TSW1c+6iSMbXb7gegEWFLOFNRqpvjb25MMs0U=
=9QvW
-----END PGP SIGNATURE-----
commit

e59f3e1609f9715c90291be2e950b6f8ce393461

parent

25e51fb2d5626544e3bcd3c339f3899ae854c29c

4 files changed, 140 insertions(+), 121 deletions(-)

jump to
M gametable/server.gogametable/server.go

@@ -1,47 +1,47 @@

package gametable import ( - "context" - "nhooyr.io/websocket" - "golang.org/x/time/rate" - "io/ioutil" - "time" - "sync" - "net/http" - "log" - "errors" + "context" + "errors" + "golang.org/x/time/rate" + "io/ioutil" + "log" + "net/http" + "nhooyr.io/websocket" + "sync" + "time" ) type Subscriber struct { - msgs chan []byte - closeSlow func() + msgs chan []byte + closeSlow func() } type GameTableServer struct { - subscribeMessageBuffer int - publishLimiter *rate.Limiter - logf func(f string, v ...interface{}) - serveMux http.ServeMux - subscribersLock sync.Mutex - subscribers map[*Subscriber]struct{} + subscribeMessageBuffer int + publishLimiter *rate.Limiter + logf func(f string, v ...interface{}) + serveMux http.ServeMux + subscribersLock sync.Mutex + subscribers map[*Subscriber]struct{} } func New() *GameTableServer { - srvr := &GameTableServer { - subscribeMessageBuffer: 16, - logf: log.Printf, - subscribers: make(map[*Subscriber]struct{}), - publishLimiter: rate.NewLimiter(rate.Every(time.Millisecond*100), 8), - } - srvr.serveMux.Handle("/", http.FileServer(http.Dir("./static"))) - srvr.serveMux.HandleFunc("/subscribe", srvr.subscribeHandler) - srvr.serveMux.HandleFunc("/publish", srvr.publishHandler) - - return srvr + srvr := &GameTableServer{ + subscribeMessageBuffer: 16, + logf: log.Printf, + subscribers: make(map[*Subscriber]struct{}), + publishLimiter: rate.NewLimiter(rate.Every(time.Millisecond*100), 8), + } + srvr.serveMux.Handle("/", http.FileServer(http.Dir("./static"))) + srvr.serveMux.HandleFunc("/subscribe", srvr.subscribeHandler) + srvr.serveMux.HandleFunc("/publish", srvr.publishHandler) + + return srvr } func (self *GameTableServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { - self.serveMux.ServeHTTP(w, r) + self.serveMux.ServeHTTP(w, r) } func (self *GameTableServer) subscribeHandler(w http.ResponseWriter, r *http.Request) {

@@ -112,7 +112,7 @@ func (self *GameTableServer) publish(msg []byte) {

self.subscribersLock.Lock() defer self.subscribersLock.Unlock() - // decode message and store in DB + // decode message and store in DB self.publishLimiter.Wait(context.Background())

@@ -142,4 +142,4 @@ ctx, cancel := context.WithTimeout(ctx, timeout)

defer cancel() return c.Write(ctx, websocket.MessageText, msg) -}+}
M main.gomain.go

@@ -1,14 +1,14 @@

package main import ( - "context" - "nilfm.cc/git/felt/gametable" - "net" - "net/http" - "os" - "os/signal" - "time" - "log" + "context" + "log" + "net" + "net/http" + "nilfm.cc/git/felt/gametable" + "os" + "os/signal" + "time" ) func main() {

@@ -23,14 +23,14 @@ l, err := net.Listen("tcp", os.Args[1])

if err != nil { return err } - + gt := gametable.New() s := &http.Server{ - Handler: gt, - ReadTimeout: time.Second * 10, - WriteTimeout: time.Second * 10, + Handler: gt, + ReadTimeout: time.Second * 10, + WriteTimeout: time.Second * 10, } - + errc := make(chan error, 1) go func() { errc <- s.Serve(l)

@@ -49,4 +49,4 @@ ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)

defer cancel() return s.Shutdown(ctx) -}+}
M models/models.gomodels/models.go

@@ -1,25 +1,25 @@

package models import ( - "time" + "time" ) type TableKey struct { - name: string - passcode: string + Name string + Passcode string } type DiceRoll struct { - faces: uint8 - roll: uint8[] - player: string - note: string - timestamp: time.Time + Faces uint8 + Roll []uint8 + Player string + Note string + Timestamp time.Time } type Token struct { - id: string - spriteUri: string - x: int - y: int -}+ Id string + SpriteUri string + X int + Y int +}
M mongodb/adapter.gomongodb/adapter.go

@@ -1,76 +1,95 @@

package dbengine import ( - "context" - "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - "nilfm.cc/git/felt/models" + "context" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "nilfm.cc/git/felt/models" + "time" ) -interface DbAdapter { - Init(mongoUri: string): error - - CreateTable(table: models.TableKey): error - DestroyTable(table: models.TableKey): error - - InsertDiceRoll(table: models.TableKey, diceRoll: models.DiceRoll): error - GetDiceRolls(table: models.TableKey): models.DiceRoll[], error - - SetMapImageUrl(table: models.TableKey, url: string): error - GetMapImageUrl(table: models.TableKey): string, error - - AddToken(table: models.TableKey, token: models.Token): error - RemoveToken(table: models.TableKey, tokenId: string): error - ModifyToken(table: models.TableKey, token: models.Token): error - GetTokens(table: models.TableKey): models.Token[], error +type DbAdapter interface { + Init(mongoUri string) error + + CreateTable(table models.TableKey) error + DestroyTable(table models.TableKey) error + + InsertDiceRoll(table models.TableKey, diceRoll models.DiceRoll) error + GetDiceRolls(table models.TableKey) ([]models.DiceRoll, error) + + SetMapImageUrl(table models.TableKey, url string) error + GetMapImageUrl(table models.TableKey) (string, error) + + AddToken(table models.TableKey, token models.Token) error + RemoveToken(table models.TableKey, tokenId string) error + ModifyToken(table models.TableKey, token models.Token) error + GetTokens(table models.TableKey) ([]models.Token, error) } type DbEngine struct { - client: mongo.Client + client mongo.Client } -func (self *DbEngine) Init(mongoUri: string) error { - client, err := mongo.NewClient(options.Client().ApplyURI(mongoUri)) - if err != nil { - return err - } - self.client = client - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - - err = client.Connect(ctx) - if err != nil { - return err - } - defer client.Disconnect(ctx) - - db := client.Database("felt") - - err = self.ensureCollections(db) - return err +func (self *DbEngine) mkCtx(timeoutSec int) context.Context { + return context.WithTimeout(context.Background(), 10*time.Second) +} + +func (self *DbEngine) Init(mongoUri string) error { + client, err := mongo.NewClient(options.Client().ApplyURI(mongoUri)) + if err != nil { + return err + } + self.client = client + ctx, _ := self.mkCtx(10) + + err = client.Connect(ctx) + if err != nil { + return err + } + defer client.Disconnect(ctx) + + db := client.Database("felt") + + err = self.ensureCollections(db) + return err +} + +func (self *DbEngine) ensureCollections(db mongo.Database) error { + tables := db.Collection("tables") + if tables == nil { + createCmd := bson.D{ + {"create", "tables"}, + {"clusteredIndex", { + {"key", {"name"}}, + {"unique", true}, + {"name", "idx_tables_unique_names"}, + }}, + } + + var createResult bson.M + err := db.RunCommand( + self.mkCtx(10), + createCmd).Decode(&createResult) + + if err != nil { + return err + } + } + return nil } -func (self *DbEngine) ensureCollections(db: mongo.Database) error { - tables := db.Collection("tables") - if tables == nil { - createCmd := bson.D{ - {"create", "tables"}, - {"clusteredIndex", { - {"key", {"name"}}, - {"unique", true}, - {"name", "idx_tables_unique_names"} - }} - } - - var createResult bson.M - err := db.RunCommand( - context.WithTimeout(context.Background(), 10*time.Second), - createCmd).Decode(&createResult) - - if err != nil { - return err - } - } - return nil +func (self *DbEngine) CreateTable(table models.TableKey) error { + tables := self.db.Collection("tables") + if tables != nil { + _, err := tables.insertOne(self.mkCtx(10), bson.D{ + {"name", table.Name}, + {"passcode", table.Passcode}, + {"mapUri", ""}, + {"diceRolls", bson.A{}}, + {"tokens", bson.A{}}, + }) + } + + return err }