@@ -37,6 +37,8 @@ protocol AuthManagerDelegate: AnyObject {
3737
3838class AuthManager : CompositeManager < AuthManagerConfiguration > {
3939
40+ private let reAuthenticateQueue = DispatchQueue ( label: " com.sooum.reAuthenticate.serial.queue " )
41+
4042 private var isReAuthenticating : Bool = false
4143 private var pendingResults : [ ( AuthResult ) -> Void ] = [ ]
4244
@@ -229,72 +231,79 @@ extension AuthManager: AuthManagerDelegate {
229231 4. RefreshToken 도 유효하지 않다면 로그인 시도
230232 */
231233 func reAuthenticate( _ token: Token , _ completion: @escaping ( AuthResult ) -> Void ) {
232-
233- guard self . authInfo. token. isEmpty == false else {
234- let error = NSError (
235- domain: " SOOUM " ,
236- code: - 99 ,
237- userInfo: [ NSLocalizedDescriptionKey: " tokens not found " ]
238- )
239- completion ( . failure( error) )
240- return
241- }
242-
243- /// 1개 이상의 API에서 reAuthenticate 요청 했을 때,
244- /// 처음 요청이 끝날 떄까지 대기
245- guard self . isReAuthenticating == false else {
234+ var immediateResult : AuthResult ?
235+ /// isReAuthenticating == true로 변경되기 전 짧은 시간에 재인증 요청이 들어왔을 때, 순서 보장
236+ let shouldRequest : Bool = self . reAuthenticateQueue. sync {
237+ guard self . authInfo. token. isEmpty == false else {
238+ let error = NSError (
239+ domain: " SOOUM " ,
240+ code: - 99 ,
241+ userInfo: [ NSLocalizedDescriptionKey: " tokens not found " ]
242+ )
243+ immediateResult = . failure( error)
244+ return false
245+ }
246+
247+ /// AccessToken이 업데이트 됐다면, 즉시 성공 처리
248+ guard token == self . authInfo. token else {
249+ immediateResult = . success
250+ return false
251+ }
252+
246253 self . pendingResults. append ( completion)
247- return
248- }
249-
250- /// AccessToken이 업데이트 됐다면, 즉시 성공 처리
251- guard token == self . authInfo . token else {
252- completion ( . success )
253- return
254+
255+ /// 1개 이상의 API에서 reAuthenticate 요청 했을 때,
256+ /// 처음 요청이 끝날 떄까지 대기
257+ guard self . isReAuthenticating == false else { return false }
258+ self . isReAuthenticating = true
259+
260+ return true
254261 }
255-
256- self . isReAuthenticating = true
257- self . pendingResults. append ( completion)
258-
259- let request : AuthRequest = . reAuthenticationWithRefreshSession( token: token)
260- self . provider. networkManager. perform ( TokenResponse . self, request: request)
261- . map ( \. token)
262- . subscribe (
263- with: self ,
264- onNext: { object, token in
265-
266- if token. accessToken. isEmpty && token. refreshToken. isEmpty {
267- let error = NSError (
268- domain: " SOOUM " ,
269- code: - 99 ,
270- userInfo: [ NSLocalizedDescriptionKey: " Session not refresh " ]
271- )
272-
273- object. excutePendingResults ( . failure( error) )
274- } else {
275-
276- object. updateTokens ( token)
262+ /// 여러 API가 재인증 요청 시, 맨 처음 요청만 재인증 요청
263+ if shouldRequest == false , let result = immediateResult {
264+ completion ( result)
265+ } else if shouldRequest {
266+
267+ let request : AuthRequest = . reAuthenticationWithRefreshSession( token: token)
268+ self . provider. networkManager. perform ( TokenResponse . self, request: request)
269+ . map ( \. token)
270+ . subscribe (
271+ with: self ,
272+ onNext: { object, token in
277273
278- // FCM token 업데이트
279- object. provider. networkManager. registerFCMToken ( from: #function)
274+ if token. accessToken. isEmpty && token. refreshToken. isEmpty {
275+ let error = NSError (
276+ domain: " SOOUM " ,
277+ code: - 99 ,
278+ userInfo: [ NSLocalizedDescriptionKey: " Session not refresh " ]
279+ )
280+
281+ object. excutePendingResults ( . failure( error) )
282+ } else {
283+
284+ object. updateTokens ( token)
285+
286+ // FCM token 업데이트
287+ object. provider. networkManager. registerFCMToken ( from: #function)
288+
289+ object. excutePendingResults ( . success)
290+ }
280291
281- object. excutePendingResults ( . success)
292+ object. isReAuthenticating = false
293+ } ,
294+ onError: { object, error in
295+ /// 재인증 과정이 실패하면 항상 재로그인 시도
296+ object. certification ( )
297+ . subscribe ( onNext: { isRegistered in
298+ object. excutePendingResults ( isRegistered ? . success : . failure( error) )
299+
300+ object. isReAuthenticating = false
301+ } )
302+ . disposed ( by: object. disposeBag)
282303 }
283-
284- object. isReAuthenticating = false
285- } ,
286- onError: { object, error in
287- /// 재인증 과정이 실패하면 항상 재로그인 시도
288- object. certification ( )
289- . subscribe ( onNext: { isRegistered in
290- object. excutePendingResults ( isRegistered ? . success : . failure( error) )
291-
292- object. isReAuthenticating = false
293- } )
294- . disposed ( by: object. disposeBag)
295- }
296- )
297- . disposed ( by: self . disposeBag)
304+ )
305+ . disposed ( by: self . disposeBag)
306+ }
298307 }
299308
300309 func initializeAuthInfo( ) {
0 commit comments