Bugfixes. Optimizations/refactor. Add redis for player-cache. Add docker files. Replace sqlite dep. Single-Calc for existing players. Game-Metrics in JSON.
This commit is contained in:
@@ -3,37 +3,29 @@ package controllers
|
||||
import (
|
||||
"InfantrySkillCalculator/models"
|
||||
"InfantrySkillCalculator/utils"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
"internal/cache"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AddCacheInput struct {
|
||||
PlayerID uint `json:"player_id" binding:"required"`
|
||||
CacheDate time.Time `json:"date" binding:"required"`
|
||||
Score float32 `json:"score" gorm:"default:-1.0"`
|
||||
Game string `json:"game" binding:"required"`
|
||||
PlayerID uint `json:"player_id" binding:"required"`
|
||||
Score float32 `json:"score" gorm:"default:-1.0"`
|
||||
GameTag string `json:"game_tag" binding:"required"`
|
||||
}
|
||||
|
||||
type UpdateCacheInput struct {
|
||||
CacheDate time.Time `json:"date" binding:"required"`
|
||||
Score float32 `json:"score" gorm:"default:-1.0"`
|
||||
Score float32 `json:"score" gorm:"default:-1.0"`
|
||||
}
|
||||
|
||||
var ctx = context.Background()
|
||||
|
||||
// GetCacheByPlayerID GET /cache/:player_id?game_id=TAG
|
||||
// GetCacheByPlayerID GET /cache/:player_id?game_tag=TAG
|
||||
func GetCacheByPlayerID(c *gin.Context) {
|
||||
playerId := utils.StringToUint(c.Param("player_id"))
|
||||
gameId := utils.StringToUint(c.Request.URL.Query().Get("game_id"))
|
||||
gameTag := c.Request.URL.Query().Get("game_tag")
|
||||
|
||||
val, err := GetCacheByPlayerIDGorm(playerId, gameId)
|
||||
val, err := cache.GetScore(playerId, gameTag)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
|
||||
} else {
|
||||
@@ -41,19 +33,6 @@ func GetCacheByPlayerID(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func GetCacheByPlayerIDGorm(playerId uint, gameId uint) (float32, error) {
|
||||
key := fmt.Sprintf("player:%d:game:%d", playerId, gameId)
|
||||
|
||||
val, err := models.Cache.Get(ctx, key).Result()
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return -1.0, nil // cache miss
|
||||
} else if err != nil {
|
||||
return -1.0, err // cache error
|
||||
} else {
|
||||
return utils.StringToFloat(val), nil // cache hit
|
||||
}
|
||||
}
|
||||
|
||||
// AddCache POST /cache
|
||||
func AddCache(c *gin.Context) {
|
||||
var input AddCacheInput
|
||||
@@ -63,69 +42,84 @@ func AddCache(c *gin.Context) {
|
||||
}
|
||||
|
||||
var game models.Game
|
||||
if err := FindGameByTag(&game, input.Game).Error; err != nil {
|
||||
if err := FindGameByTag(&game, input.GameTag).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Game not found!"})
|
||||
return
|
||||
}
|
||||
|
||||
cache := models.PlayerCache{CacheDate: input.CacheDate, PlayerID: input.PlayerID, Score: input.Score, Game: input.Game}
|
||||
err := cache.SetScore(input.PlayerID, input.GameTag, input.Score)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Cache update failed! Error: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, cache)
|
||||
c.JSON(http.StatusOK, nil)
|
||||
}
|
||||
|
||||
// UpdateCacheByPlayerID PATCH /cache/:id?game=TAG
|
||||
func UpdateCacheByPlayerID(c *gin.Context) {
|
||||
var cache models.PlayerCache
|
||||
if err := FindCacheGin(&cache, c).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
|
||||
return
|
||||
playerID := utils.StringToUint(c.Param("id"))
|
||||
gameTag := c.Request.URL.Query().Get("game")
|
||||
score := utils.StringToFloat(c.PostForm("score"))
|
||||
|
||||
err := cache.SetScore(playerID, gameTag, score)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Cache update failed! Error: " + err.Error()})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, nil)
|
||||
}
|
||||
|
||||
var input UpdateCacheInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
models.DB.Model(&cache).Updates(map[string]interface{}{
|
||||
"CacheDate": input.CacheDate,
|
||||
"Score": input.Score,
|
||||
})
|
||||
|
||||
c.JSON(http.StatusOK, cache)
|
||||
}
|
||||
|
||||
// DeleteCacheByPlayerID DELETE /cache/:id?game=TAG
|
||||
func DeleteCacheByPlayerID(c *gin.Context) {
|
||||
var cache models.PlayerCache
|
||||
if err := FindCacheGin(&cache, c).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
|
||||
return
|
||||
playerID := utils.StringToUint(c.Param("id"))
|
||||
gameTag := c.Request.URL.Query().Get("game")
|
||||
|
||||
if err := cache.DeleteScore(playerID, gameTag); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, nil)
|
||||
}
|
||||
|
||||
models.DB.Delete(&cache)
|
||||
|
||||
c.JSON(http.StatusOK, true)
|
||||
}
|
||||
|
||||
// DeleteAllCaches DELETE /cache
|
||||
func DeleteAllCaches(c *gin.Context) {
|
||||
var caches []models.PlayerCache
|
||||
if err := cache.PurgeCache(); err != nil {
|
||||
c.String(http.StatusBadRequest, err.Error())
|
||||
} else {
|
||||
c.String(http.StatusOK, "Purged all caches!")
|
||||
}
|
||||
}
|
||||
|
||||
// GetScoreByPlayerID GET /score/:player_id?game_tag=TAG
|
||||
func GetScoreByPlayerID(c *gin.Context) {
|
||||
var player models.Player
|
||||
var gameTag = c.Request.URL.Query().Get("game_tag")
|
||||
var playerId = utils.StringToUint(c.Param("player_id"))
|
||||
if err := models.DB.
|
||||
Session(&gorm.Session{AllowGlobalUpdate: true}).
|
||||
Clauses(clause.Returning{}).
|
||||
Delete(&caches).Error; err != nil {
|
||||
c.String(http.StatusBadRequest, "Purge failed! Error: "+err.Error())
|
||||
Model(&models.Player{}).
|
||||
Where("id = ?", playerId).
|
||||
First(&player).Error; err != nil {
|
||||
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Player not found!"})
|
||||
return
|
||||
}
|
||||
|
||||
c.String(http.StatusOK, "Purged "+utils.UintToString(uint(len(caches)))+" caches!")
|
||||
}
|
||||
score, err := cache.GetScore(player.ID, gameTag)
|
||||
if err != nil || score == -1 {
|
||||
score = utils.CalcPlayerScore(player.Name, gameTag)
|
||||
if score == score && score != -1 { // not NaN
|
||||
if err := cache.SetScore(player.ID, gameTag, score); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func FindCacheGin(out interface{}, c *gin.Context) *gorm.DB {
|
||||
return FindCache(out, utils.StringToUint(c.Param("id")), c.Request.URL.Query().Get("game"))
|
||||
}
|
||||
|
||||
func FindCache(out interface{}, id uint, game string) *gorm.DB {
|
||||
return models.DB.Where("player_id = ?", id).Where("game = ?", game).First(out)
|
||||
if score != score || score == -1 { // NaN
|
||||
c.String(http.StatusOK, "<i class=\"bi bi-person-x-fill me-2 text-danger fs-5\" style=\"margin-left: 0.69rem;\"></i>")
|
||||
} else if score != -1 {
|
||||
c.String(http.StatusOK, fmt.Sprintf("%.2f", score))
|
||||
} else {
|
||||
c.JSON(http.StatusBadRequest, "Invalid request!")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user