diff --git a/.gitignore b/.gitignore index bf98a88..b705790 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,4 @@ go.work go.work.sum data -.idea -env \ No newline at end of file +.idea \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index fe37db2..892385f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,8 @@ WORKDIR $GOPATH/src ADD . . ENV GO111MODULE=on +RUN go mod vendor + RUN go build -o /bin/app ./cmd/multiplayer FROM ubuntu:24.04 diff --git a/README.md b/README.md index e87395d..de86654 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ var ( RunMultiplayer = true // Enable multiplayer mode RunAdminPanel = true // Enable admin panel MultiplayerPort = "8080" // Port for multiplayer mode - MongoURL = "mongodb://username:userpassword@ascenmmo.com:27017/?maxPoolSize=20&w=majority" // MongoDB connection URL + MongoURL = "mongodb://username:userpassword@ascenmmo.com:27017" // MongoDB connection URL MultiplayerMaxRequestPerSecond = 5 // Maximum requests per second for multiplayer mode ) diff --git a/RU_README.md b/RU_README.md index 25d1a73..ff328c8 100644 --- a/RU_README.md +++ b/RU_README.md @@ -39,7 +39,7 @@ var ( RunMultiplayer = true // Запуск многопользовательского режима RunAdminPanel = true // Запуск админки MultiplayerPort = "8080" // Порт для многопользовательского режима - MongoURL = "mongodb://username:userpassword@ascenmmo.com:27017/?maxPoolSize=20&w=majority" // URL подключения к MongoDB + MongoURL = "mongodb://username:userpassword@ascenmmo.com:27017" // URL подключения к MongoDB MultiplayerMaxRequestPerSecond = 5 // Максимальное количество запросов в секунду для многопользовательского режима ) diff --git a/cmd/multiplayer/main.go b/cmd/multiplayer/main.go index 9c74e7c..4ddd098 100644 --- a/cmd/multiplayer/main.go +++ b/cmd/multiplayer/main.go @@ -5,17 +5,26 @@ import ( "github.com/ascenmmo/multiplayer-game-servers/env" "github.com/ascenmmo/multiplayer-game-servers/internal/start" "github.com/rs/zerolog" + "log" + "net/http" + _ "net/http/pprof" "os" "os/signal" "syscall" ) func main() { - logger := zerolog.New(os.Stdout).With().Timestamp().Logger() + logger := zerolog.Logger{} + ctx := context.Background() shutdown := make(chan os.Signal, 1) signal.Notify(shutdown, syscall.SIGINT) + //go exiter() + + if env.DebugLogs { + logger = zerolog.New(os.Stdout).With().Timestamp().Logger() + } if env.RunMultiplayer { go start.Multiplayer(logger) @@ -33,5 +42,19 @@ func main() { go start.TcpServer(ctx, logger) } + prof() + <-shutdown } + +func prof() { + go func() { + log.Println(http.ListenAndServe(":6060", nil)) + }() +} + +//func exiter() { +// for range time.NewTicker(time.Minute * 5).C { +// os.Exit(0) +// } +//} diff --git a/docker-compose.yml b/docker-compose.yml index 4be3ebe..80baf6c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,6 +14,7 @@ services: - "8083:8083" # TCP Server - "4500:4500/udp" # UDP Connection Port - "4240:4240" # WebSocket Connection Port + - "6060:6060" # WebSocket Connection Port mongodb: image: mongo:8.0 diff --git a/env/env.go b/env/env.go index 36af062..e595fd4 100644 --- a/env/env.go +++ b/env/env.go @@ -3,14 +3,15 @@ package env var ( ServerAddress = "ascenmmo.com" TokenKey = "_remember_token_mast_be_32_bytes" + DebugLogs = true ) var ( RunMultiplayer = true RunAdminPanel = true MultiplayerPort = "8080" - MongoURL = "mongodb://username:userpassword@ascenmmo.com:27017/?maxPoolSize=20&w=majority" - MultiplayerMaxRequestPerSecond = 5 + MongoURL = "mongodb://username:userpassword@ascenmmo.com:27017" + MultiplayerMaxRequestPerSecond = 100 ) var ( diff --git a/go.mod b/go.mod index 8715697..576c032 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module github.com/ascenmmo/multiplayer-game-servers go 1.23.2 require ( - github.com/ascenmmo/tcp-server v0.0.0-20241024213218-104f0955af07 - github.com/ascenmmo/token-generator v1.0.0 - github.com/ascenmmo/udp-server v0.0.0-20241024213152-f807e90ce36c - github.com/ascenmmo/websocket-server v0.0.0-20241024213056-3c1271cc0529 + github.com/ascenmmo/tcp-server v1.0.2 + github.com/ascenmmo/token-generator v1.0.2 + github.com/ascenmmo/udp-server v1.0.2 + github.com/ascenmmo/websocket-server v1.0.3 github.com/go-kit/kit v0.13.0 github.com/gofiber/adaptor/v2 v2.2.1 github.com/gofiber/fiber/v2 v2.52.5 @@ -37,10 +37,12 @@ require ( github.com/montanaflynn/stats v0.7.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect + github.com/philhofer/fwd v1.1.2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/tinylib/msgp v1.1.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect diff --git a/go.sum b/go.sum index 580f874..e673394 100644 --- a/go.sum +++ b/go.sum @@ -4,14 +4,14 @@ github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrd github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/ascenmmo/tcp-server v0.0.0-20241024213218-104f0955af07 h1:sAVYrtUU+Q0OECrtxmp+AouR9n7tAchjBmH7gG6md2E= -github.com/ascenmmo/tcp-server v0.0.0-20241024213218-104f0955af07/go.mod h1:14K6fwh/Sj958MMSPA+35xHzng0ZzVc2oq5kpXYLQbo= -github.com/ascenmmo/token-generator v1.0.0 h1:+yUCIXfeO68tuWvYyStT4dnnYWfujfP4vPXqOrEf7No= -github.com/ascenmmo/token-generator v1.0.0/go.mod h1:M3RdQKl1JfQeqM2hWNs0645G48GupB7idwdzQMkxlxM= -github.com/ascenmmo/udp-server v0.0.0-20241024213152-f807e90ce36c h1:6XLXv+VJ1pI5SbQhLlB2ynVcJ6y2UN1lQKh5tBb99V4= -github.com/ascenmmo/udp-server v0.0.0-20241024213152-f807e90ce36c/go.mod h1:uJBaE4CgtsgKsu7DFiW9+RYy+BXjjG3+N1V52saYEqY= -github.com/ascenmmo/websocket-server v0.0.0-20241024213056-3c1271cc0529 h1:Rwgx3hEykeJMIy9R/abLIz652Y1ZYnQR1cgSUOCV714= -github.com/ascenmmo/websocket-server v0.0.0-20241024213056-3c1271cc0529/go.mod h1:P6ISIRo2rzqMDx5YzP7ixsFKXbYMw0DeYkAPsJS5ScE= +github.com/ascenmmo/tcp-server v1.0.2 h1:ykvz3at8Efm7dPJXlIPrDlcEMSq9GS9TpqD9WUh+EjI= +github.com/ascenmmo/tcp-server v1.0.2/go.mod h1:14K6fwh/Sj958MMSPA+35xHzng0ZzVc2oq5kpXYLQbo= +github.com/ascenmmo/token-generator v1.0.2 h1:NpqtMWsx/XhhZlvodPjWvwx9jVKxe6xrUnLTHBCBR8k= +github.com/ascenmmo/token-generator v1.0.2/go.mod h1:M3RdQKl1JfQeqM2hWNs0645G48GupB7idwdzQMkxlxM= +github.com/ascenmmo/udp-server v1.0.2 h1:4ckeABZEE4s3qJ5C2M9v/Gku5rReNKC/l+xUIW6beyc= +github.com/ascenmmo/udp-server v1.0.2/go.mod h1:uJBaE4CgtsgKsu7DFiW9+RYy+BXjjG3+N1V52saYEqY= +github.com/ascenmmo/websocket-server v1.0.3 h1:fBpYxAadz+VXXIJjZTptedoWASdhJNw+u/VG/gTzSjc= +github.com/ascenmmo/websocket-server v1.0.3/go.mod h1:P6ISIRo2rzqMDx5YzP7ixsFKXbYMw0DeYkAPsJS5ScE= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -63,6 +63,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 h1:uhcF5Jd7rP9DVEL10S github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0/go.mod h1:+oCZ5GXXr7KPI/DNOQORPTq5AWHfALJj9c72b0+YsEY= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -85,6 +87,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= @@ -113,11 +117,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -126,21 +133,25 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= diff --git a/internal/errors/access.go b/internal/errors/access.go index b57044e..32b60b7 100644 --- a/internal/errors/access.go +++ b/internal/errors/access.go @@ -5,4 +5,5 @@ import "errors" var ( ErrAccessDenied = errors.New("access denied") ErrAccessDeniedDeleteCreatorID = errors.New("access denied cannot delete creatorID") + ErrRecordAlredyExists = errors.New("record already exists") ) diff --git a/internal/errors/client.go b/internal/errors/client.go index eef6c53..f24f8fb 100644 --- a/internal/errors/client.go +++ b/internal/errors/client.go @@ -4,5 +4,8 @@ import "errors" var ( ErrClientCreationError = errors.New("error creating client") - ErrClientNotFound = errors.New("error client not found") + ErrNotFound = errors.New("error not found") + ErrWrongUserOrPassword = errors.New("error wrong user or password") + ErrBadNewPassword = errors.New("error bad new password") + ErrGameSaves = errors.New("error game saves found") ) diff --git a/internal/errors/errors.go b/internal/errors/errors.go new file mode 100644 index 0000000..5c69133 --- /dev/null +++ b/internal/errors/errors.go @@ -0,0 +1,7 @@ +package errors + +import "errors" + +var ( + ErrTooManyRequests = errors.New("too many requests") +) diff --git a/internal/service/access/access.go b/internal/service/access/access.go index 2ad52f6..89a7178 100644 --- a/internal/service/access/access.go +++ b/internal/service/access/access.go @@ -31,7 +31,7 @@ func (c *accessGame) CreateNew(gameID, userID uuid.UUID) (err error) { err = c.storage.CreateAccessGame(gameAccess) if err != nil { - return err + return errors.ErrRecordAlredyExists } return nil @@ -54,7 +54,7 @@ func (c *accessGame) AddOwner(ownerID uuid.UUID, gameID, newOwnerID uuid.UUID) ( } gameAccess.Owners = append(gameAccess.Owners, newOwnerID) - err = c.storage.CreateAccessGame(gameAccess) + err = c.storage.Update(gameAccess) if err != nil { return err } diff --git a/internal/service/dev_tools/connections.go b/internal/service/dev_tools/connections.go index eba3a72..4e6681c 100644 --- a/internal/service/dev_tools/connections.go +++ b/internal/service/dev_tools/connections.go @@ -14,12 +14,11 @@ import ( ) type connections struct { - gameStorage storage.GameStorage - serverStorage storage.ServersStorage - roomsStorage storage.RoomsStorage - gameConfigsStorage storage.GameConfigsStorage - token tokengenerator.TokenGenerator - logger *zerolog.Logger + gameStorage storage.GameStorage + serverStorage storage.ServersStorage + roomsStorage storage.RoomsStorage + token tokengenerator.TokenGenerator + logger *zerolog.Logger } func (c *connections) CreateRoom(ctx context.Context, token string, gameID uuid.UUID) (newToken string, err error) { @@ -52,7 +51,7 @@ func (c *connections) CreateRoom(ctx context.Context, token string, gameID uuid. for i := range servers { exists, err := servers[i].IsExists(ctx, token) if err != nil { - c.logger.Error().Err(err) + c.logger.Error().Err(err).Msg("IsExists error") continue } if exists { @@ -144,14 +143,12 @@ func (c *connections) GetRoomsConnectionUrls(ctx context.Context, token string) return []types.ConnectionServer{}, errors.ErrServerCreatingRoomAllServesOffError } - config, err := c.gameConfigsStorage.GetConfig(info.GameID) if err != nil { c.logger.Error().Err(err).Msg("game configs not found") } for _, server := range servers { - configForServer := config.ConfigForServer(server.ServerType) - err = server.CreateRoom(ctx, token, configForServer) + err = server.CreateRoom(ctx, token) if err != nil { if err.Error() != errors.ErrRoomIsExists.Error() { c.logger.Error().Err(err).Msg("server error create room") @@ -187,6 +184,6 @@ func (c *connections) RemoveRoomByID(ctx context.Context, token string, gameID u return nil } -func NewConnections(gameStorage storage.GameStorage, serverStorage storage.ServersStorage, roomsStorage storage.RoomsStorage, gameConfigsStorage storage.GameConfigsStorage, token tokengenerator.TokenGenerator, logger *zerolog.Logger) multiplayer.DevToolsConnections { - return &connections{gameStorage: gameStorage, serverStorage: serverStorage, roomsStorage: roomsStorage, gameConfigsStorage: gameConfigsStorage, token: token, logger: logger} +func NewConnections(gameStorage storage.GameStorage, serverStorage storage.ServersStorage, roomsStorage storage.RoomsStorage, token tokengenerator.TokenGenerator, logger *zerolog.Logger) multiplayer.DevToolsConnections { + return &connections{gameStorage: gameStorage, serverStorage: serverStorage, roomsStorage: roomsStorage, token: token, logger: logger} } diff --git a/internal/service/registration/client.go b/internal/service/registration/client.go index 1c8e4fe..b73ea1a 100644 --- a/internal/service/registration/client.go +++ b/internal/service/registration/client.go @@ -9,24 +9,34 @@ import ( tokentype "github.com/ascenmmo/token-generator/token_type" "github.com/google/uuid" "github.com/rs/zerolog" + "strings" "time" ) type clientService struct { - clientStorage storage.ClientStorage - gameStorage storage.GameStorage - roomStorage storage.RoomsStorage - token tokengenerator.TokenGenerator + clientStorage storage.ClientStorage + gameStorage storage.GameStorage + roomStorage storage.RoomsStorage + gameSavesStorage storage.GameSavesStorage + token tokengenerator.TokenGenerator logger *zerolog.Logger } func (c *clientService) SignUp(ctx context.Context, client types.Client) (token string, refresh string, err error) { - client.ID = uuid.NewMD5(uuid.NameSpaceX500, []byte(client.GameID.String()+client.Email)) + newClient := types.Client{} + newClient.Update(client) - client.Password = c.token.PasswordHash(client.Password) + newClient.GameID = client.GameID + newClient.Password = client.Password + newClient.NewPassword = client.NewPassword - game, err := c.gameStorage.FindByID(client.GameID) + newClient.Password, err = c.token.GenerateSecretHash(newClient.Password) + if err != nil { + return token, refresh, errors.ErrBadNewPassword + } + + game, err := c.gameStorage.FindByID(newClient.GameID) if err != nil { return token, refresh, errors.ErrGameNotFound } @@ -37,20 +47,20 @@ func (c *clientService) SignUp(ctx context.Context, client types.Client) (token return token, refresh, errors.ErrGameNotFound } - err = c.clientStorage.CreateClient(client) + err = c.clientStorage.CreateClient(newClient) if err != nil { return token, refresh, errors.ErrClientCreationError } token, err = c.token.GenerateToken(tokentype.Info{ - UserID: client.ID, - GameID: client.GameID, + UserID: newClient.ID, + GameID: newClient.GameID, TTL: time.Minute * 15, }, tokengenerator.JWT) refresh, err = c.token.GenerateToken(tokentype.Info{ - UserID: client.ID, - GameID: client.GameID, + UserID: newClient.ID, + GameID: newClient.GameID, TTL: time.Hour * 24, }, tokengenerator.JWT) @@ -62,18 +72,16 @@ func (c *clientService) SignUp(ctx context.Context, client types.Client) (token } func (c *clientService) SignIn(ctx context.Context, client types.Client) (token, refresh string, err error) { - client.Password = c.token.PasswordHash(client.Password) + client.Password, err = c.token.GenerateSecretHash(client.Password) + if err != nil { + return token, refresh, errors.ErrBadNewPassword + } - if client.Nickname != "" { - client, err = c.clientStorage.FindByNicknameAndPassword(client.GameID, client.Nickname, client.Password) - if err != nil { - return token, refresh, errors.ErrClientNotFound - } - } else { - client, err = c.clientStorage.FindByEmailAndPassword(client.GameID, client.Email, client.Password) - if err != nil { - return token, refresh, errors.ErrClientNotFound - } + client.Email = strings.ToLower(client.Email) + + client, err = c.clientStorage.FindByPassword(client.GameID, client.Email, client.Nickname, client.Password) + if err != nil { + return token, refresh, errors.ErrWrongUserOrPassword } token, err = c.token.GenerateToken(tokentype.Info{ @@ -149,39 +157,80 @@ func (c *clientService) GetClient(ctx context.Context, token string, gameID uuid } func (c *clientService) UpdateClient(ctx context.Context, token string, client types.Client) (err error) { - //info, err := c.token.ParseToken(token) - //if err != nil { - // return err - //} - // - //if client.Password != "" && client.Nickname != "" { - // oldClient, err := c.clientStorage.FindByID(client.ID, client.GameID) - // if err != nil { - // return err - // } - // oldClient.Email = client.Email - // if oldClient.Nickname != client.Nickname { - // newID := uuid.NewMD5(uuid.NameSpaceX500, []byte(client.GameID.String()+client.Email)) - // _, err = c.clientStorage.FindByID(newID, client.GameID) - // if err == nil { - // return errors.ErrClientNickNameNotExists - // } - // oldClient.ID = newID - // } - // - // err = c.clientStorage.Update(oldClient) - //} - // - //client.ID = info.UserID - // - //err = c.clientStorage.Update(client) - //if err != nil { - // return err - //} + info, err := c.token.ParseToken(token) + if err != nil { + return err + } + + oldClient, err := c.clientStorage.FindByID(info.UserID, info.GameID) + if err != nil { + return errors.ErrNotFound + } + + if client.Password != "" && client.NewPassword != "" { + hash, _ := c.token.GenerateSecretHash(client.Password) + newPswHash, err := c.token.GenerateSecretHash(client.NewPassword) + if err != nil { + return errors.ErrBadNewPassword + } + if oldClient.Password != hash { + return errors.ErrNotFound + } + oldClient.Password = newPswHash + } + + oldClient.Update(client) + + client.ID = info.UserID + + err = c.clientStorage.Update(client) + if err != nil { + return err + } return nil } -func NewClientService(clientStorage storage.ClientStorage, gameStorage storage.GameStorage, roomStorage storage.RoomsStorage, token tokengenerator.TokenGenerator, logger *zerolog.Logger) *clientService { - return &clientService{clientStorage: clientStorage, gameStorage: gameStorage, roomStorage: roomStorage, token: token, logger: logger} +func (c *clientService) GetGameSaves(ctx context.Context, token string) (gameSaves types.GameSaves, err error) { + info, err := c.token.ParseToken(token) + if err != nil { + return gameSaves, err + } + gameSaves, err = c.gameSavesStorage.FindByID(info.GameID, info.UserID) + if err != nil { + return gameSaves, errors.ErrGameSaves + } + + return gameSaves, nil +} + +func (c *clientService) SetGameSaves(ctx context.Context, token string, gameSaves types.GameSaves) (err error) { + info, err := c.token.ParseToken(token) + if err != nil { + return err + } + + gameSaves.ID = uuid.NewMD5(uuid.NameSpaceX500, []byte(info.GameID.String()+info.UserID.String())) + gameSaves.GameID = info.GameID + gameSaves.UserID = info.UserID + + _, err = c.gameSavesStorage.FindByID(info.GameID, info.UserID) + if err != nil { + return c.gameSavesStorage.Create(gameSaves) + } + + return c.gameSavesStorage.Update(gameSaves) +} + +func (c *clientService) DeleteGameSaves(ctx context.Context, token string) (err error) { + info, err := c.token.ParseToken(token) + if err != nil { + return err + } + + return c.gameSavesStorage.Delete(info.GameID, info.UserID) +} + +func NewClientService(clientStorage storage.ClientStorage, gameStorage storage.GameStorage, gameSavesStorage storage.GameSavesStorage, roomStorage storage.RoomsStorage, token tokengenerator.TokenGenerator, logger *zerolog.Logger) *clientService { + return &clientService{clientStorage: clientStorage, gameStorage: gameStorage, gameSavesStorage: gameSavesStorage, roomStorage: roomStorage, token: token, logger: logger} } diff --git a/internal/service/registration/developer.go b/internal/service/registration/developer.go index 10c252a..bacc21f 100644 --- a/internal/service/registration/developer.go +++ b/internal/service/registration/developer.go @@ -2,7 +2,7 @@ package registration import ( "context" - "fmt" + "github.com/ascenmmo/multiplayer-game-servers/internal/errors" "github.com/ascenmmo/multiplayer-game-servers/internal/storage" "github.com/ascenmmo/multiplayer-game-servers/pkg/multiplayer" "github.com/ascenmmo/multiplayer-game-servers/pkg/multiplayer/types" @@ -10,6 +10,7 @@ import ( tokentype "github.com/ascenmmo/token-generator/token_type" "github.com/google/uuid" "github.com/rs/zerolog" + "strings" "time" ) @@ -22,12 +23,16 @@ type developerService struct { func (c *developerService) SignUp(ctx context.Context, developer types.Developer) (token string, refresh string, err error) { developer.ID = uuid.NewMD5(uuid.NameSpaceX500, []byte(developer.Email)) + developer.Email = strings.ToLower(developer.Email) - developer.Password = c.token.PasswordHash(developer.Password) + developer.Password, err = c.token.GenerateSecretHash(developer.Password) + if err != nil { + return token, refresh, errors.ErrBadNewPassword + } err = c.developerStorage.CreateDeveloper(developer) if err != nil { - return + return token, refresh, errors.ErrRecordAlredyExists } token, err = c.token.GenerateToken(tokentype.Info{ @@ -48,11 +53,16 @@ func (c *developerService) SignUp(ctx context.Context, developer types.Developer } func (c *developerService) SignIn(ctx context.Context, developer types.Developer) (token, refresh string, err error) { - developer.Password = c.token.PasswordHash(developer.Password) + developer.Password, err = c.token.GenerateSecretHash(developer.Password) + if err != nil { + return token, refresh, errors.ErrBadNewPassword + } + + developer.Email = strings.ToLower(developer.Email) developer, err = c.developerStorage.FindByPassword(developer.Email, developer.Nickname, developer.Password) if err != nil { - return + return token, refresh, errors.ErrWrongUserOrPassword } token, err = c.token.GenerateToken(tokentype.Info{ @@ -117,9 +127,6 @@ func (c *developerService) UpdateDeveloper(ctx context.Context, token string, de if err != nil { return err } - - developer.Password = c.token.PasswordHash(developer.Password) - developer.ID = info.UserID oldDev, err := c.developerStorage.FindByID(developer.ID) @@ -128,9 +135,16 @@ func (c *developerService) UpdateDeveloper(ctx context.Context, token string, de } if developer.Password != "" && developer.NewPassword != "" { - fmt.Println("tut") - if developer.Password == oldDev.Password { - oldDev.Password = c.token.PasswordHash(developer.NewPassword) + pswHash, err := c.token.GenerateSecretHash(developer.Password) + if err != nil { + return errors.ErrNotFound + } + + if developer.Password == pswHash { + oldDev.Password, err = c.token.GenerateSecretHash(developer.NewPassword) + if err != nil { + return errors.ErrBadNewPassword + } } } @@ -139,7 +153,7 @@ func (c *developerService) UpdateDeveloper(ctx context.Context, token string, de } if developer.Email != "" { - oldDev.Nickname = developer.Nickname + oldDev.Email = strings.ToLower(developer.Email) } err = c.developerStorage.Update(oldDev) diff --git a/internal/service/scheduler/scheduler.go b/internal/service/scheduler/scheduler.go deleted file mode 100644 index 8c4b6c5..0000000 --- a/internal/service/scheduler/scheduler.go +++ /dev/null @@ -1,95 +0,0 @@ -package scheduler - -import ( - "context" - "github.com/ascenmmo/multiplayer-game-servers/internal/storage" - tokengenerator "github.com/ascenmmo/token-generator/token_generator" - tokentype "github.com/ascenmmo/token-generator/token_type" - "github.com/google/uuid" - "github.com/rs/zerolog/log" - "time" -) - -type Scheduler interface { - Run(ctx context.Context) -} - -type scheduler struct { - gameStorage storage.GameStorage - roomStorage storage.RoomsStorage - serverStorage storage.ServersStorage - confResultStorage storage.GameConfigsResultsStorage - tokenGenerator tokengenerator.TokenGenerator -} - -func (s scheduler) Run(ctx context.Context) { - ticker := time.NewTicker(time.Second * 1) - for range ticker.C { - err := s.getConfigResultsFromServer(ctx) - if err != nil { - log.Error().Err(err).Msg("error getting config results from server") - } - } -} - -func (s scheduler) getConfigResultsFromServer(ctx context.Context) (err error) { - serverIDs, err := s.serverStorage.FindAllServerIDs() - if err != nil { - return - } - - token, _ := s.tokenGenerator.GenerateToken(tokentype.Info{ - GameID: uuid.New(), - RoomID: uuid.New(), - UserID: uuid.New(), - }, tokengenerator.JWT) - - var batchServerIDs [][]uuid.UUID - batchSize := 10 - - for i := 0; i < len(serverIDs); i += batchSize { - end := i + batchSize - - if end > len(serverIDs) { - end = len(serverIDs) - } - - batchServerIDs = append(batchServerIDs, serverIDs[i:end]) - } - - for _, batch := range batchServerIDs { - servers, err := s.serverStorage.FindByIDs(batch) - if err != nil { - continue - } - - for _, server := range servers { - results, err := server.GetGameConfigResults(ctx, token) - if err != nil { - continue - } - - if len(results) == 0 { - continue - } - - err = s.confResultStorage.CreateMany(results) - if err != nil { - return err - } - - for _, result := range results { - err := s.roomStorage.Delete(result.RoomID) - if err != nil { - return err - } - } - } - } - - return nil -} - -func NewScheduler(gameStorage storage.GameStorage, roomStorage storage.RoomsStorage, serverStorage storage.ServersStorage, confResultStorage storage.GameConfigsResultsStorage, tokenGenerator tokengenerator.TokenGenerator) *scheduler { - return &scheduler{gameStorage: gameStorage, roomStorage: roomStorage, serverStorage: serverStorage, confResultStorage: confResultStorage, tokenGenerator: tokenGenerator} -} diff --git a/internal/start/multiplatform.go b/internal/start/multiplatform.go index 166d1cb..2d626f8 100644 --- a/internal/start/multiplatform.go +++ b/internal/start/multiplatform.go @@ -1,21 +1,24 @@ package start import ( - "context" "fmt" "github.com/ascenmmo/multiplayer-game-servers/env" + "github.com/ascenmmo/multiplayer-game-servers/internal/errors" "github.com/ascenmmo/multiplayer-game-servers/internal/service/access" devtools "github.com/ascenmmo/multiplayer-game-servers/internal/service/dev_tools" "github.com/ascenmmo/multiplayer-game-servers/internal/service/registration" - "github.com/ascenmmo/multiplayer-game-servers/internal/service/scheduler" "github.com/ascenmmo/multiplayer-game-servers/internal/storage" adminclient "github.com/ascenmmo/multiplayer-game-servers/pkg/admin_client" "github.com/ascenmmo/multiplayer-game-servers/pkg/admin_client/dev_doc" "github.com/ascenmmo/multiplayer-game-servers/pkg/transport" tokengenerator "github.com/ascenmmo/token-generator/token_generator" "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/limiter" + _ "github.com/gofiber/fiber/v2/middleware/limiter" "github.com/rs/zerolog" "html/template" + "runtime" + "time" ) func Multiplayer(logger zerolog.Logger) { @@ -40,17 +43,15 @@ func Multiplayer(logger zerolog.Logger) { mastNil(err) gameConfigStorage, err := storage.NewGameConfigsStorage(client) mastNil(err) - gameConfigResultsStorage, err := storage.NewGameConfigsResultsStorage(client) + gameSavesStorage, err := storage.NewGameSavesStorage(client) mastNil(err) accessGameService := access.NewAccessGame(accessGameStorage) - newScheduler := scheduler.NewScheduler(gameStorage, roomStorage, serverStorage, gameConfigResultsStorage, token) - developerService := registration.NewDeveloperService(developerStorage, token, &logger) - clientService := registration.NewClientService(clientStorage, gameStorage, roomStorage, token, &logger) + clientService := registration.NewClientService(clientStorage, gameStorage, gameSavesStorage, roomStorage, token, &logger) - devToolsConnectionServicc := devtools.NewConnections(gameStorage, serverStorage, roomStorage, gameConfigStorage, token, &logger) + devToolsConnectionServicc := devtools.NewConnections(gameStorage, serverStorage, roomStorage, token, &logger) devToolsService := devtools.NewDevTools(accessGameService, gameStorage, serverStorage, token, &logger) devToolsServerService := devtools.NewServerService(accessGameService, gameStorage, serverStorage, token, &logger) devToolsGameConfigs := devtools.NewGameConfigs(accessGameService, gameConfigStorage, token, &logger) @@ -65,14 +66,22 @@ func Multiplayer(logger zerolog.Logger) { transport.DevToolsGameConfigs(transport.NewDevToolsGameConfigs(devToolsGameConfigs)), } + logMemoryUsage(&logger) + srv := transport.New(logger, services...).WithLog() + app := srv.Fiber() if env.RunAdminPanel { - app := srv.Fiber() adminPanel(app) } - go newScheduler.Run(context.Background()) + app.Use(limiter.New(limiter.Config{ + Max: env.MultiplayerMaxRequestPerSecond, + Expiration: 1 * time.Second, + LimitReached: func(c *fiber.Ctx) error { + return c.Status(fiber.StatusTooManyRequests).SendString(errors.ErrTooManyRequests.Error()) + }, + })) logger.Info().Str("bind", fmt.Sprintf("http://%s:%s", env.ServerAddress, env.MultiplayerPort)).Msg("listen on") if err := srv.Fiber().Listen(":" + env.MultiplayerPort); err != nil { @@ -80,6 +89,24 @@ func Multiplayer(logger zerolog.Logger) { } } +func logMemoryUsage(logger *zerolog.Logger) { + ticker := time.NewTicker(time.Second * 10) + go func() { + for range ticker.C { + var stats runtime.MemStats + runtime.ReadMemStats(&stats) + logger.Info(). + Interface("num cpu", runtime.NumCPU()). + Interface("num gorutins", runtime.NumGoroutine()). + Interface("Memory Usage", stats.Alloc/1024/1024). + Interface("TotalAlloc", stats.TotalAlloc/1024/1024). + Interface("Sys", stats.Sys/1024/1024). + Interface("NumGC", stats.NumGC). + Msg("system") + } + }() +} + func mastNil(err error) { if err != nil { panic(err) @@ -88,12 +115,12 @@ func mastNil(err error) { func adminPanel(app *fiber.App) { app.Get("/", func(c *fiber.Ctx) error { - tmpl, err := template.New("docs").Parse(string(adminclient.MainPage("ru"))) + tmpl, err := template.New("docs").Parse(string(adminclient.MainPage(detectLanguage(c)))) if err != nil { return err } c.Set("Content-Type", "text/html") - err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory()) + err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory(detectLanguage(c))) if err != nil { return err } @@ -101,12 +128,12 @@ func adminPanel(app *fiber.App) { }) app.Get("/developer/doc", func(c *fiber.Ctx) error { - tmpl, err := template.New("docs").Parse(string(adminclient.DevDocs("ru"))) + tmpl, err := template.New("docs").Parse(string(adminclient.DevDocs(detectLanguage(c)))) if err != nil { return err } c.Set("Content-Type", "text/html") - err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory()) + err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory(detectLanguage(c))) if err != nil { return err } @@ -115,12 +142,12 @@ func adminPanel(app *fiber.App) { }) app.Get("/admin/auth", func(c *fiber.Ctx) error { - tmpl, err := template.New("docs").Parse(string(adminclient.Auth("ru"))) + tmpl, err := template.New("docs").Parse(string(adminclient.Auth(detectLanguage(c)))) if err != nil { return err } c.Set("Content-Type", "text/html") - err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory()) + err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory(detectLanguage(c))) if err != nil { return err } @@ -128,12 +155,12 @@ func adminPanel(app *fiber.App) { }) app.Get("/admin/games", func(c *fiber.Ctx) error { - tmpl, err := template.New("docs").Parse(string(adminclient.GameCollection("ru"))) + tmpl, err := template.New("docs").Parse(string(adminclient.GameCollection(detectLanguage(c)))) if err != nil { return err } c.Set("Content-Type", "text/html") - err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory()) + err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory(detectLanguage(c))) if err != nil { return err } @@ -141,12 +168,12 @@ func adminPanel(app *fiber.App) { }) app.Get("/admin/game_info", func(c *fiber.Ctx) error { - tmpl, err := template.New("docs").Parse(string(adminclient.GameInfo("ru"))) + tmpl, err := template.New("docs").Parse(string(adminclient.GameInfo(detectLanguage(c)))) if err != nil { return err } c.Set("Content-Type", "text/html") - err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory()) + err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory(detectLanguage(c))) if err != nil { return err } @@ -154,12 +181,12 @@ func adminPanel(app *fiber.App) { }) app.Get("/admin/game_info/config", func(c *fiber.Ctx) error { - tmpl, err := template.New("docs").Parse(string(adminclient.GameConfig("ru"))) + tmpl, err := template.New("docs").Parse(string(adminclient.GameConfig(detectLanguage(c)))) if err != nil { return err } c.Set("Content-Type", "text/html") - err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory()) + err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory(detectLanguage(c))) if err != nil { return err } @@ -167,15 +194,27 @@ func adminPanel(app *fiber.App) { }) app.Get("/admin/info", func(c *fiber.Ctx) error { - tmpl, err := template.New("docs").Parse(string(adminclient.DeveloperInfo("ru"))) + tmpl, err := template.New("docs").Parse(string(adminclient.DeveloperInfo(detectLanguage(c)))) if err != nil { return err } c.Set("Content-Type", "text/html") - err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory()) + err = tmpl.Execute(c.Response().BodyWriter(), dev_doc.GetCategory(detectLanguage(c))) if err != nil { return err } return nil }) } + +func detectLanguage(c *fiber.Ctx) (lng string) { + //acceptLanguage := c.Get("Accept-Language", "") + admin := c.Cookies("AdminLanguageLanguage", adminclient.Ru) + if admin != "" { + return admin + } + //if strings.Contains(acceptLanguage, detectLanguage(c)) { + // return adminclient.Ru + //} + return adminclient.Eng +} diff --git a/internal/start/rest.go b/internal/start/rest.go index 9709aa4..9874d5a 100644 --- a/internal/start/rest.go +++ b/internal/start/rest.go @@ -15,8 +15,8 @@ func TcpServer(ctx context.Context, logger zerolog.Logger) { env.TokenKey, env.TcpServerMaxRequestPerSecond, 10, - 60, logger.With().Str("server:", "tcp").Logger(), + false, ) mastNil(err) } diff --git a/internal/start/udp.go b/internal/start/udp.go index 42e6946..458b135 100644 --- a/internal/start/udp.go +++ b/internal/start/udp.go @@ -16,8 +16,8 @@ func UdpServer(ctx context.Context, logger zerolog.Logger) { env.TokenKey, env.UdpServerMaxRequestPerSecond, 10, - 60, logger.With().Str("server:", "udp").Logger(), + false, ) mastNil(err) } diff --git a/internal/start/ws.go b/internal/start/ws.go index c2fd444..fa6def3 100644 --- a/internal/start/ws.go +++ b/internal/start/ws.go @@ -16,8 +16,8 @@ func WebsocketRun(ctx context.Context, logger zerolog.Logger) { env.TokenKey, env.WebsocketServerMaxRequestPerSecond, 10, - 60, logger.With().Str("server:", "websocket").Logger(), + false, ) mastNil(err) } diff --git a/internal/storage/client.go b/internal/storage/client.go index a6d5454..25de1c5 100644 --- a/internal/storage/client.go +++ b/internal/storage/client.go @@ -11,8 +11,7 @@ import ( type ClientStorage interface { CreateClient(client types.Client) (err error) FindByID(clientID uuid.UUID, gameID uuid.UUID) (client types.Client, err error) - FindByEmailAndPassword(gameID uuid.UUID, email, password string) (client types.Client, err error) - FindByNicknameAndPassword(gameID uuid.UUID, nickname, password string) (client types.Client, err error) + FindByPassword(gameID uuid.UUID, email, nickname, password string) (client types.Client, err error) Update(client types.Client) (err error) } @@ -20,31 +19,6 @@ type clientStorage struct { collection *mongo.Collection } -func NewClientStorage(client *mongo.Client) (ClientStorage, error) { - coll := client.Database(dataBaseClients).Collection(clientsCollectionKey) - _, err := coll.Indexes().CreateMany( - context.Background(), - []mongo.IndexModel{ - { - Keys: bson.D{ - {Key: "email", Value: 1}, - {Key: "nickname", Value: 1}, - {Key: "password", Value: 1}, - {Key: "gameID", Value: 1}, - }, - }, - }, - ) - if err != nil { - return &clientStorage{}, nil - } - - return &clientStorage{ - collection: coll, - }, nil - -} - func (c *clientStorage) CreateClient(client types.Client) (err error) { _, err = c.collection.InsertOne(context.TODO(), client) return err @@ -52,7 +26,8 @@ func (c *clientStorage) CreateClient(client types.Client) (err error) { func (c *clientStorage) FindByID(clientID uuid.UUID, gameID uuid.UUID) (client types.Client, err error) { filter := bson.M{ - "_id": clientID, + "_id": clientID, + "gameID": gameID, } err = c.collection.FindOne(context.TODO(), filter).Decode(&client) if err != nil { @@ -61,24 +36,16 @@ func (c *clientStorage) FindByID(clientID uuid.UUID, gameID uuid.UUID) (client t return client, nil } -func (c *clientStorage) FindByEmailAndPassword(gameID uuid.UUID, email, password string) (client types.Client, err error) { +func (c *clientStorage) FindByPassword(gameID uuid.UUID, email, nickname, password string) (client types.Client, err error) { filter := bson.M{ "gameID": gameID, - "email": email, "password": password, } - err = c.collection.FindOne(context.TODO(), filter).Decode(&client) - if err != nil { - return client, err + if email != "" { + filter["email"] = email } - return client, nil -} - -func (c *clientStorage) FindByNicknameAndPassword(gameID uuid.UUID, nickname, password string) (client types.Client, err error) { - filter := bson.M{ - "gameID": gameID, - "nickname": nickname, - "password": password, + if nickname != "" { + filter["nickname"] = nickname } err = c.collection.FindOne(context.TODO(), filter).Decode(&client) if err != nil { @@ -98,3 +65,28 @@ func (c *clientStorage) Update(client types.Client) (err error) { } return nil } + +func NewClientStorage(client *mongo.Client) (ClientStorage, error) { + coll := client.Database(dataBaseClients).Collection(clientsCollectionKey) + _, err := coll.Indexes().CreateMany( + context.Background(), + []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "email", Value: 1}, + {Key: "nickname", Value: 1}, + {Key: "password", Value: 1}, + {Key: "gameID", Value: 1}, + }, + }, + }, + ) + if err != nil { + return &clientStorage{}, nil + } + + return &clientStorage{ + collection: coll, + }, nil + +} diff --git a/internal/storage/game_saves.go b/internal/storage/game_saves.go new file mode 100644 index 0000000..4eff92e --- /dev/null +++ b/internal/storage/game_saves.go @@ -0,0 +1,84 @@ +package storage + +import ( + "context" + "github.com/ascenmmo/multiplayer-game-servers/pkg/multiplayer/types" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type GameSavesStorage interface { + Create(gameSave types.GameSaves) (err error) + FindByID(gameID uuid.UUID, userID uuid.UUID) (gameSave types.GameSaves, err error) + Update(gameSave types.GameSaves) (err error) + Delete(gameID uuid.UUID, userID uuid.UUID) (err error) +} + +type gameSavesStorage struct { + collection *mongo.Collection +} + +func (d *gameSavesStorage) Create(gameSave types.GameSaves) (err error) { + _, err = d.collection.InsertOne(context.TODO(), gameSave) + return err +} + +func (d *gameSavesStorage) FindByID(gameID uuid.UUID, userID uuid.UUID) (gameSave types.GameSaves, err error) { + filter := bson.M{ + "gameID": gameID, + "userID": userID, + } + err = d.collection.FindOne(context.TODO(), filter).Decode(&gameSave) + if err != nil { + return gameSave, err + } + return gameSave, nil +} + +func (d *gameSavesStorage) Update(gameSave types.GameSaves) (err error) { + filter := bson.M{ + "gameID": gameSave.GameID, + "userID": gameSave.UserID, + } + update := bson.M{"$set": gameSave} + _, err = d.collection.UpdateOne(context.TODO(), filter, update) + if err != nil { + return err + } + return nil +} + +func (d *gameSavesStorage) Delete(gameID uuid.UUID, userID uuid.UUID) (err error) { + filter := bson.M{ + "gameID": gameID, + "userID": userID, + } + + _, err = d.collection.DeleteOne(context.TODO(), filter) + if err != nil { + return err + } + + return nil +} + +func NewGameSavesStorage(client *mongo.Client) (GameSavesStorage, error) { + coll := client.Database(dataBaseGame).Collection(gameSavesCollectionKey) + _, err := coll.Indexes().CreateMany( + context.Background(), + []mongo.IndexModel{{ + Keys: bson.D{{Key: "name", Value: 1}}, + Options: options.Index().SetUnique(true), + }, + }, + ) + if err != nil { + return &gameSavesStorage{}, err + } + + return &gameSavesStorage{ + collection: coll, + }, nil +} diff --git a/internal/storage/mongo.go b/internal/storage/mongo.go index be9821b..05d7a96 100644 --- a/internal/storage/mongo.go +++ b/internal/storage/mongo.go @@ -26,6 +26,7 @@ const ( roomsCollectionKey = "rooms" configsCollectionKey = "configs" configsResultCollectionKey = "configs_results" + gameSavesCollectionKey = "games_saves" dataBaseAccess = "access" accessGameCollectionKey = "accessGame" diff --git a/internal/storage/server_configuration.go b/internal/storage/server_configuration.go deleted file mode 100644 index ea4ca9d..0000000 --- a/internal/storage/server_configuration.go +++ /dev/null @@ -1,62 +0,0 @@ -package storage - -import ( - "encoding/json" - "github.com/ascenmmo/multiplayer-game-servers/pkg/multiplayer/types" - tokengenerator "github.com/ascenmmo/token-generator/token_generator" - "os" -) - -type ServerConfiguration interface { - Create(conf types.ServerConfiguration) (err error) - Read() (conf types.ServerConfiguration, err error) -} - -type serverConfiguration struct { - generator tokengenerator.TokenGenerator -} - -func NewServerConfiguration(generator tokengenerator.TokenGenerator) ServerConfiguration { - return &serverConfiguration{ - generator: generator, - } -} - -func (s *serverConfiguration) Create(conf types.ServerConfiguration) (err error) { - create, err := os.Create("server_configuration.txt") - if err != nil { - return err - } - marshal, err := json.Marshal(conf) - if err != nil { - return err - } - - data, err := s.generator.GenerateHash(string(marshal)) - if err != nil { - return err - } - - _, err = create.Write([]byte(data)) - if err != nil { - return err - } - - return nil -} - -func (s *serverConfiguration) Read() (conf types.ServerConfiguration, err error) { - file, err := os.ReadFile("server_configuration.txt") - if err != nil { - return conf, err - } - - txt, err := s.generator.ParseHash(string(file)) - if err != nil { - return conf, err - } - - err = json.Unmarshal([]byte(txt), &conf) - - return conf, err -} diff --git a/pkg/admin_client/adminpanel.go b/pkg/admin_client/adminpanel.go index f7af265..97e53cb 100644 --- a/pkg/admin_client/adminpanel.go +++ b/pkg/admin_client/adminpanel.go @@ -3,83 +3,83 @@ package adminclient import "github.com/ascenmmo/multiplayer-game-servers/pkg/admin_client/assets/pages" const ( - ru = "ru" - eng = "eng" + Ru = "ru" + Eng = "eng" ) -func DevDocs(lengudage string) string { - switch lengudage { - case ru: - return pages.Docs - case eng: - return pages.Docs +func DevDocs(lEngudage string) string { + switch lEngudage { + case Ru: + return pages.RuDocs + case Eng: + return pages.EngDocs default: - return "not found" + return pages.EngDeveloperInfo } } -func Auth(lengudage string) string { - switch lengudage { - case ru: - return pages.Auth - case eng: - return pages.Auth +func Auth(lEngudage string) string { + switch lEngudage { + case Ru: + return pages.RuAuth + case Eng: + return pages.EngAuth default: - return "not found" + return pages.EngDeveloperInfo } } -func GameCollection(lengudage string) string { - switch lengudage { - case ru: - return pages.GameCollection - case eng: - return pages.GameCollection +func GameCollection(lEngudage string) string { + switch lEngudage { + case Ru: + return pages.RuGameCollection + case Eng: + return pages.EngGameCollection default: - return "not found" + return pages.EngDeveloperInfo } } -func MainPage(lengudage string) string { - switch lengudage { - case ru: - return pages.MainPage - case eng: - return pages.MainPage +func MainPage(lEngudage string) string { + switch lEngudage { + case Ru: + return pages.RuMainPage + case Eng: + return pages.EngMainPage default: - return "not found" + return pages.EngDeveloperInfo } } -func GameInfo(lengudage string) string { - switch lengudage { - case ru: - return pages.GameInfo - case eng: - return pages.GameInfo +func GameInfo(lEngudage string) string { + switch lEngudage { + case Ru: + return pages.RuGameInfo + case Eng: + return pages.EngGameInfo default: - return "not found" + return pages.EngDeveloperInfo } } -func GameConfig(lengudage string) string { - switch lengudage { - case ru: - return pages.GameConfig - case eng: - return pages.GameConfig +func GameConfig(lEngudage string) string { + switch lEngudage { + case Ru: + return pages.RuGameConfig + case Eng: + return pages.EngGameConfig default: - return "not found" + return pages.EngDeveloperInfo } } -func DeveloperInfo(lengudage string) string { - switch lengudage { - case ru: - return pages.DeveloperInfo - case eng: - return pages.DeveloperInfo +func DeveloperInfo(lEngudage string) string { + switch lEngudage { + case Ru: + return pages.RuDeveloperInfo + case Eng: + return pages.EngDeveloperInfo default: - return "not found" + return pages.EngDeveloperInfo } } diff --git a/pkg/admin_client/assets/build_pages.go b/pkg/admin_client/assets/build_pages.go index 5623756..f3e435c 100644 --- a/pkg/admin_client/assets/build_pages.go +++ b/pkg/admin_client/assets/build_pages.go @@ -11,13 +11,21 @@ const dir = "pkg/admin_client/assets/pages/" var ( indexFiles = map[string]string{ - "Auth": dir + "auth/index.html", - "Docs": dir + "docs/ru_index.html", - "GameCollection": dir + "game_collection/index.html", - "MainPage": dir + "main/index.html", - "GameInfo": dir + "game_info/index.html", - "GameConfig": dir + "game_config/index.html", - "DeveloperInfo": dir + "developer_info/index.html", + "RuAuth": dir + "auth/ru_index.html", + "RuDocs": dir + "docs/ru_index.html", + "RuGameCollection": dir + "game_collection/ru_index.html", + "RuMainPage": dir + "main/ru_index.html", + "RuGameInfo": dir + "game_info/ru_index.html", + "RuGameConfig": dir + "game_config/ru_index.html", + "RuDeveloperInfo": dir + "developer_info/ru_index.html", + + "EngAuth": dir + "auth/eng_index.html", + "EngDocs": dir + "docs/eng_index.html", + "EngGameCollection": dir + "game_collection/eng_index.html", + "EngMainPage": dir + "main/eng_index.html", + "EngGameInfo": dir + "game_info/eng_index.html", + "EngGameConfig": dir + "game_config/eng_index.html", + "EngDeveloperInfo": dir + "developer_info/eng_index.html", } ) diff --git a/pkg/admin_client/assets/pages/auth/eng_index.html b/pkg/admin_client/assets/pages/auth/eng_index.html new file mode 100644 index 0000000..35c9ce6 --- /dev/null +++ b/pkg/admin_client/assets/pages/auth/eng_index.html @@ -0,0 +1,270 @@ + + +
+ + +