4 Commits

Author SHA1 Message Date
a0f65394d4 wip: fields
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is failing
2025-07-25 22:28:18 -07:00
7a37224487 connect to maps grpc
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2025-07-25 20:45:40 -07:00
b98b184a32 switch maps queries to maps_extended
times continues to use the embedded map
2025-07-25 20:38:50 -07:00
dace105a9a update go-grpc for maps_extended 2025-07-25 20:31:56 -07:00
15 changed files with 115 additions and 71 deletions

View File

@@ -61,9 +61,4 @@ steps:
when:
branch:
- master
- staging
---
kind: signature
hmac: 7655eb6dead73d2ad977685120cee8562931036bb5d7fa59d30d5917840c4a22
...
- staging

View File

@@ -1,5 +1,6 @@
clean:
rm -rf build
rm -rf web/dist
test:
go fmt ./...

View File

@@ -301,8 +301,7 @@ const docTemplate = `{
{
"type": "array",
"items": {
"type": "integer",
"format": "int64"
"type": "integer"
},
"collectionFormat": "csv",
"description": "Comma-separated array of time IDs (25 Limit)",
@@ -632,6 +631,12 @@ const docTemplate = `{
"Map": {
"type": "object",
"properties": {
"creator": {
"type": "string"
},
"date": {
"type": "string"
},
"display_name": {
"type": "string"
},
@@ -640,9 +645,6 @@ const docTemplate = `{
},
"id": {
"type": "integer"
},
"thumbnail": {
"type": "integer"
}
}
},

View File

@@ -294,8 +294,7 @@
{
"type": "array",
"items": {
"type": "integer",
"format": "int64"
"type": "integer"
},
"collectionFormat": "csv",
"description": "Comma-separated array of time IDs (25 Limit)",
@@ -625,6 +624,12 @@
"Map": {
"type": "object",
"properties": {
"creator": {
"type": "string"
},
"date": {
"type": "string"
},
"display_name": {
"type": "string"
},
@@ -633,9 +638,6 @@
},
"id": {
"type": "integer"
},
"thumbnail": {
"type": "integer"
}
}
},

View File

@@ -7,14 +7,16 @@ definitions:
type: object
Map:
properties:
creator:
type: string
date:
type: string
display_name:
type: string
game_id:
type: integer
id:
type: integer
thumbnail:
type: integer
type: object
PagedResponse-Map:
properties:
@@ -416,7 +418,6 @@ paths:
description: Comma-separated array of time IDs (25 Limit)
in: query
items:
format: int64
type: integer
name: ids
required: true

2
go.mod
View File

@@ -4,7 +4,7 @@ go 1.24.0
require (
git.itzana.me/StrafesNET/dev-service v0.0.0-20250628022558-4cf59e46f9f1
git.itzana.me/strafesnet/go-grpc v0.0.0-20250807005013-301d35b914ef
git.itzana.me/strafesnet/go-grpc v0.0.0-20250724030029-845bea991815
github.com/gin-gonic/gin v1.10.1
github.com/sirupsen/logrus v1.9.3
github.com/swaggo/files v1.0.1

4
go.sum
View File

@@ -2,8 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
git.itzana.me/StrafesNET/dev-service v0.0.0-20250628022558-4cf59e46f9f1 h1:Ndpa4d93gCQrW5pm64u9IRaDJTfu7fKfLqm8ctzML1o=
git.itzana.me/StrafesNET/dev-service v0.0.0-20250628022558-4cf59e46f9f1/go.mod h1:KJal0K++M6HEzSry6JJ2iDPZtOQn5zSstNlDbU3X4Jg=
git.itzana.me/strafesnet/go-grpc v0.0.0-20250807005013-301d35b914ef h1:SJi4V4+xzScFnbMRN1gkZxcqR1xKfiT7CaXanLltEzw=
git.itzana.me/strafesnet/go-grpc v0.0.0-20250807005013-301d35b914ef/go.mod h1:X7XTRUScRkBWq8q8bplbeso105RPDlnY7J6Wy1IwBMs=
git.itzana.me/strafesnet/go-grpc v0.0.0-20250724030029-845bea991815 h1:hkuOnehphRXUq/2z2UYgoqTq5MJj1GsWfshyc7bXda8=
git.itzana.me/strafesnet/go-grpc v0.0.0-20250724030029-845bea991815/go.mod h1:X7XTRUScRkBWq8q8bplbeso105RPDlnY7J6Wy1IwBMs=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=

View File

@@ -2,17 +2,15 @@ package dto
import (
"git.itzana.me/strafesnet/go-grpc/maps"
"time"
)
type MapFilter struct {
GameID *int32 `json:"game_id" form:"game_id"`
} // @name MapFilter
type Map struct {
ID int64 `json:"id"`
DisplayName string `json:"display_name"`
Creator string `json:"creator"`
GameID int32 `json:"game_id"`
Thumbnail uint64 `json:"thumbnail"`
Date time.Time `json:"date"`
} // @name Map
// FromGRPC converts a maps.MapResponse protobuf message to a Map domain object
@@ -23,8 +21,9 @@ func (m *Map) FromGRPC(resp *maps.MapResponse) *Map {
m.ID = resp.ID
m.DisplayName = resp.DisplayName
m.Creator = resp.Creator
m.Date = time.Unix(resp.Date, 0)
m.GameID = resp.GameID
m.Thumbnail = resp.Thumbnail
return m
}

View File

@@ -0,0 +1,40 @@
package dto
import (
"git.itzana.me/strafesnet/go-grpc/maps_extended"
"time"
)
type MapExtendedFilter struct {
GameID *uint32 `json:"game_id" form:"game_id"`
} // @name MapFilter
type MapExtended struct {
ID int64 `json:"id"`
DisplayName string `json:"display_name"`
Creator string `json:"creator"`
GameID uint32 `json:"game_id"`
Date time.Time `json:"date"`
CreatedAt time.Time `json:created_at`
UpdatedAt time.Time `json:updated_at`
Submitter uint64 `json:submitter`
Thumbnail uint64 `json:thumbnail`
AssetVersion uint64 `json:asset_version`
LoadCount uint32 `json:load_count`
Modes uint32 `json:modes`
} // @name Map
// FromGRPC converts a maps.MapResponse protobuf message to a Map domain object
func (m *MapExtended) FromGRPC(resp *maps_extended.MapResponse) *MapExtended {
if resp == nil {
return nil
}
m.ID = resp.ID
m.DisplayName = resp.DisplayName
m.Creator = resp.Creator
m.Date = time.Unix(resp.Date, 0)
m.GameID = resp.GameID
return m
}

View File

@@ -14,11 +14,10 @@ type UserRankFilter struct {
} // @name UserRankFilter
type User struct {
ID int64 `json:"id"`
Username string `json:"username"`
StateID int32 `json:"state_id"`
Muted bool `json:"muted"`
PlayerData map[string]any `json:"data"`
ID int64 `json:"id"`
Username string `json:"username"`
StateID int32 `json:"state_id"`
Muted bool `json:"muted"`
} // @name User
// FromGRPC converts a users.UserResponse protobuf message to a User domain object

View File

@@ -14,6 +14,7 @@ const (
// Handler is a base handler that provides common functionality for all HTTP handlers.
type Handler struct {
dataClient *grpc.ClientConn
mapsClient *grpc.ClientConn
}
// HandlerOption defines a functional option for configuring a Handler
@@ -26,6 +27,13 @@ func WithDataClient(dataClient *grpc.ClientConn) HandlerOption {
}
}
// WithMapsClient sets the maps client for the Handler
func WithMapsClient(mapsClient *grpc.ClientConn) HandlerOption {
return func(h *Handler) {
h.mapsClient = mapsClient
}
}
// NewHandler creates a new Handler with the provided options.
// It requires both a datastore and an authentication service to function properly.
func NewHandler(options ...HandlerOption) (*Handler, error) {

View File

@@ -1,7 +1,7 @@
package handlers
import (
"git.itzana.me/strafesnet/go-grpc/maps"
"git.itzana.me/strafesnet/go-grpc/maps_extended"
"git.itzana.me/strafesnet/public-api/pkg/api/dto"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
@@ -49,7 +49,7 @@ func (h *MapHandler) Get(ctx *gin.Context) {
}
// Call the gRPC service
mapData, err := maps.NewMapsServiceClient(h.dataClient).Get(ctx, &maps.IdMessage{
mapData, err := maps_extended.NewMapsServiceClient(h.mapsClient).Get(ctx, &maps_extended.MapId{
ID: mapID,
})
if err != nil {
@@ -72,11 +72,11 @@ func (h *MapHandler) Get(ctx *gin.Context) {
}
// Convert gRPC MapResponse object to dto.Map object
var mapDto dto.Map
var mapDto dto.MapExtended
result := mapDto.FromGRPC(mapData)
// Return the map data
ctx.JSON(http.StatusOK, dto.Response[dto.Map]{
ctx.JSON(http.StatusOK, dto.Response[dto.MapExtended]{
Data: *result,
})
}
@@ -107,7 +107,7 @@ func (h *MapHandler) List(ctx *gin.Context) {
}
// Get list filter
var filter dto.MapFilter
var filter dto.MapExtendedFilter
if err := ctx.ShouldBindQuery(&filter); err != nil {
ctx.JSON(http.StatusBadRequest, dto.Error{
Error: err.Error(),
@@ -116,13 +116,13 @@ func (h *MapHandler) List(ctx *gin.Context) {
}
// Call the gRPC service
mapList, err := maps.NewMapsServiceClient(h.dataClient).List(ctx, &maps.ListRequest{
Filter: &maps.MapFilter{
mapList, err := maps_extended.NewMapsServiceClient(h.mapsClient).List(ctx, &maps_extended.ListRequest{
Filter: &maps_extended.MapFilter{
GameID: filter.GameID,
},
Page: &maps.Pagination{
Size: int32(query.PageSize),
Number: int32(query.PageNumber),
Page: &maps_extended.Pagination{
Size: uint32(query.PageSize),
Number: uint32(query.PageNumber),
},
})
if err != nil {
@@ -136,14 +136,14 @@ func (h *MapHandler) List(ctx *gin.Context) {
}
// Convert gRPC MapResponse objects to dto.Map objects
dtoMaps := make([]dto.Map, len(mapList.Maps))
dtoMaps := make([]dto.MapExtended, len(mapList.Maps))
for i, m := range mapList.Maps {
var mapDto dto.Map
var mapDto dto.MapExtended
dtoMaps[i] = *mapDto.FromGRPC(m)
}
// Return the paged response
ctx.JSON(http.StatusOK, dto.PagedResponse[dto.Map]{
ctx.JSON(http.StatusOK, dto.PagedResponse[dto.MapExtended]{
Data: dtoMaps,
Pagination: dto.Pagination{
Page: query.PageNumber,

View File

@@ -1,10 +1,6 @@
package handlers
import (
"net/http"
"strconv"
"git.itzana.me/strafesnet/go-grpc/datastore"
"git.itzana.me/strafesnet/go-grpc/ranks"
"git.itzana.me/strafesnet/go-grpc/users"
"git.itzana.me/strafesnet/public-api/pkg/api/dto"
@@ -12,6 +8,8 @@ import (
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"net/http"
"strconv"
)
// UserHandler handles HTTP requests related to users.
@@ -74,26 +72,9 @@ func (h *UserHandler) Get(ctx *gin.Context) {
return
}
dataStoreData, err := datastore.NewDatastoreServiceClient(h.dataClient).Get(ctx, &datastore.KeyMessage{
Key: "playerdata-" + strconv.FormatInt(userID, 10),
})
if err != nil {
statusCode := http.StatusInternalServerError
errorMessage := "Failed to get playerdata from data store"
ctx.JSON(statusCode, dto.Error{
Error: errorMessage,
})
log.WithError(err).Error(
"Failed to get playerdata data store",
)
return
}
// Convert gRPC UserResponse object to dto.UserData object
var user dto.User
result := user.FromGRPC(userData)
result.PlayerData = dataStoreData.Data.AsMap()
// Return the user data
ctx.JSON(http.StatusOK, dto.Response[dto.User]{

View File

@@ -25,6 +25,7 @@ type RouterConfig struct {
port int
devClient *grpc.ClientConn
dataClient *grpc.ClientConn
mapsClient *grpc.ClientConn
context *cli.Context
shutdownTimeout time.Duration
}
@@ -57,6 +58,13 @@ func WithDataClient(conn *grpc.ClientConn) Option {
}
}
// WithMapsClient sets the maps gRPC client
func WithMapsClient(conn *grpc.ClientConn) Option {
return func(cfg *RouterConfig) {
cfg.mapsClient = conn
}
}
// WithShutdownTimeout sets the graceful shutdown timeout
func WithShutdownTimeout(timeout time.Duration) Option {
return func(cfg *RouterConfig) {
@@ -72,6 +80,7 @@ func setupRoutes(cfg *RouterConfig) (*gin.Engine, error) {
handlerOptions := []handlers.HandlerOption{
handlers.WithDataClient(cfg.dataClient),
handlers.WithMapsClient(cfg.mapsClient),
}
// Times handler

View File

@@ -32,10 +32,10 @@ func NewApiCommand() *cli.Command {
Value: "data-service:9000",
},
&cli.StringFlag{
Name: "datastore-rpc-host",
Usage: "Host of datastore rpc",
EnvVars: []string{"DATASTORE_RPC_HOST"},
Value: "datastore-service:9000",
Name: "maps-rpc-host",
Usage: "Host of maps rpc",
EnvVars: []string{"MAPS_RPC_HOST"},
Value: "maptest-api:8081",
},
},
}
@@ -54,10 +54,17 @@ func runAPI(ctx *cli.Context) error {
return err
}
// Maps service client
mapsConn, err := grpc.Dial(ctx.String("maps-rpc-host"), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return err
}
return api.NewRouter(
api.WithContext(ctx),
api.WithPort(ctx.Int("port")),
api.WithDevClient(devConn),
api.WithDataClient(dataConn),
api.WithMapsClient(mapsConn),
)
}