2026-01-27 15:55:28 +08:00

206 lines
7.2 KiB
Swift

//
// NRNetwork.swift
// ReaderHive
//
// Created by on 2025/11/21.
//
import UIKit
import Moya
import SmartCodable
class NRNetwork: NSObject {
private static let operationQueue = OperationQueue()
private static var tokenOperation: BlockOperation?
static let provider = MoyaProvider<NRTargetType>()
static func request<T>(parameters: NRNetwork.Parameters, completion: ((_ response: NRNetwork.Response<T>) -> Void)?) {
if NRLoginManager.manager.token == nil {
self.requestToken(completer: nil)
}
if let tokenOperation = self.tokenOperation, parameters.path != "/customer/register" {
let requestOperation = BlockOperation {
let semaphore = DispatchSemaphore(value: 0)
_request(parameters: parameters) { (response: NRNetwork.Response<T>) in
semaphore.signal()
completion?(response)
}
semaphore.wait()
}
///
requestOperation.addDependency(tokenOperation)
operationQueue.addOperation(requestOperation)
} else {
_request(parameters: parameters, completion: completion)
}
}
@discardableResult
static func _request<T>(parameters: NRNetwork.Parameters, completion: ((_ response: NRNetwork.Response<T>) -> Void)?) -> Cancellable {
if parameters.isLoding {
DispatchQueue.main.async {
NRHud.show()
}
}
return provider.request(.request(parameters: parameters)) { result in
if parameters.isLoding {
DispatchQueue.main.async {
NRHud.dismiss()
}
}
guard let completion = completion else {return}
_resultDispose(parameters: parameters, result: result, completion: completion)
}
}
private static func _resultDispose<T>(parameters: NRNetwork.Parameters, result: Result<Moya.Response, MoyaError>, completion: ((_ response: NRNetwork.Response<T>) -> Void)?) {
switch result {
case .success(let response):
let code = response.statusCode
if code == 401 || code == 402 || code == 403 {
if parameters.path == "/customer/register" {
var res = NRNetwork.Response<T>()
res.code = -1
if parameters.isToast {
DispatchQueue.main.async {
NRToast.show(text: "Error".localized)
}
}
completion?(res)
} else {
if code == 402, parameters.isToast {
DispatchQueue.main.async {
NRToast.show(text: "reader_kick_out_login".localized)
}
}
//token
self.requestToken { token in
if token != nil {
_Concurrency.Task {
await NRLoginManager.manager.updateUserInfo()
}
}
}
///
if let tokenOperation = self.tokenOperation, parameters.path != "/customer/register" {
let requestOperation = BlockOperation {
let semaphore = DispatchSemaphore(value: 0)
_request(parameters: parameters) { (response: NRNetwork.Response<T>) in
semaphore.signal()
completion?(response)
}
semaphore.wait()
}
///
requestOperation.addDependency(tokenOperation)
operationQueue.addOperation(requestOperation)
}
}
return
}
do {
let tempData = try response.mapString()
nrPrint(message: parameters.parameters)
nrPrint(message: parameters.path)
let response: NRNetwork.Response<T> = _deserialize(data: tempData)
if !response.isSuccess{
if parameters.isToast {
DispatchQueue.main.async {
NRToast.show(text: response.msg)
}
}
}
completion?(response)
} catch {
var res = NRNetwork.Response<T>()
res.code = -1
if parameters.isToast {
DispatchQueue.main.async {
NRToast.show(text: "Error".localized)
}
}
completion?(res)
}
case .failure(let error):
nrPrint(message: error)
var res = NRNetwork.Response<T>()
res.code = -1
if parameters.isToast {
DispatchQueue.main.async {
NRToast.show(text: "reader_network_error".localized)
}
}
completion?(res)
break
}
}
///
static private func _deserialize<T>(data: String) -> NRNetwork.Response<T> {
var response: NRNetwork.Response<T>?
let decrypted = NRResponseCryptor.decrypt(data: data)
nrPrint(message: decrypted)
response = NRNetwork.Response<T>.deserialize(from: decrypted)
response?.rawData = decrypted
if let response = response {
return response
} else {
var response = NRNetwork.Response<T>()
response.code = -1
response.msg = "Error".localized
return response
}
}
}
extension NRNetwork {
///token
static func requestToken(completer: ((_ token: NRLoginToken?) -> Void)?) {
guard self.tokenOperation == nil else {
completer?(nil)
return
}
self.tokenOperation = BlockOperation(block: {
let semaphore = DispatchSemaphore(value: 0)
let param = NRNetwork.Parameters(path: "/customer/register")
DispatchQueue.main.async {
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<NRLoginToken>) in
if let token = response.data {
NRLoginManager.manager.setAccountToken(token)
}
do { semaphore.signal() }
self.tokenOperation = nil
completer?(response.data)
}
}
semaphore.wait()
})
operationQueue.addOperation(self.tokenOperation!)
}
}