// // APIController.swift // AcaMate // // Created by Sean Kim on 11/26/24. // import Foundation import Combine import Alamofire public class APIManager { private var cancellables = Set() // public static let shared = APIManager() @UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh @UserDefault(key: "token", defaultValue: "accToken") var accToken // private init(cancellables: Set = Set()) { // self.cancellables = cancellables // } public func loadAPIData(_ request: APIRequest) -> Future { let encoding: ParameterEncoding = (request.method == .get) ? URLEncoding.default : JSONEncoding.default return Future { promise in printLog(request.parameters) AF.request("\(request.url)\(request.path)", method: request.method, parameters: request.parameters, encoding: encoding, headers: request.headers ) .validate(statusCode: 200 ..< 300) .responseDecodable(of: request.decoding) { response in switch response.result { case .success(let value): printLog("Good: \(value)") promise(.success(value)) case .failure(let error): printLog("Bad: \(error))") promise(.failure(error)) } } } } public func reloadAccessToken() -> Future { return Future { [weak self] promise in guard let self = self else {return} let request = APIRequest.init(path: "/api/v1/in/app/retryAccess", parameters: ["refresh": refresh], decoding: APIResponse.self) APIManager().loadAPIData(request) .sink { completion in switch completion { case .failure(let error): promise(.failure(error)) printLog("\(error)") case .finished: printLog("엑세스 토큰 재발급 완료") break } } receiveValue: { response in guard let accToken = response as? APIResponse else { promise(.failure(ACA_ERROR("Unknown ERROR"))) return } switch accToken.status.code { case .success(let code): if code == "000" { if let tknData = accToken.data { promise(.success(tknData)) } } case .inputErr(let code): // 로그인 화면으로 전환하기 promise(.failure(ACA_ERROR("Refresh token ERROR(\(code), \(accToken.status.message)"))) default: // 그외에 서버에서 처리를 하다가 문제가 생겨서 발생하는 에러는 여기로 보낼거임 promise(.failure(ACA_ERROR("Unknown ERROR"))) } } .store(in: &self.cancellables) } } public func loadUserAPIData(request: APIRequest) -> Future{ return Future { [weak self] promise in guard let self = self else {return} printLog(request.parameters["token"]) loadAPIData(request) .flatMap { (response: T) -> AnyPublisher in switch response.status.code { case .inputErr(let code) where code == "101": return self.reloadAccessToken() .flatMap { response -> AnyPublisher in self.accToken = (response as! Access).access var updateRequest = request updateRequest.parameters["token"] = self.accToken return APIManager().loadAPIData(updateRequest) .eraseToAnyPublisher() } .eraseToAnyPublisher() default: return Just(response) .setFailureType(to: Error.self) .eraseToAnyPublisher() } } .sink { completion in switch completion { case .failure(let error): promise(.failure(error)) case .finished: break } } receiveValue: { finalResponse in promise(.success(finalResponse)) } .store(in: &self.cancellables) } } }