diff --git a/download.go b/download.go index ccbb0d7..493016b 100644 --- a/download.go +++ b/download.go @@ -191,17 +191,15 @@ func doDownload(downloadURL, destDir string) error { if err != nil { return fmt.Errorf("임시 추출 디렉토리 생성 실패: %w", err) } + defer os.RemoveAll(tmpExtractDir) if err := extractZip(tmpPath, tmpExtractDir); err != nil { - os.RemoveAll(tmpExtractDir) return err } if err := moveContents(tmpExtractDir, destDir); err != nil { - os.RemoveAll(tmpExtractDir) return fmt.Errorf("파일 이동 실패: %w", err) } - os.RemoveAll(tmpExtractDir) return nil } diff --git a/main.go b/main.go index 8c2d0a7..90c054f 100644 --- a/main.go +++ b/main.go @@ -58,7 +58,7 @@ func handleURI(rawURI string) error { if _, statErr := os.Stat(gamePath); statErr == nil { ret := msgBox("One of the plans", "서버에 연결할 수 없습니다.\n설치된 게임을 실행하시겠습니까?\n(업데이트 확인 불가)", mbYesNo|mbQ) if ret == idYes { - cmd := exec.Command(gamePath, "-token", token) + cmd := exec.Command(gamePath) cmd.Dir = gameDir cmd.Env = append(os.Environ(), "A301_TOKEN="+token) if err := cmd.Start(); err != nil { @@ -86,7 +86,7 @@ func handleURI(rawURI string) error { return err } - cmd := exec.Command(gamePath, "-token", token) + cmd := exec.Command(gamePath) cmd.Dir = gameDir cmd.Env = append(os.Environ(), "A301_TOKEN="+token) if err := cmd.Start(); err != nil { diff --git a/protocol.go b/protocol.go index 5cd370b..83f4e9e 100644 --- a/protocol.go +++ b/protocol.go @@ -156,8 +156,24 @@ func fetchServerInfo() (*downloadInfo, error) { } // redeemTicket exchanges a one-time launch ticket for a fresh JWT access token. +// Retries up to 3 times with exponential backoff on transient errors. func redeemTicket(ticket string) (string, error) { - return redeemTicketFrom(redeemTicketURL, ticket) + const maxRetries = 3 + var lastErr error + for i := range maxRetries { + token, err := redeemTicketFrom(redeemTicketURL, ticket) + if err == nil { + return token, nil + } + lastErr = err + // HTTP 4xx errors should not be retried + var noRetry *errNoRetry + if errors.As(err, &noRetry) { + return "", err + } + time.Sleep(time.Duration(1<= 400 && resp.StatusCode < 500 { + return "", &errNoRetry{fmt.Errorf("런처 인증에 실패했습니다 (HTTP %d)", resp.StatusCode)} + } if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("런처 인증에 실패했습니다 (HTTP %d)", resp.StatusCode) }