Compare commits
4 Commits
b006fe77c2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7acd72c74e | |||
| b1e89dca1c | |||
| 510f731a10 | |||
| ac6827aae5 |
@@ -111,9 +111,10 @@ func (h *Handler) Login(c *fiber.Ctx) error {
|
|||||||
MaxAge: 7 * 24 * 60 * 60, // 7 days
|
MaxAge: 7 * 24 * 60 * 60, // 7 days
|
||||||
})
|
})
|
||||||
return c.JSON(fiber.Map{
|
return c.JSON(fiber.Map{
|
||||||
"token": accessToken,
|
"token": accessToken,
|
||||||
"username": user.Username,
|
"refreshToken": refreshToken,
|
||||||
"role": user.Role,
|
"username": user.Username,
|
||||||
|
"role": user.Role,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +160,8 @@ func (h *Handler) Refresh(c *fiber.Ctx) error {
|
|||||||
MaxAge: 7 * 24 * 60 * 60, // 7 days
|
MaxAge: 7 * 24 * 60 * 60, // 7 days
|
||||||
})
|
})
|
||||||
return c.JSON(fiber.Map{
|
return c.JSON(fiber.Map{
|
||||||
"token": newAccessToken,
|
"token": newAccessToken,
|
||||||
|
"refreshToken": newRefreshToken,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,9 +350,10 @@ func (h *Handler) SSAFYCallback(c *fiber.Ctx) error {
|
|||||||
MaxAge: 7 * 24 * 60 * 60, // 7 days
|
MaxAge: 7 * 24 * 60 * 60, // 7 days
|
||||||
})
|
})
|
||||||
return c.JSON(fiber.Map{
|
return c.JSON(fiber.Map{
|
||||||
"token": accessToken,
|
"token": accessToken,
|
||||||
"username": user.Username,
|
"refreshToken": refreshToken,
|
||||||
"role": user.Role,
|
"username": user.Username,
|
||||||
|
"role": user.Role,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ type BossRoom struct {
|
|||||||
CreatedAt time.Time `json:"createdAt" gorm:"index"`
|
CreatedAt time.Time `json:"createdAt" gorm:"index"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
|
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
|
||||||
SessionName string `json:"sessionName" gorm:"type:varchar(100);uniqueIndex;not null"`
|
SessionName string `json:"sessionName" gorm:"type:varchar(100);uniqueIndex;not null"`
|
||||||
BossID int `json:"bossId" gorm:"index;not null"`
|
SlotSessionName string `json:"slotSessionName" gorm:"type:varchar(100);index;not null"`
|
||||||
|
BossID int `json:"bossId" gorm:"index;not null"`
|
||||||
Status RoomStatus `json:"status" gorm:"type:varchar(20);index;default:waiting;not null"`
|
Status RoomStatus `json:"status" gorm:"type:varchar(20);index;default:waiting;not null"`
|
||||||
MaxPlayers int `json:"maxPlayers" gorm:"default:3;not null"`
|
MaxPlayers int `json:"maxPlayers" gorm:"default:3;not null"`
|
||||||
// Players is stored as a JSON text column for simplicity.
|
// Players is stored as a JSON text column for simplicity.
|
||||||
|
|||||||
@@ -224,6 +224,12 @@ func (r *Repository) DeleteRoomBySessionName(sessionName string) error {
|
|||||||
return r.db.Unscoped().Where("session_name = ?", sessionName).Delete(&BossRoom{}).Error
|
return r.db.Unscoped().Where("session_name = ?", sessionName).Delete(&BossRoom{}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteRoomBySlotSessionName removes BossRoom records matching the original slot session name.
|
||||||
|
// Used when dedicated server calls ResetRoom with the slot name (not the unique per-entry name).
|
||||||
|
func (r *Repository) DeleteRoomBySlotSessionName(slotSessionName string) error {
|
||||||
|
return r.db.Unscoped().Where("slot_session_name = ?", slotSessionName).Delete(&BossRoom{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
// CleanupStaleWaitingRooms deletes BossRoom records stuck in "waiting" status
|
// CleanupStaleWaitingRooms deletes BossRoom records stuck in "waiting" status
|
||||||
// past the given threshold and resets their associated RoomSlots to idle.
|
// past the given threshold and resets their associated RoomSlots to idle.
|
||||||
// This handles cases where players disconnect during loading before the Fusion session starts.
|
// This handles cases where players disconnect during loading before the Fusion session starts.
|
||||||
|
|||||||
@@ -107,11 +107,12 @@ func (s *Service) RequestEntry(usernames []string, bossID int) (*BossRoom, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
room = &BossRoom{
|
room = &BossRoom{
|
||||||
SessionName: slot.SessionName,
|
SessionName: slot.SessionName,
|
||||||
BossID: bossID,
|
SlotSessionName: slot.SessionName,
|
||||||
Status: StatusWaiting,
|
BossID: bossID,
|
||||||
MaxPlayers: len(usernames),
|
Status: StatusWaiting,
|
||||||
Players: string(playersJSON),
|
MaxPlayers: len(usernames),
|
||||||
|
Players: string(playersJSON),
|
||||||
}
|
}
|
||||||
if err := txRepo.Create(room); err != nil {
|
if err := txRepo.Create(room); err != nil {
|
||||||
return fmt.Errorf("방 생성 실패: %w", err)
|
return fmt.Errorf("방 생성 실패: %w", err)
|
||||||
@@ -262,8 +263,13 @@ func (s *Service) CompleteRaid(sessionName string, rewards []PlayerReward) (*Bos
|
|||||||
if err := s.repo.DeleteRoomBySessionName(sessionName); err != nil {
|
if err := s.repo.DeleteRoomBySessionName(sessionName); err != nil {
|
||||||
log.Printf("BossRoom 삭제 실패 (complete): %s: %v", sessionName, err)
|
log.Printf("BossRoom 삭제 실패 (complete): %s: %v", sessionName, err)
|
||||||
}
|
}
|
||||||
if err := s.repo.ResetRoomSlot(sessionName); err != nil {
|
// SlotSessionName으로 슬롯 리셋 (고유 세션명이 아닌 원래 슬롯명)
|
||||||
log.Printf("슬롯 리셋 실패 (complete): %s: %v", sessionName, err)
|
slotName := resultRoom.SlotSessionName
|
||||||
|
if slotName == "" {
|
||||||
|
slotName = sessionName // 하위 호환
|
||||||
|
}
|
||||||
|
if err := s.repo.ResetRoomSlot(slotName); err != nil {
|
||||||
|
log.Printf("슬롯 리셋 실패 (complete): %s: %v", slotName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultRoom, resultRewards, nil
|
return resultRoom, resultRewards, nil
|
||||||
@@ -295,8 +301,12 @@ func (s *Service) FailRaid(sessionName string) (*BossRoom, error) {
|
|||||||
if err := s.repo.DeleteRoomBySessionName(sessionName); err != nil {
|
if err := s.repo.DeleteRoomBySessionName(sessionName); err != nil {
|
||||||
log.Printf("BossRoom 삭제 실패 (fail): %s: %v", sessionName, err)
|
log.Printf("BossRoom 삭제 실패 (fail): %s: %v", sessionName, err)
|
||||||
}
|
}
|
||||||
if err := s.repo.ResetRoomSlot(sessionName); err != nil {
|
slotName := room.SlotSessionName
|
||||||
log.Printf("슬롯 리셋 실패 (fail): %s: %v", sessionName, err)
|
if slotName == "" {
|
||||||
|
slotName = sessionName
|
||||||
|
}
|
||||||
|
if err := s.repo.ResetRoomSlot(slotName); err != nil {
|
||||||
|
log.Printf("슬롯 리셋 실패 (fail): %s: %v", slotName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return room, nil
|
return room, nil
|
||||||
@@ -411,7 +421,11 @@ func (s *Service) RequestEntryWithTokens(usernames []string, bossID int) (*BossR
|
|||||||
if delErr := s.repo.DeleteRoomBySessionName(room.SessionName); delErr != nil {
|
if delErr := s.repo.DeleteRoomBySessionName(room.SessionName); delErr != nil {
|
||||||
log.Printf("롤백 중 방 삭제 실패: %v", delErr)
|
log.Printf("롤백 중 방 삭제 실패: %v", delErr)
|
||||||
}
|
}
|
||||||
if resetErr := s.repo.ResetRoomSlot(room.SessionName); resetErr != nil {
|
rollbackSlot := room.SlotSessionName
|
||||||
|
if rollbackSlot == "" {
|
||||||
|
rollbackSlot = room.SessionName
|
||||||
|
}
|
||||||
|
if resetErr := s.repo.ResetRoomSlot(rollbackSlot); resetErr != nil {
|
||||||
log.Printf("롤백 중 슬롯 리셋 실패: %v", resetErr)
|
log.Printf("롤백 중 슬롯 리셋 실패: %v", resetErr)
|
||||||
}
|
}
|
||||||
return nil, nil, fmt.Errorf("입장 토큰 생성 실패: %w", err)
|
return nil, nil, fmt.Errorf("입장 토큰 생성 실패: %w", err)
|
||||||
@@ -445,7 +459,11 @@ func (s *Service) cleanupStaleWaitingForUsers(usernames []string) {
|
|||||||
if err := s.repo.DeleteRoomBySessionName(room.SessionName); err != nil {
|
if err := s.repo.DeleteRoomBySessionName(room.SessionName); err != nil {
|
||||||
log.Printf("대기방 삭제 실패: %v", err)
|
log.Printf("대기방 삭제 실패: %v", err)
|
||||||
}
|
}
|
||||||
_ = s.repo.ResetRoomSlot(room.SessionName)
|
cleanupSlot := room.SlotSessionName
|
||||||
|
if cleanupSlot == "" {
|
||||||
|
cleanupSlot = room.SessionName
|
||||||
|
}
|
||||||
|
_ = s.repo.ResetRoomSlot(cleanupSlot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,10 +545,15 @@ func (s *Service) CheckStaleSlots() {
|
|||||||
|
|
||||||
// ResetRoom resets a room slot back to idle and cleans up any lingering BossRoom records.
|
// ResetRoom resets a room slot back to idle and cleans up any lingering BossRoom records.
|
||||||
// Called by the dedicated server after a raid ends and the runner is recycled.
|
// Called by the dedicated server after a raid ends and the runner is recycled.
|
||||||
|
// sessionName here is the slot's original session name (not the unique per-entry name).
|
||||||
func (s *Service) ResetRoom(sessionName string) error {
|
func (s *Service) ResetRoom(sessionName string) error {
|
||||||
// 완료/실패되지 않은 BossRoom 레코드 정리 (waiting/in_progress 상태)
|
// 고유 세션명 BossRoom도 정리 (slot_session_name으로 검색)
|
||||||
|
if err := s.repo.DeleteRoomBySlotSessionName(sessionName); err != nil {
|
||||||
|
log.Printf("BossRoom 레코드 정리 실패 (by slot): %s: %v", sessionName, err)
|
||||||
|
}
|
||||||
|
// 하위 호환: 원래 세션명으로도 시도
|
||||||
if err := s.repo.DeleteRoomBySessionName(sessionName); err != nil {
|
if err := s.repo.DeleteRoomBySessionName(sessionName); err != nil {
|
||||||
log.Printf("BossRoom 레코드 정리 실패: %s: %v", sessionName, err)
|
// 이미 삭제되었을 수 있으므로 무시
|
||||||
}
|
}
|
||||||
return s.repo.ResetRoomSlot(sessionName)
|
return s.repo.ResetRoomSlot(sessionName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,12 +151,12 @@ func (s *Service) Upload(filename string, body io.Reader, baseURL string) (*Info
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileHash := hashGameExeFromZip(finalPath)
|
// game.zip 전체의 해시를 사용하여 업데이트 감지.
|
||||||
|
// A301.exe만 해시하면 Mono 빌드에서 exe가 안 바뀌어도
|
||||||
|
// Data 폴더의 스크립트/에셋 변경을 감지하지 못함.
|
||||||
|
fileHash := hashFileToHex(finalPath)
|
||||||
if fileHash == "" {
|
if fileHash == "" {
|
||||||
if removeErr := os.Remove(finalPath); removeErr != nil {
|
return nil, fmt.Errorf("파일 해시 계산에 실패했습니다")
|
||||||
log.Printf("WARNING: failed to remove file %s: %v", finalPath, removeErr)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("zip 파일에 %s이(가) 포함되어 있지 않습니다", "A301.exe")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := s.repo.GetLatest()
|
info, err := s.repo.GetLatest()
|
||||||
|
|||||||
Reference in New Issue
Block a user