Fableon/Fableon/Object/Base/Request/FANetworkManager.swift
湖北秦九 008d5b55b8 1
2025-11-21 09:12:46 +08:00

243 lines
7.6 KiB
Swift

//
// FANetworkManager.swift
// Fableon
//
// Created by on 2025/9/15.
//
import Foundation
import Alamofire
import AdSupport
import SmartCodable
import YYCategories
///
class FANetworkManager {
static let manager = FANetworkManager()
private let operationQueue = OperationQueue()
private var tokenOperation: BlockOperation?
//
func request<T: SmartCodable>(
_ url: String,
method: HTTPMethod = .post,
parameters: Parameters? = nil,
isLoding: Bool = false,
isToast: Bool = true,
completion: ((_ response: FANetworkManager.Response<T>) -> Void)?
) {
if FALogin.manager.token == nil, !isTokenUrl(url) {
self.requestUserToken(completer: nil)
}
if let _ = self.tokenOperation, !isTokenUrl(url) {
requestAddQueue(url, method: method, parameters: parameters, isLoding: isLoding, isToast: isToast, completion: completion)
return
}
_request(url, method: method, parameters: parameters, isLoding: isLoding, isToast: isToast, completion: completion)
}
private func _request<T: SmartCodable>(
_ url: String,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
isLoding: Bool,
isToast: Bool,
completion: ((_ response: FANetworkManager.Response<T>) -> Void)?
) {
if isLoding {
FAHUD.show()
}
AF.request(
url,
method: method,
parameters: parameters,
encoding: method == .get ? URLEncoding.default : JSONEncoding.default,
headers: self.headers
)
.responseString(completionHandler: { response in
if isLoding {
FAHUD.dismiss()
}
let code = response.response?.statusCode
if code == 401 || code == 402 || code == 403 {
if self.isTokenUrl(url) {
var response = FANetworkManager.Response<T>()
response.code = -1
completion?(response)
} else {
if code == 402, isToast {
FAToast.show(text: "fableon_kick_out_login".localized)
}
self.requestUserToken {
if FALogin.manager.token != nil {
FALogin.manager.requestUserInfo(completer: nil)
}
}
if let _ = self.tokenOperation, !self.isTokenUrl(url) {
self.requestAddQueue(url, method: method, parameters: parameters, isLoding: isLoding, isToast: isToast, completion: completion)
}
}
return
}
switch response.result {
case .success(let data):
let decrypted = FACryptorService.decrypt(data: data)
if let parameters = parameters {
debugLog(parameters)
}
debugLog(url)
debugLog(decrypted)
if let response = FANetworkManager.Response<T>.deserialize(from: decrypted) {
completion?(response)
} else {
if isToast {
FAToast.show(text: "fableon_error".localized)
}
var res = FANetworkManager.Response<T>()
res.code = -1
res.msg = "解析错误"
completion?(res)
}
case .failure(let error):
if isToast {
FAToast.show(text: "network_error_01".localized)
}
var res = FANetworkManager.Response<T>()
res.code = error.responseCode
res.msg = error.localizedDescription
completion?(res)
}
})
}
}
extension FANetworkManager {
private func requestUserToken(completer: (() -> Void)?) {
guard self.tokenOperation == nil else {
completer?()
return
}
self.tokenOperation = BlockOperation(block: {
let semaphore = DispatchSemaphore(value: 0)
FALogin.manager.requestUserToken {
do { semaphore.signal() }
self.tokenOperation = nil
completer?()
}
semaphore.wait()
})
operationQueue.addOperation(self.tokenOperation!)
}
private func requestAddQueue<T: SmartCodable>(_ url: String,
method: HTTPMethod,
parameters: Parameters?,
isLoding: Bool,
isToast: Bool,
completion: ((_ response: FANetworkManager.Response<T>) -> Void)?) {
guard let tokenOperation = self.tokenOperation else { return }
let requestOperation = BlockOperation {
let semaphore = DispatchSemaphore(value: 0)
self._request(url, method: method, parameters: parameters, isLoding: isLoding, isToast: isToast) { response in
semaphore.signal()
completion?(response)
}
semaphore.wait()
}
///
requestOperation.addDependency(tokenOperation)
operationQueue.addOperation(requestOperation)
}
}
extension FANetworkManager {
private func isTokenUrl(_ url: String) -> Bool {
return url.contains("/customer/register")
}
private var headers: HTTPHeaders {
let token = FALogin.manager.token?.token ?? ""
var dic = [
"authorization" : token,
"system-version" : UIDevice.current.systemVersion,
"lang-key" : FALanguageManager.manager.currentLanguageKey,
"time-zone" : String.timeZone(),
"app-version" : (Bundle.main.infoDictionary!["CFBundleShortVersionString"] as? String) ?? "",
"brand" : "apple", //
"app-name" : "Fableon",
"system-type" : "ios",
"model" : UIDevice.current.machineModelName ?? "",
"idfa" : ASIdentifierManager.shared().advertisingIdentifier.uuidString,
"device-id" : FADeviceIDManager.shared.id, //id
"device-gaid" : UIDevice.current.identifierForVendor?.uuidString ?? "",
"product-prefix" : FAIapManager.IAPPrefix,
]
#if DEBUG
dic["security"] = "false"
#endif
return HTTPHeaders(dic)
}
}
extension FANetworkManager {
struct Response<T : SmartCodable>: SmartCodable {
var code: Int?
var data: T?
var msg: String?
var isSuccess: Bool {
return code == 200
}
}
struct List<T: SmartCodable>: SmartCodable {
var list: [T]?
var pagination: Pagination?
var hasNextPage: Bool {
let totalPage = pagination?.page_total ?? 0
let currentPage = pagination?.current_page ?? 0
return totalPage > currentPage
}
}
struct Pagination: SmartCodable {
var current_page: Int?
var page_size: Int?
var page_total: Int?
var total_size: Int?
}
}