Use hashids for player IDs, drop UUID uses

This commit is contained in:
zikaeroh 2020-06-14 14:01:17 -07:00
parent 3e091eb71b
commit e69ffba5ae
7 changed files with 68 additions and 56 deletions

1
go.mod
View File

@ -4,7 +4,6 @@ go 1.14
require ( require (
github.com/go-chi/chi v4.1.2+incompatible github.com/go-chi/chi v4.1.2+incompatible
github.com/gofrs/uuid v3.3.0+incompatible
github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4 github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4
github.com/mailru/easyjson v0.7.1 github.com/mailru/easyjson v0.7.1
github.com/markbates/pkger v0.17.0 github.com/markbates/pkger v0.17.0

2
go.sum
View File

@ -41,8 +41,6 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=

View File

@ -1,19 +1,5 @@
package main package main
import (
"reflect"
"github.com/gofrs/uuid"
"github.com/tomwright/queryparam/v4"
)
func stringPtr(s string) *string { func stringPtr(s string) *string {
return &s return &s
} }
func init() {
queryparam.DefaultParser.ValueParsers[reflect.TypeOf(uuid.UUID{})] = func(value string, _ string) (reflect.Value, error) {
id, err := uuid.FromString(value)
return reflect.ValueOf(id), err
}
}

View File

@ -1,12 +1,11 @@
package game package game
import ( import (
"github.com/gofrs/uuid"
"github.com/zikaeroh/codies/internal/words" "github.com/zikaeroh/codies/internal/words"
"github.com/zikaeroh/codies/internal/words/static" "github.com/zikaeroh/codies/internal/words/static"
) )
type PlayerID = uuid.UUID type PlayerID = string
type WordList struct { type WordList struct {
Name string Name string

View File

@ -537,9 +537,7 @@ func easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol6(in *jlexer.L
} }
switch key { switch key {
case "playerID": case "playerID":
if data := in.UnsafeBytes(); in.Ok() { out.PlayerID = string(in.String())
in.AddError((out.PlayerID).UnmarshalText(data))
}
case "nickname": case "nickname":
out.Nickname = string(in.String()) out.Nickname = string(in.String())
case "spymaster": case "spymaster":
@ -565,7 +563,7 @@ func easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol6(out *jwriter
{ {
const prefix string = ",\"playerID\":" const prefix string = ",\"playerID\":"
out.RawString(prefix[1:]) out.RawString(prefix[1:])
out.RawText((in.PlayerID).MarshalText()) out.String(string(in.PlayerID))
} }
{ {
const prefix string = ",\"nickname\":" const prefix string = ",\"nickname\":"
@ -623,9 +621,7 @@ func easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol7(in *jlexer.L
} }
switch key { switch key {
case "playerID": case "playerID":
if data := in.UnsafeBytes(); in.Ok() { out.PlayerID = string(in.String())
in.AddError((out.PlayerID).UnmarshalText(data))
}
case "roomState": case "roomState":
if in.IsNull() { if in.IsNull() {
in.Skip() in.Skip()
@ -657,7 +653,7 @@ func easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol7(out *jwriter
{ {
const prefix string = ",\"playerID\":" const prefix string = ",\"playerID\":"
out.RawString(prefix[1:]) out.RawString(prefix[1:])
out.RawText((in.PlayerID).MarshalText()) out.String(string(in.PlayerID))
} }
{ {
const prefix string = ",\"roomState\":" const prefix string = ",\"roomState\":"

View File

@ -4,13 +4,13 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"strconv"
"sync" "sync"
"time" "time"
"github.com/gofrs/uuid"
"github.com/speps/go-hashids"
"github.com/zikaeroh/codies/internal/game" "github.com/zikaeroh/codies/internal/game"
"github.com/zikaeroh/codies/internal/protocol" "github.com/zikaeroh/codies/internal/protocol"
"github.com/zikaeroh/codies/internal/uid"
"github.com/zikaeroh/ctxjoin" "github.com/zikaeroh/ctxjoin"
"github.com/zikaeroh/ctxlog" "github.com/zikaeroh/ctxlog"
"go.uber.org/atomic" "go.uber.org/atomic"
@ -33,34 +33,30 @@ type Server struct {
doPrune chan struct{} doPrune chan struct{}
ready chan struct{} ready chan struct{}
mu sync.Mutex genRoomID *uid.Generator
ctx context.Context ctx context.Context
mu sync.Mutex
rooms map[string]*Room rooms map[string]*Room
roomIDs map[string]*Room roomIDs map[string]*Room
hid *hashids.HashID
nextID int64
} }
func NewServer() *Server { func NewServer() *Server {
hd := hashids.NewData()
hd.MinLength = 8
hd.Salt = uuid.Must(uuid.NewV4()).String() // IDs are only valid for this server instance; ok to randomize salt.
hid, err := hashids.NewWithData(hd)
if err != nil {
panic(err)
}
return &Server{ return &Server{
ready: make(chan struct{}), ready: make(chan struct{}),
doPrune: make(chan struct{}, 1), doPrune: make(chan struct{}, 1),
genRoomID: uid.NewGenerator(salt()), // IDs are only valid for this server instance; ok to randomize salt.
rooms: make(map[string]*Room), rooms: make(map[string]*Room),
roomIDs: make(map[string]*Room), roomIDs: make(map[string]*Room),
hid: hid,
} }
} }
func salt() string {
x := time.Now().Unix()
return strconv.FormatInt(x, 10)
}
func (s *Server) Run(ctx context.Context) error { func (s *Server) Run(ctx context.Context) error {
s.ctx = ctx s.ctx = ctx
@ -113,11 +109,7 @@ func (s *Server) CreateRoom(ctx context.Context, name, password string) (*Room,
return nil, ErrTooManyRooms return nil, ErrTooManyRooms
} }
id, err := s.hid.EncodeInt64([]int64{s.nextID}) id, idRaw := s.genRoomID.Next()
if err != nil {
return nil, err
}
s.nextID++
roomCtx, roomCancel := context.WithCancel(s.ctx) roomCtx, roomCancel := context.WithCancel(s.ctx)
@ -127,6 +119,7 @@ func (s *Server) CreateRoom(ctx context.Context, name, password string) (*Room,
ID: id, ID: id,
clientCount: &s.clientCount, clientCount: &s.clientCount,
roomCount: &s.roomCount, roomCount: &s.roomCount,
genPlayerID: uid.NewGenerator(id),
ctx: roomCtx, ctx: roomCtx,
cancel: roomCancel, cancel: roomCancel,
room: game.NewRoom(nil), room: game.NewRoom(nil),
@ -143,9 +136,9 @@ func (s *Server) CreateRoom(ctx context.Context, name, password string) (*Room,
s.roomCount.Inc() s.roomCount.Inc()
metricRooms.Inc() metricRooms.Inc()
ctxlog.Info(ctx, "created new room", zap.String("name", name), zap.String("id", room.ID)) ctxlog.Info(ctx, "created new room", zap.String("roomName", name), zap.String("roomID", room.ID))
if s.nextID%100 == 0 { if idRaw%100 == 0 {
s.triggerPrune() s.triggerPrune()
} }
@ -207,6 +200,7 @@ type Room struct {
cancel context.CancelFunc cancel context.CancelFunc
clientCount *atomic.Int64 clientCount *atomic.Int64
roomCount *atomic.Int64 roomCount *atomic.Int64
genPlayerID *uid.Generator
mu sync.Mutex mu sync.Mutex
room *game.Room room *game.Room
@ -225,12 +219,12 @@ type Room struct {
type noteSender func(protocol.ServerNote) type noteSender func(protocol.ServerNote)
func (r *Room) HandleConn(ctx context.Context, nickname string, c *websocket.Conn) { func (r *Room) HandleConn(ctx context.Context, nickname string, c *websocket.Conn) {
playerID := uuid.Must(uuid.NewV4()) playerID, _ := r.genPlayerID.Next()
ctx, cancel := ctxjoin.AddCancel(ctx, r.ctx) ctx, cancel := ctxjoin.AddCancel(ctx, r.ctx)
defer cancel() defer cancel()
ctx = ctxlog.With(ctx, zap.String("roomName", r.Name), zap.String("roomID", r.ID), zap.String("nickname", nickname)) ctx = ctxlog.With(ctx, zap.String("roomName", r.Name), zap.String("roomID", r.ID), zap.String("playerID", playerID), zap.String("nickname", nickname))
metricClients.Inc() metricClients.Inc()
defer metricClients.Dec() defer metricClients.Dec()

40
internal/uid/uid.go Normal file
View File

@ -0,0 +1,40 @@
// Package uid generates unique IDs.
package uid
import (
"github.com/speps/go-hashids"
"go.uber.org/atomic"
)
// Generator generates unique incrementing IDs. These IDs are only comparable
// with other IDs from this generator.
type Generator struct {
hid *hashids.HashID
next atomic.Int64
}
// NewGenerator creates a new Generator with the specified salt. Generators
// with the same salt generate the same IDs in order.
func NewGenerator(salt string) *Generator {
hd := hashids.NewData()
hd.MinLength = 8
hd.Salt = salt
hid, err := hashids.NewWithData(hd)
if err != nil {
panic(err)
}
return &Generator{
hid: hid,
}
}
// Next gets the next ID, in both an encoded string form and the raw integer form.
func (g *Generator) Next() (string, int64) {
v := g.next.Inc()
id, err := g.hid.EncodeInt64([]int64{v})
if err != nil {
panic(err)
}
return id, v
}