游戏 API
权限分两条线,互不包含:游戏本体(新增/编辑/删除游戏)走 games:write;游戏环境(增删改环境)走 games:manage。读路径 games:read / games:manage / games:write 皆可。游戏管理独立页面在 /system/games,环境维护在 /system/environments。
1. "获取游戏列表"
- route definition
- Url: /api/v1/games
- Method: GET
- Request:
GamesListRequest - Response:
GamesListResponse
- request definition
go
type GamesListRequest struct {
Page int `form:"page,optional"`
PageSize int `form:"pageSize,optional"`
Status string `form:"status,optional"`
}- response definition
go
type GamesListResponse struct {
// 响应为裸 payload(去掉 envelope 的 code/message 两行)
Data GamesData `json:"data,omitempty"`
}
type GamesData struct {
Games []GameInfo `json:"games"`
Total int `json:"total,optional"`
}2. "创建游戏"
- route definition
- Url: /api/v1/games
- Method: POST
- Request:
GameCreateRequest - Response:
GameCreateResponse
- request definition
go
type GameCreateRequest struct {
Name string `json:"name"`
AliasName string `json:"aliasName"`
Icon string `json:"icon"`
Description string `json:"description"`
Config string `json:"config"`
}- 权限:
admin:all或games:write(games:manage不含游戏创建)。 name仅限字母、数字和_ - @,重名 409;aliasName(显示名称)留空时回填name(alias_name 唯一索引不接受多个空串)。icon为图片地址,留空 = 渲染默认骰子占位图。
- response definition
go
// 实际响应为裸 payload(业务 DTO 直接 JSON 序列化),无 code/message envelope。
// 错误统一 { "error", "message", "details" }(见 rest.md)。3. "获取游戏详情"
- route definition
- Url: /api/v1/games/:id
- Method: GET
- Request:
GameDetailRequest - Response:
GameDetailResponse
- request definition
go
type GameDetailRequest struct {
ID string `path:"id"`
}- response definition
go
type GameDetailResponse struct {
// 响应为裸 payload(去掉 envelope 的 code/message 两行)
Data GameInfo `json:"data,omitempty"`
}
type GameInfo struct {
ID uint `json:"id"`
Name string `json:"name"`
Icon string `json:"icon,optional"`
Description string `json:"description,optional"`
Enabled bool `json:"enabled"`
AliasName string `json:"aliasName,optional"`
Homepage string `json:"homepage,optional"`
Status string `json:"status"`
GameType string `json:"gameType,optional"`
GenreCode string `json:"genreCode,optional"`
Color string `json:"color,optional"`
Envs []GameEnvItem `json:"envs,optional"`
CreatedAt string `json:"createdAt,optional"`
UpdatedAt string `json:"updatedAt,optional"`
}4. "更新游戏"
- route definition
- Url: /api/v1/games/:id
- Method: PUT
- Request:
GameUpdateRequest - Response:
GameUpdateResponse
- request definition
go
type GameUpdateRequest struct {
ID string `uri:"id"`
Name string `json:"name"`
AliasName string `json:"aliasName"`
// Icon 指针语义:字段出现即更新(空串 = 清空,回落默认骰子图标),缺省 = 保持。
Icon *string `json:"icon"`
Description string `json:"description"`
Config string `json:"config"`
Status string `json:"status"`
}- 权限:
admin:all或games:write。 name/aliasName/description/config/status提供非空值才更新,全部为空 400「请提供需要更新的字段」;icon是指针,显式提交即生效(含空串清除)。
- response definition
go
type GameUpdateResponse struct {
// 响应为裸 payload(去掉 envelope 的 code/message 两行)
Data GameInfo `json:"data,omitempty"`
}
type GameInfo struct {
ID uint `json:"id"`
Name string `json:"name"`
Icon string `json:"icon,optional"`
Description string `json:"description,optional"`
Enabled bool `json:"enabled"`
AliasName string `json:"aliasName,optional"`
Homepage string `json:"homepage,optional"`
Status string `json:"status"`
GameType string `json:"gameType,optional"`
GenreCode string `json:"genreCode,optional"`
Color string `json:"color,optional"`
Envs []GameEnvItem `json:"envs,optional"`
CreatedAt string `json:"createdAt,optional"`
UpdatedAt string `json:"updatedAt,optional"`
}5. "删除游戏"
- route definition
- Url: /api/v1/games/:id
- Method: DELETE
- Request:
GameDeleteRequest - Response:
GameDeleteResponse
- request definition
go
type GameDeleteRequest struct {
ID string `path:"id"`
}- response definition
go
// 实际响应为裸 payload(业务 DTO 直接 JSON 序列化),无 code/message envelope。
// 错误统一 { "error", "message", "details" }(见 rest.md)。- 权限:
admin:all或games:write(games:manage不能删游戏)。 - 删除门禁:游戏的
game_envs绑定表或 Envs 元数据任一非空即 409conflict「请先删除该游戏的全部环境,再删除游戏」——先到环境页清空全部环境才能删游戏。
6. "获取游戏环境列表"
- route definition
- Url: /api/v1/games/:id/envs
- Method: GET
- Request:
GameEnvsListRequest - Response:
GameEnvsListResponse
- request definition
go
type GameEnvsListRequest struct {
ID string `path:"id"`
}- response definition
go
type GameEnvsListResponse struct {
// 响应为裸 payload(去掉 envelope 的 code/message 两行)
Data GameEnvsData `json:"data,omitempty"`
}
type GameEnvsData struct {
Envs []GameEnvItem `json:"envs"`
}7. "添加游戏环境"
- route definition
- Url: /api/v1/games/:id/envs
- Method: POST
- Request:
GameEnvAddRequest - Response:
GameEnvAddResponse
- request definition
go
type GameEnvAddRequest struct {
ID string `path:"id"`
Name string `json:"name"`
Type string `json:"type,optional"`
}- response definition
go
// 实际响应为裸 payload(业务 DTO 直接 JSON 序列化),无 code/message envelope。
// 错误统一 { "error", "message", "details" }(见 rest.md)。8. "更新游戏环境"
- route definition
- Url: /api/v1/games/:id/envs/:envId
- Method: PUT
- Request:
GameEnvUpdateRequest - Response:
GameEnvUpdateResponse
- request definition
go
type GameEnvUpdateRequest struct {
ID string `path:"id"`
EnvID string `path:"envId"`
Name string `json:"name,optional"`
Type string `json:"type,optional"`
}- response definition
go
// 实际响应为裸 payload(业务 DTO 直接 JSON 序列化),无 code/message envelope。
// 错误统一 { "error", "message", "details" }(见 rest.md)。9. "删除游戏环境"
- route definition
- Url: /api/v1/games/:id/envs/:envId
- Method: DELETE
- Request:
GameEnvDeleteRequest - Response:
GameEnvDeleteResponse
- request definition
go
type GameEnvDeleteRequest struct {
ID string `path:"id"`
EnvID string `path:"envId"`
}- response definition
go
// 实际响应为裸 payload(业务 DTO 直接 JSON 序列化),无 code/message envelope。
// 错误统一 { "error", "message", "details" }(见 rest.md)。10. "上传游戏图标"
- route definition
- Url: /api/v1/games/icons
- Method: POST(multipart/form-data,字段名
file) - Request: multipart 文件
- Response:
GameIconUploadResponse
- request definition
go
// internal/api/game/icon_upload.go
// 大小上限 IconMaxBytes = 2MB;类型按文件头魔数嗅探(png/jpg/webp/svg),
// 不信任扩展名与 Content-Type。- response definition
go
type GameIconUploadResponse struct {
Key string `json:"key"` // 对象存储裸 key:icons/games/<sha1 前 16 hex>.<ext>
URL string `json:"url"` // 可直接回填 game.icon 的访问地址
}- 权限:
admin:all或games:write。 - 覆盖策略(内容寻址):key 由内容 sha1 派生,同内容重复上传得到同一 key(幂等覆盖),不同内容必不同 key——不存在「A 游戏同名图标覆盖 B 游戏」互踩;旧图标成为孤儿文件(KB 级,不清理)。
- 仅 file 存储驱动:图标 URL 必须长期稳定可直载,S3/OSS/COS 的 SignedURL 带过期时间存库即死链;对象存储部署请直接在图标字段填 CDN/外部 URL。
- 静态暴露:file 驱动下
GET /uploads/icons/*(免认证白名单,<img>直载不带 Authorization 头);仅暴露icons/子树,通用存储 API 写入的私有对象不外泄。SVG 可内嵌脚本,静态路由附加Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'+X-Content-Type-Options: nosniff+ immutable 缓存兜底。
