Comment, list all saves, set port, set hash
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
---
|
---
|
||||||
|
server:
|
||||||
|
port: 8080
|
||||||
database:
|
database:
|
||||||
host: localhost
|
host: localhost
|
||||||
password: root
|
password: root
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
|
Server ServerConfiguration `yaml:"server"`
|
||||||
Database DatabaseConfiguration `yaml:"database"`
|
Database DatabaseConfiguration `yaml:"database"`
|
||||||
Features FeaturesConfiguration `yaml:"features"`
|
Features FeaturesConfiguration `yaml:"features"`
|
||||||
Path PathConfiguration `yaml:"path"`
|
Path PathConfiguration `yaml:"path"`
|
||||||
@@ -18,6 +19,10 @@ type PathConfiguration struct {
|
|||||||
Storage string `yaml:"storage"`
|
Storage string `yaml:"storage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServerConfiguration struct {
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
type DatabaseConfiguration struct {
|
type DatabaseConfiguration struct {
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
@@ -55,3 +60,7 @@ func Features() *FeaturesConfiguration {
|
|||||||
func Path() *PathConfiguration {
|
func Path() *PathConfiguration {
|
||||||
return ¤tConfig.Path
|
return ¤tConfig.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Server() *ServerConfiguration {
|
||||||
|
return ¤tConfig.Server
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -175,31 +173,18 @@ func UploadSave(file multipart.File, game *Game) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateGameRevision(game *Game) error {
|
func UpdateGameRevision(game *Game, hash string) error {
|
||||||
filePath := path.Join(config.Path().Storage, game.PathStorage)
|
|
||||||
file, err := os.Open(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
hash := md5.New()
|
|
||||||
_, err = io.Copy(hash, file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sum := hash.Sum(nil)
|
|
||||||
game.Revision += 1
|
game.Revision += 1
|
||||||
if game.Hash == nil {
|
if game.Hash == nil {
|
||||||
game.Hash = new(string)
|
game.Hash = new(string)
|
||||||
}
|
}
|
||||||
*game.Hash = hex.EncodeToString(sum)
|
*game.Hash = hash
|
||||||
game.Available = true
|
game.Available = true
|
||||||
if game.LastUpdate == nil {
|
if game.LastUpdate == nil {
|
||||||
game.LastUpdate = new(time.Time)
|
game.LastUpdate = new(time.Time)
|
||||||
}
|
}
|
||||||
*game.LastUpdate = time.Now()
|
*game.LastUpdate = time.Now()
|
||||||
err = db.Save(game).Error
|
err := db.Save(game).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ CREATE TABLE IF NOT EXISTS `games` (
|
|||||||
`user_id` bigint unsigned NOT NULL DEFAULT '0',
|
`user_id` bigint unsigned NOT NULL DEFAULT '0',
|
||||||
`available` tinyint unsigned NOT NULL DEFAULT '0',
|
`available` tinyint unsigned NOT NULL DEFAULT '0',
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3;
|
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||||
|
|
||||||
-- Data exporting was unselected.
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ CREATE TABLE IF NOT EXISTS `users` (
|
|||||||
`username` varchar(50) NOT NULL,
|
`username` varchar(50) NOT NULL,
|
||||||
`password` binary(60) NOT NULL,
|
`password` binary(60) NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
|
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||||
|
|
||||||
-- Data exporting was unselected.
|
-- Data exporting was unselected.
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NewGameInfo struct {
|
type NewGameInfo struct {
|
||||||
@@ -26,6 +27,7 @@ type LockError struct {
|
|||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateGame create a game entry to the database
|
||||||
func CreateGame(w http.ResponseWriter, r *http.Request) {
|
func CreateGame(w http.ResponseWriter, r *http.Request) {
|
||||||
userId, err := userIdFromContext(r.Context())
|
userId, err := userIdFromContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -55,6 +57,7 @@ func CreateGame(w http.ResponseWriter, r *http.Request) {
|
|||||||
ok(game, w, r)
|
ok(game, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GameInfoByID get the game save information from the database
|
||||||
func GameInfoByID(w http.ResponseWriter, r *http.Request) {
|
func GameInfoByID(w http.ResponseWriter, r *http.Request) {
|
||||||
userId, err := userIdFromContext(r.Context())
|
userId, err := userIdFromContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -78,6 +81,24 @@ func GameInfoByID(w http.ResponseWriter, r *http.Request) {
|
|||||||
ok(game, w, r)
|
ok(game, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllGamesInformation all game saves information for a user
|
||||||
|
func AllGamesInformation(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userId, err := userIdFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
internalServerError(w, r)
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
games, err := database.GameInfosByUserId(userId)
|
||||||
|
if err != nil {
|
||||||
|
internalServerError(w, r)
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok(games, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AskForUpload check if the game save is not lock, then lock it and generate a token
|
||||||
func AskForUpload(w http.ResponseWriter, r *http.Request) {
|
func AskForUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
userId, err := userIdFromContext(r.Context())
|
userId, err := userIdFromContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -106,6 +127,7 @@ func AskForUpload(w http.ResponseWriter, r *http.Request) {
|
|||||||
ok(token, w, r)
|
ok(token, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UploadSave upload the game save archive to the storage folder
|
||||||
func UploadSave(w http.ResponseWriter, r *http.Request) {
|
func UploadSave(w http.ResponseWriter, r *http.Request) {
|
||||||
userId, err := userIdFromContext(r.Context())
|
userId, err := userIdFromContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -120,6 +142,11 @@ func UploadSave(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer database.UnlockGame(gameId)
|
defer database.UnlockGame(gameId)
|
||||||
|
hash := r.Header.Get("X-Game-Save-Hash")
|
||||||
|
if utf8.RuneCountInString(hash) == 0 {
|
||||||
|
badRequest("The header X-Game-Save-Hash is missing", w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
game, err := database.GameInfoById(userId, gameId)
|
game, err := database.GameInfoById(userId, gameId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
internalServerError(w, r)
|
internalServerError(w, r)
|
||||||
@@ -139,7 +166,7 @@ func UploadSave(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = database.UpdateGameRevision(game)
|
err = database.UpdateGameRevision(game, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
internalServerError(w, r)
|
internalServerError(w, r)
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@@ -153,6 +180,7 @@ func UploadSave(w http.ResponseWriter, r *http.Request) {
|
|||||||
ok(payload, w, r)
|
ok(payload, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Download send the game save archive to the client
|
||||||
func Download(w http.ResponseWriter, r *http.Request) {
|
func Download(w http.ResponseWriter, r *http.Request) {
|
||||||
userId, err := userIdFromContext(r.Context())
|
userId, err := userIdFromContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"log"
|
"log"
|
||||||
@@ -37,6 +38,7 @@ func Serve() {
|
|||||||
r.Route("/game", func(secureRouter chi.Router) {
|
r.Route("/game", func(secureRouter chi.Router) {
|
||||||
secureRouter.Use(authMiddleware)
|
secureRouter.Use(authMiddleware)
|
||||||
secureRouter.Post("/create", CreateGame)
|
secureRouter.Post("/create", CreateGame)
|
||||||
|
secureRouter.Get("/all", AllGamesInformation)
|
||||||
secureRouter.Get("/info/{id}", GameInfoByID)
|
secureRouter.Get("/info/{id}", GameInfoByID)
|
||||||
secureRouter.Post("/upload/init", AskForUpload)
|
secureRouter.Post("/upload/init", AskForUpload)
|
||||||
secureRouter.Group(func(uploadRouter chi.Router) {
|
secureRouter.Group(func(uploadRouter chi.Router) {
|
||||||
@@ -49,7 +51,7 @@ func Serve() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
log.Println("Server is listening...")
|
log.Println("Server is listening...")
|
||||||
err := http.ListenAndServe(":8080", router)
|
err := http.ListenAndServe(fmt.Sprintf(":%d", config.Server().Port), router)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user