Comment, list all saves, set port, set hash
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
---
|
||||
server:
|
||||
port: 8080
|
||||
database:
|
||||
host: localhost
|
||||
password: root
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
)
|
||||
|
||||
type Configuration struct {
|
||||
Server ServerConfiguration `yaml:"server"`
|
||||
Database DatabaseConfiguration `yaml:"database"`
|
||||
Features FeaturesConfiguration `yaml:"features"`
|
||||
Path PathConfiguration `yaml:"path"`
|
||||
@@ -18,6 +19,10 @@ type PathConfiguration struct {
|
||||
Storage string `yaml:"storage"`
|
||||
}
|
||||
|
||||
type ServerConfiguration struct {
|
||||
Port int `yaml:"port"`
|
||||
}
|
||||
|
||||
type DatabaseConfiguration struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
@@ -55,3 +60,7 @@ func Features() *FeaturesConfiguration {
|
||||
func Path() *PathConfiguration {
|
||||
return ¤tConfig.Path
|
||||
}
|
||||
|
||||
func Server() *ServerConfiguration {
|
||||
return ¤tConfig.Server
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
@@ -175,31 +173,18 @@ func UploadSave(file multipart.File, game *Game) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateGameRevision(game *Game) 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)
|
||||
func UpdateGameRevision(game *Game, hash string) error {
|
||||
game.Revision += 1
|
||||
if game.Hash == nil {
|
||||
game.Hash = new(string)
|
||||
}
|
||||
*game.Hash = hex.EncodeToString(sum)
|
||||
*game.Hash = hash
|
||||
game.Available = true
|
||||
if game.LastUpdate == nil {
|
||||
game.LastUpdate = new(time.Time)
|
||||
}
|
||||
*game.LastUpdate = time.Now()
|
||||
err = db.Save(game).Error
|
||||
err := db.Save(game).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
108
db_dump.sql
108
db_dump.sql
@@ -1,54 +1,54 @@
|
||||
-- --------------------------------------------------------
|
||||
-- Host: 127.0.0.1
|
||||
-- Server version: 8.0.27 - MySQL Community Server - GPL
|
||||
-- Server OS: Win64
|
||||
-- HeidiSQL Version: 12.0.0.6468
|
||||
-- --------------------------------------------------------
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET NAMES utf8 */;
|
||||
/*!50503 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
|
||||
-- Dumping database structure for osc
|
||||
DROP DATABASE IF EXISTS `osc`;
|
||||
CREATE DATABASE IF NOT EXISTS `osc` /*!40100 DEFAULT CHARACTER SET utf8 */ /*!80016 DEFAULT ENCRYPTION='N' */;
|
||||
USE `osc`;
|
||||
|
||||
-- Dumping structure for table osc.games
|
||||
DROP TABLE IF EXISTS `games`;
|
||||
CREATE TABLE IF NOT EXISTS `games` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL DEFAULT '0',
|
||||
`revision` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`path_storage` text NOT NULL,
|
||||
`hash` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
|
||||
`last_update` datetime DEFAULT NULL,
|
||||
`user_id` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`available` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
-- Data exporting was unselected.
|
||||
|
||||
-- Dumping structure for table osc.users
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(50) NOT NULL,
|
||||
`password` binary(60) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
-- Data exporting was unselected.
|
||||
|
||||
/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
|
||||
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;
|
||||
-- --------------------------------------------------------
|
||||
-- Host: 127.0.0.1
|
||||
-- Server version: 8.0.27 - MySQL Community Server - GPL
|
||||
-- Server OS: Win64
|
||||
-- HeidiSQL Version: 12.0.0.6468
|
||||
-- --------------------------------------------------------
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET NAMES utf8 */;
|
||||
/*!50503 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
|
||||
-- Dumping database structure for osc
|
||||
DROP DATABASE IF EXISTS `osc`;
|
||||
CREATE DATABASE IF NOT EXISTS `osc` /*!40100 DEFAULT CHARACTER SET utf8 */ /*!80016 DEFAULT ENCRYPTION='N' */;
|
||||
USE `osc`;
|
||||
|
||||
-- Dumping structure for table osc.games
|
||||
DROP TABLE IF EXISTS `games`;
|
||||
CREATE TABLE IF NOT EXISTS `games` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL DEFAULT '0',
|
||||
`revision` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`path_storage` text NOT NULL,
|
||||
`hash` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
|
||||
`last_update` datetime DEFAULT NULL,
|
||||
`user_id` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`available` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
-- Data exporting was unselected.
|
||||
|
||||
-- Dumping structure for table osc.users
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(50) NOT NULL,
|
||||
`password` binary(60) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
-- Data exporting was unselected.
|
||||
|
||||
/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
|
||||
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type NewGameInfo struct {
|
||||
@@ -26,6 +27,7 @@ type LockError struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// CreateGame create a game entry to the database
|
||||
func CreateGame(w http.ResponseWriter, r *http.Request) {
|
||||
userId, err := userIdFromContext(r.Context())
|
||||
if err != nil {
|
||||
@@ -55,6 +57,7 @@ func CreateGame(w http.ResponseWriter, r *http.Request) {
|
||||
ok(game, w, r)
|
||||
}
|
||||
|
||||
// GameInfoByID get the game save information from the database
|
||||
func GameInfoByID(w http.ResponseWriter, r *http.Request) {
|
||||
userId, err := userIdFromContext(r.Context())
|
||||
if err != nil {
|
||||
@@ -78,6 +81,24 @@ func GameInfoByID(w http.ResponseWriter, r *http.Request) {
|
||||
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) {
|
||||
userId, err := userIdFromContext(r.Context())
|
||||
if err != nil {
|
||||
@@ -106,6 +127,7 @@ func AskForUpload(w http.ResponseWriter, r *http.Request) {
|
||||
ok(token, w, r)
|
||||
}
|
||||
|
||||
// UploadSave upload the game save archive to the storage folder
|
||||
func UploadSave(w http.ResponseWriter, r *http.Request) {
|
||||
userId, err := userIdFromContext(r.Context())
|
||||
if err != nil {
|
||||
@@ -120,6 +142,11 @@ func UploadSave(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
internalServerError(w, r)
|
||||
@@ -139,7 +166,7 @@ func UploadSave(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
err = database.UpdateGameRevision(game)
|
||||
err = database.UpdateGameRevision(game, hash)
|
||||
if err != nil {
|
||||
internalServerError(w, r)
|
||||
log.Println(err)
|
||||
@@ -153,6 +180,7 @@ func UploadSave(w http.ResponseWriter, r *http.Request) {
|
||||
ok(payload, w, r)
|
||||
}
|
||||
|
||||
// Download send the game save archive to the client
|
||||
func Download(w http.ResponseWriter, r *http.Request) {
|
||||
userId, err := userIdFromContext(r.Context())
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"log"
|
||||
@@ -37,6 +38,7 @@ func Serve() {
|
||||
r.Route("/game", func(secureRouter chi.Router) {
|
||||
secureRouter.Use(authMiddleware)
|
||||
secureRouter.Post("/create", CreateGame)
|
||||
secureRouter.Get("/all", AllGamesInformation)
|
||||
secureRouter.Get("/info/{id}", GameInfoByID)
|
||||
secureRouter.Post("/upload/init", AskForUpload)
|
||||
secureRouter.Group(func(uploadRouter chi.Router) {
|
||||
@@ -49,7 +51,7 @@ func Serve() {
|
||||
})
|
||||
})
|
||||
log.Println("Server is listening...")
|
||||
err := http.ListenAndServe(":8080", router)
|
||||
err := http.ListenAndServe(fmt.Sprintf(":%d", config.Server().Port), router)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user