diff --git a/go.mod b/go.mod index d99384b..b180b2d 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.14 require ( 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/mailru/easyjson v0.7.1 github.com/markbates/pkger v0.17.0 diff --git a/go.sum b/go.sum index c969f39..08f8890 100644 --- a/go.sum +++ b/go.sum @@ -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/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= 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/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= diff --git a/helpers.go b/helpers.go index 273740d..5b05be8 100644 --- a/helpers.go +++ b/helpers.go @@ -1,19 +1,5 @@ package main -import ( - "reflect" - - "github.com/gofrs/uuid" - "github.com/tomwright/queryparam/v4" -) - func stringPtr(s string) *string { 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 - } -} diff --git a/internal/game/room.go b/internal/game/room.go index 5f2a8ae..c099da5 100644 --- a/internal/game/room.go +++ b/internal/game/room.go @@ -1,12 +1,11 @@ package game import ( - "github.com/gofrs/uuid" "github.com/zikaeroh/codies/internal/words" "github.com/zikaeroh/codies/internal/words/static" ) -type PlayerID = uuid.UUID +type PlayerID = string type WordList struct { Name string diff --git a/internal/protocol/protocol_easyjson.go b/internal/protocol/protocol_easyjson.go index 364bb11..c100efe 100644 --- a/internal/protocol/protocol_easyjson.go +++ b/internal/protocol/protocol_easyjson.go @@ -537,9 +537,7 @@ func easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol6(in *jlexer.L } switch key { case "playerID": - if data := in.UnsafeBytes(); in.Ok() { - in.AddError((out.PlayerID).UnmarshalText(data)) - } + out.PlayerID = string(in.String()) case "nickname": out.Nickname = string(in.String()) case "spymaster": @@ -565,7 +563,7 @@ func easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol6(out *jwriter { const prefix string = ",\"playerID\":" out.RawString(prefix[1:]) - out.RawText((in.PlayerID).MarshalText()) + out.String(string(in.PlayerID)) } { const prefix string = ",\"nickname\":" @@ -623,9 +621,7 @@ func easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol7(in *jlexer.L } switch key { case "playerID": - if data := in.UnsafeBytes(); in.Ok() { - in.AddError((out.PlayerID).UnmarshalText(data)) - } + out.PlayerID = string(in.String()) case "roomState": if in.IsNull() { in.Skip() @@ -657,7 +653,7 @@ func easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol7(out *jwriter { const prefix string = ",\"playerID\":" out.RawString(prefix[1:]) - out.RawText((in.PlayerID).MarshalText()) + out.String(string(in.PlayerID)) } { const prefix string = ",\"roomState\":" diff --git a/internal/server/server.go b/internal/server/server.go index 06b407d..1bb8c95 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -4,13 +4,13 @@ import ( "context" "encoding/json" "errors" + "strconv" "sync" "time" - "github.com/gofrs/uuid" - "github.com/speps/go-hashids" "github.com/zikaeroh/codies/internal/game" "github.com/zikaeroh/codies/internal/protocol" + "github.com/zikaeroh/codies/internal/uid" "github.com/zikaeroh/ctxjoin" "github.com/zikaeroh/ctxlog" "go.uber.org/atomic" @@ -33,34 +33,30 @@ type Server struct { doPrune chan struct{} ready chan struct{} - mu sync.Mutex + genRoomID *uid.Generator - ctx context.Context + ctx context.Context + + mu sync.Mutex rooms map[string]*Room roomIDs map[string]*Room - - hid *hashids.HashID - nextID int64 } 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{ - ready: make(chan struct{}), - doPrune: make(chan struct{}, 1), - rooms: make(map[string]*Room), - roomIDs: make(map[string]*Room), - hid: hid, + ready: make(chan struct{}), + 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), + roomIDs: make(map[string]*Room), } } +func salt() string { + x := time.Now().Unix() + return strconv.FormatInt(x, 10) +} + func (s *Server) Run(ctx context.Context) error { s.ctx = ctx @@ -113,11 +109,7 @@ func (s *Server) CreateRoom(ctx context.Context, name, password string) (*Room, return nil, ErrTooManyRooms } - id, err := s.hid.EncodeInt64([]int64{s.nextID}) - if err != nil { - return nil, err - } - s.nextID++ + id, idRaw := s.genRoomID.Next() roomCtx, roomCancel := context.WithCancel(s.ctx) @@ -127,6 +119,7 @@ func (s *Server) CreateRoom(ctx context.Context, name, password string) (*Room, ID: id, clientCount: &s.clientCount, roomCount: &s.roomCount, + genPlayerID: uid.NewGenerator(id), ctx: roomCtx, cancel: roomCancel, room: game.NewRoom(nil), @@ -143,9 +136,9 @@ func (s *Server) CreateRoom(ctx context.Context, name, password string) (*Room, s.roomCount.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() } @@ -207,6 +200,7 @@ type Room struct { cancel context.CancelFunc clientCount *atomic.Int64 roomCount *atomic.Int64 + genPlayerID *uid.Generator mu sync.Mutex room *game.Room @@ -225,12 +219,12 @@ type Room struct { type noteSender func(protocol.ServerNote) 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) 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() defer metricClients.Dec() diff --git a/internal/uid/uid.go b/internal/uid/uid.go new file mode 100644 index 0000000..15d4a50 --- /dev/null +++ b/internal/uid/uid.go @@ -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 +}