Skip to content

Commit 42f59a0

Browse files
authored
Merge pull request #327 from Atcha-Project/env/dev
[Merge] Live 환경 배포 및 심사 (v1.9.5)
2 parents a41fd45 + 0e477cc commit 42f59a0

50 files changed

Lines changed: 252 additions & 154 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Atcha-iOS.xcodeproj/project.pbxproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,7 +2516,7 @@
25162516
CODE_SIGN_IDENTITY = "Apple Development";
25172517
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
25182518
CODE_SIGN_STYLE = Manual;
2519-
CURRENT_PROJECT_VERSION = 1;
2519+
CURRENT_PROJECT_VERSION = 4;
25202520
DEVELOPMENT_TEAM = "";
25212521
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 23SCTLK482;
25222522
FRAMEWORK_SEARCH_PATHS = (
@@ -2539,7 +2539,7 @@
25392539
"$(inherited)",
25402540
"@executable_path/Frameworks",
25412541
);
2542-
MARKETING_VERSION = 1.9.2;
2542+
MARKETING_VERSION = 1.9.5;
25432543
PRODUCT_BUNDLE_IDENTIFIER = com.atcha.iOS;
25442544
PRODUCT_NAME = "$(TARGET_NAME)";
25452545
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2563,7 +2563,7 @@
25632563
CODE_SIGN_ENTITLEMENTS = "Atcha-iOS/Atcha-iOS.entitlements";
25642564
CODE_SIGN_IDENTITY = "Apple Development";
25652565
CODE_SIGN_STYLE = Automatic;
2566-
CURRENT_PROJECT_VERSION = 1;
2566+
CURRENT_PROJECT_VERSION = 4;
25672567
DEVELOPMENT_TEAM = 23SCTLK482;
25682568
EXCLUDED_ARCHS = "";
25692569
FRAMEWORK_SEARCH_PATHS = (
@@ -2586,7 +2586,7 @@
25862586
"$(inherited)",
25872587
"@executable_path/Frameworks",
25882588
);
2589-
MARKETING_VERSION = 1.9.2;
2589+
MARKETING_VERSION = 1.9.5;
25902590
OTHER_SWIFT_FLAGS = "";
25912591
PRODUCT_BUNDLE_IDENTIFIER = com.atcha.iOS;
25922592
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -2611,7 +2611,7 @@
26112611
CODE_SIGN_IDENTITY = "Apple Development";
26122612
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
26132613
CODE_SIGN_STYLE = Manual;
2614-
CURRENT_PROJECT_VERSION = 1;
2614+
CURRENT_PROJECT_VERSION = 4;
26152615
DEVELOPMENT_TEAM = "";
26162616
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 23SCTLK482;
26172617
FRAMEWORK_SEARCH_PATHS = (
@@ -2634,7 +2634,7 @@
26342634
"$(inherited)",
26352635
"@executable_path/Frameworks",
26362636
);
2637-
MARKETING_VERSION = 1.9.2;
2637+
MARKETING_VERSION = 1.9.5;
26382638
PRODUCT_BUNDLE_IDENTIFIER = com.atcha.iOS;
26392639
PRODUCT_NAME = "$(TARGET_NAME)";
26402640
PROVISIONING_PROFILE_SPECIFIER = "";

Atcha-iOS.xcodeproj/xcshareddata/xcschemes/Atcha-Live.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
shouldAutocreateTestPlan = "YES">
4141
</TestAction>
4242
<LaunchAction
43-
buildConfiguration = "Debug"
43+
buildConfiguration = "Release"
4444
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
4545
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
4646
launchStyle = "0"

Atcha-iOS.xcodeproj/xcshareddata/xcschemes/Atcha-Stage.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
shouldAutocreateTestPlan = "YES">
4141
</TestAction>
4242
<LaunchAction
43-
buildConfiguration = "Debug"
43+
buildConfiguration = "Stage"
4444
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
4545
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
4646
launchStyle = "0"

Atcha-iOS/Core/Manager/Discord/DiscordWebhookManager.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ final class DiscordWebhookManager {
1414
private let webhookURLString = "https://discord.com/api/webhooks/1483870710018474066/qyzNBI1Bwr7J5tQDrPx2-mOcej_9yLSOk5Bmlmza2D-4nSWqvWgcMd4CZDziG4vkpKrm"
1515

1616
func sendErrorLog(
17+
baseURL: String,
1718
statusCode: Int,
1819
method: String,
1920
path: String,
@@ -55,6 +56,7 @@ final class DiscordWebhookManager {
5556
"title": "서버 에러 상세 보고",
5657
"color": 16711680,
5758
"fields": [
59+
["name": "Base URL", "value": "`\(baseURL)`", "inline": false],
5860
["name": "Method & Path", "value": "`\(method) \(path)`", "inline": false],
5961
["name": "HTTP Status", "value": "\(statusCode)", "inline": true],
6062
["name": "responseCode", "value": responseCode, "inline": true],

Atcha-iOS/Core/Manager/Proximity/ProximityManager.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ final class ProximityManager {
1313

1414
// 판별 임계값(미터). 기본 1km.
1515
private let threshold: CLLocationDistance
16-
static let shared = ProximityManager(thresholdMeters: 1_000)
16+
static let shared = ProximityManager(thresholdMeters: 800)
1717

18-
init(thresholdMeters: CLLocationDistance = 1_000) {
18+
init(thresholdMeters: CLLocationDistance = 800) {
1919
self.threshold = thresholdMeters
2020
}
2121

Atcha-iOS/Core/Manager/Proximity/ProximityViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ final class ProximityViewController: BaseViewController<ProximityViewModel> {
8585
containerView.snp.makeConstraints {
8686
$0.leading.trailing.equalToSuperview()
8787
$0.bottom.equalToSuperview()
88-
$0.height.equalTo(195)
88+
$0.height.equalTo(182)
8989
}
9090

9191
labelStackView.snp.makeConstraints {

Atcha-iOS/Core/Network/API/APIServiceImpl.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ extension APIServiceImpl {
124124
}
125125

126126
DiscordWebhookManager.shared.sendErrorLog(
127+
baseURL: NetworkConstant.baseURL,
127128
statusCode: statusCode,
128129
method: method,
129130
path: serverPath,
@@ -136,7 +137,7 @@ extension APIServiceImpl {
136137

137138
let apiError = APIError.serverError(statusCode: statusCode, responseCode: responseCode)
138139

139-
NotificationCenter.default.post(name: .apiErrorOccurred, object: apiError)
140+
// NotificationCenter.default.post(name: .apiErrorOccurred, object: apiError)
140141
continuation.resume(throwing: apiError)
141142
}
142143
}

Atcha-iOS/Core/Network/Token/TokenInterceptor.swift

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ final class TokenInterceptor: RequestInterceptor, @unchecked Sendable {
3838
]
3939

4040
if publicPaths.contains(where: { path.hasSuffix($0) }) {
41-
completion(.success(request))
42-
return
43-
}
41+
completion(.success(request))
42+
return
43+
}
4444

4545
if path.contains("/auth/logout") {
4646
if let refreshToken = tokenStorage.refreshToken {
@@ -65,7 +65,6 @@ final class TokenInterceptor: RequestInterceptor, @unchecked Sendable {
6565
return
6666
}
6767

68-
6968
let path = request.request?.url?.path ?? "unknown"
7069

7170
if path.contains("/auth/reissue") {
@@ -78,6 +77,8 @@ final class TokenInterceptor: RequestInterceptor, @unchecked Sendable {
7877
return
7978
}
8079

80+
let actualHeaders = request.request?.allHTTPHeaderFields ?? [:]
81+
8182
guard let refreshToken = tokenStorage.refreshToken else {
8283
SessionController.shared.expireAndRouteToLogin()
8384
completion(.doNotRetry)
@@ -109,12 +110,29 @@ final class TokenInterceptor: RequestInterceptor, @unchecked Sendable {
109110
return
110111
}
111112

113+
let successBody = [
114+
"newAccessToken": p.accessToken,
115+
"newRefreshToken": p.refreshToken
116+
]
117+
118+
DiscordWebhookManager.shared.sendErrorLog(
119+
baseURL: NetworkConstant.baseURL,
120+
statusCode: 200,
121+
method: "GET",
122+
path: "/auth/reissue",
123+
responseCode: "REISSUE_SUCCESS",
124+
message: "토큰 재발급에 성공하여 새로운 토큰을 수신했습니다.",
125+
requestHeaders: actualHeaders,
126+
requestBody: successBody, // 여기서 받은 토큰 정보를 보냅니다.
127+
requestParameters: nil
128+
)
129+
112130
self.tokenStorage.accessToken = p.accessToken
113131
self.tokenStorage.refreshToken = p.refreshToken
114132

115133
waiters.forEach { $0(.retry) }
116134

117-
case .failure(let error):
135+
case .failure(_):
118136
SessionController.shared.expireAndRouteToLogin()
119137
waiters.forEach { $0(.doNotRetry) }
120138
}

Atcha-iOS/Data/Repository/CourseRepositoryImpl.swift

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -72,21 +72,8 @@ final class CourseRepositoryImpl: CourseRepository {
7272
throw URLError(.badServerResponse)
7373
}
7474

75-
// 401 외의 코드도 명확히 분기
76-
if http.statusCode == 401 {
77-
if let tokens = await refreshToken() {
78-
tokenStorage.accessToken = tokens.accessToken
79-
if let rt = tokens.refreshToken { tokenStorage.refreshToken = rt }
80-
print("재발급 성공 → 스트림 재연결")
81-
await startStream(request, continuation: continuation)
82-
return
83-
} else {
84-
continuation.finish(throwing: NSError(domain: "CourseRepository", code: 401, userInfo: [NSLocalizedDescriptionKey: "토큰 재발급 실패"]))
85-
return
86-
}
87-
} else if http.statusCode != 200 {
88-
// 서버가 JSON 에러 바디를 줄 수 있으니 한번 읽어봄
89-
// bytes(for:)는 스트림이므로 바디를 통째로 읽기 어렵다 → 상태만으로 에러 처리
75+
// HTTP 401 체크는 제거 (서버가 200으로 주기 때문)
76+
if http.statusCode != 200 {
9077
continuation.finish(throwing: NSError(domain: "CourseRepository", code: http.statusCode, userInfo: [NSLocalizedDescriptionKey: "SSE 연결 실패 (\(http.statusCode))"]))
9178
return
9279
}
@@ -100,23 +87,41 @@ final class CourseRepositoryImpl: CourseRepository {
10087
let events = parser.feed(Data([byte]))
10188
for event in events {
10289
guard !event.data.isEmpty, let payload = event.data.data(using: .utf8) else { continue }
90+
91+
// 1. 데이터 내부의 에러 코드 확인 (TOK_001)
92+
if let errorCheck = try? JSONDecoder().decode(SSEErrorPayload.self, from: payload),
93+
errorCheck.responseCode == "TOK_001" {
94+
95+
if let tokens = await refreshToken() {
96+
tokenStorage.accessToken = tokens.accessToken
97+
if let rt = tokens.refreshToken { tokenStorage.refreshToken = rt }
98+
print("재발급 성공 → 스트림 재연결")
99+
// 현재 스트림을 종료하지 않고 새 연결 시도
100+
await startStream(request, continuation: continuation)
101+
return
102+
} else {
103+
continuation.finish(throwing: NSError(domain: "CourseRepository", code: 401, userInfo: [NSLocalizedDescriptionKey: "토큰 재발급 실패"]))
104+
return
105+
}
106+
}
107+
108+
// 2. 정상 데이터 디코딩
103109
do {
104110
let decoded = try JSONDecoder().decode(CourseSearchResponse.self, from: payload)
111+
print("데이터 수신: \(decoded)")
105112
continuation.yield(decoded)
106113
} catch {
107-
// 서버가 keep-alive ping 이나 텍스트를 보낼 수 있으므로 디코드 실패는 경고만
108-
print("SSE decode 실패:", error, "raw:", event.data)
114+
// 단순 텍스트나 핑 데이터인 경우 무시
115+
print("SSE decode 실패 (데이터 무시):", error, "raw:", event.data)
109116
}
110117
}
111118
}
112119
} catch {
113-
// 실제 네트워크 오류(연결 끊김 등)
114120
print("SSE stream read error:", error)
115121
continuation.finish(throwing: error)
116122
return
117123
}
118124

119-
// 서버가 조용히 닫은 케이스
120125
if !receivedAny {
121126
continuation.finish(throwing: NSError(domain: "CourseRepository", code: -1, userInfo: [NSLocalizedDescriptionKey: "SSE에서 응답이 없습니다."]))
122127
return
@@ -182,6 +187,9 @@ final class CourseRepositoryImpl: CourseRepository {
182187
return nil
183188
}
184189
}
185-
186190
}
187191

192+
struct SSEErrorPayload: Decodable {
193+
let responseCode: String?
194+
let message: String?
195+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "bus-chevron-right.png",
5+
"idiom" : "universal",
6+
"scale" : "1x"
7+
},
8+
{
9+
"filename" : "bus-chevron-right@2x.png",
10+
"idiom" : "universal",
11+
"scale" : "2x"
12+
},
13+
{
14+
"filename" : "bus-chevron-right@3x.png",
15+
"idiom" : "universal",
16+
"scale" : "3x"
17+
}
18+
],
19+
"info" : {
20+
"author" : "xcode",
21+
"version" : 1
22+
}
23+
}

0 commit comments

Comments
 (0)