feat: DB DI 전환 + download 하위 호환성 + race condition 수정
- middleware(Auth, Idempotency)를 클로저 팩토리 패턴으로 DI 전환 - database.DB/RDB 전역 변수 제거, ConnectMySQL/Redis 값 반환으로 변경 - download API X-API-Version 헤더 + 하위 호환성 규칙 문서화 - SaveGameData PlayTimeDelta 원자적 UPDATE (race condition 해소) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,19 @@ import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// Download API 하위 호환성 규칙:
|
||||
// - 기존 필드 삭제 금지 (런처 바이너리가 필드에 의존)
|
||||
// - 기존 필드 타입 변경 금지
|
||||
// - 기존 필드명(JSON key) 변경 금지
|
||||
// - 신규 필드 추가만 허용 (기존 런처는 unknown 필드를 무시)
|
||||
// - 스키마 변경 시 downloadAPIVersion 값을 올릴 것
|
||||
//
|
||||
// 현재 /api/download/info 응답 필드 (v1):
|
||||
// id, createdAt, updatedAt, url, version, fileName, fileSize,
|
||||
// fileHash, launcherUrl, launcherSize, launcherHash
|
||||
|
||||
const downloadAPIVersion = "1"
|
||||
|
||||
type Handler struct {
|
||||
svc *Service
|
||||
baseURL string
|
||||
@@ -34,6 +47,7 @@ func (h *Handler) GetInfo(c *fiber.Ctx) error {
|
||||
if err != nil {
|
||||
return apperror.NotFound("다운로드 정보가 없습니다")
|
||||
}
|
||||
c.Set("X-API-Version", downloadAPIVersion)
|
||||
return c.JSON(info)
|
||||
}
|
||||
|
||||
@@ -89,6 +103,7 @@ func (h *Handler) ServeFile(c *fiber.Ctx) error {
|
||||
if info != nil && info.FileName != "" {
|
||||
filename = info.FileName
|
||||
}
|
||||
c.Set("X-API-Version", downloadAPIVersion)
|
||||
c.Set("Content-Disposition", mime.FormatMediaType("attachment", map[string]string{"filename": filename}))
|
||||
return c.SendFile(path)
|
||||
}
|
||||
@@ -128,6 +143,7 @@ func (h *Handler) ServeLauncher(c *fiber.Ctx) error {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return apperror.NotFound("파일이 없습니다")
|
||||
}
|
||||
c.Set("X-API-Version", downloadAPIVersion)
|
||||
c.Set("Content-Disposition", `attachment; filename="launcher.exe"`)
|
||||
return c.SendFile(path)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user