Visual_Novel_iOS/crush/Crush/Src/API/Network/APIProvider.swift

283 lines
10 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// APIProvider.swift
// WoolniOriginalSwift
//
// Created by lyu dong on 2025/7/2.
// Copyright © 2025 lydsnm. All rights reserved.
//
import Foundation
import Moya
import UIKit
let myEndpointClosure = { (target: TargetType) -> Endpoint in
let url = target.baseURL.absoluteString + target.path
var task = target.task
var endpoint = Endpoint(
url: url,
sampleResponseClosure: { .networkResponse(200, target.sampleData) },
method: target.method,
task: task,
httpHeaderFields: target.headers
)
return endpoint
}
let myRequestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in
do {
var request = try endpoint.urlRequest()
request.timeoutInterval = 30
let token = UserCore.shared.token
if !token.isEmpty {
let body = request.httpBody ?? Data()
let str = String(data:body, encoding: .utf8)
if APIConfig.apiLogEnable {
// dlog(" request\(str ?? "")")
}
/*
//
let key = (token + "AHkt5aUUtO6HZPid").md5().uppercased()
let aes = try AES(key: key, iv: "HBB4UO5kEmM4169Z")
let encrypted = try aes.encrypt(str!.bytes)
let result = encrypted.toBase64()
if APIConfig.apiLogEnable {
// dlog(" request\(result)")
}
let dic = ["key": result]
let httpBody = try JSONSerialization.data(withJSONObject: dic, options: .prettyPrinted)
request.httpBody = httpBody
*/
}
done(.success(request))
} catch {
done(.failure(MoyaError.underlying(error, nil)))
}
}
let myNetworkPlugin = NetworkActivityPlugin.init { changeType, _ in
switch changeType {
case .began: dlog("开始请求网络")
case .ended: dlog("结束请求网络")
}
}
public enum ServiceErrorEnum: String, Codable {
case unknow = "-1"
case unknowEmpty = ""
case internalError = "00000000"
case common = "0000"
case sign_usernotexist = "10050002"
case sign_userLoginclientNotExist = "10050003"
case sign_userNotAuthorizedClient = "10050004"
case tokenExpired = "10050005"
case tokenIllegal = "10050006"
case accountIsFrozen = "10010002"
///
case sign_usernotLoggedIn = "10050001"
///
case otherAccountFrozen = "10010005"
///
case newAccount = "10010001"
///
case smscodeIncorrect = "10031001"
///
case smscodeExpired = "10031002"
///
case userExist = "10010004"
case mustNotBeBlank = "00000001"
case imageCheckFailed = "10019999"
///
case imageGenTimeOut = "8006"
/// AI
case imageBrowseButUnlock = "10010011"
/// AI
case aiRoleNotExist = "10010012"
/// Coin
case insufficentCoin = "INSUFFICIENT_BALANCE"
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let rawValue = try container.decode(String.self)
self = ServiceErrorEnum(rawValue: rawValue) ?? .unknow
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .unknow:
// "-999"
try container.encode("unknown")
default:
try container.encode(self.rawValue)
}
}
}
// ResponseData API
struct ResponseData<T: Codable>: Codable {
/// OK or ERROR
let status: String?
let errorCode: ServiceErrorEnum?
let errorMsg: String?
let content: T?
let traceId : String?
}
class ResponseContentPageData<T: Codable>: Codable{
var pn: Int?
var ps: Int?
var datas: [T]?
var tc: Int?
var sortType:String?
var sortField: String?
}
class RequestPageData:Codable {
var pn : Int = 1
var ps : Int = 20
}
public enum ResponseError: Error {
case serviceError(code: ServiceErrorEnum?, msg: String?)
case deserializeError
case networkError
}
//extension ResponseError {
// enum Code: String, Codable {
// case tokenExpired
// case tokenIllegal
// case accountIsFrozen
// case sign_usernotexist
// case sign_usernotLoggedIn
// case sign_userLoginclientNotExist
// case sign_userNotAuthorizedClient
// case newAccount
// case hcaptchaNeed
// case common
// }
//}
extension MoyaProvider {
@discardableResult
public func request<T: Codable>(_ target: Target,
progress _: ProgressBlock? = .none,
modelType TTType: T.Type,
autoShowErrMsg: Bool = true,
completion: @escaping (Result<T?, ResponseError>) -> Void) -> Cancellable {
if APIConfig.apiLogEnable {
// 🗣\(target.method)\n
var paramsLog = ""
if case let .requestParameters(parameters, _) = target.task {
if let jsonData = try? JSONSerialization.data(withJSONObject: parameters, options: [.prettyPrinted]),
let jsonString = String(data: jsonData, encoding: .utf8) {
paramsLog = "\n\(jsonString)"
} else {
paramsLog = "\(parameters)"
}
} else {
paramsLog = "\(target.task)"
}
dlog("headers: \(target.headers ?? ["": ""])\n「🗣Request」path: ⭐️\(target.path)⭐️\n🗣params:\(paramsLog)") //
}
return request(target, completion: { result in
switch result {
case let .success(response):
do {
// 使 JSONDecoder response.data
let decoder = JSONDecoder()
let data = try decoder.decode(ResponseData<T>.self, from: response.data)
// JSON
if APIConfig.apiLogEnable {
let jsonObject = try JSONSerialization.jsonObject(with: response.data)
let jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted)
let jsonString = String(data: jsonData, encoding: .utf8) ?? String(data: response.data, encoding: .utf8) ?? ""
dlog("👉⭐️\(target.path)⭐️ response:\n\(jsonString)")
}
let status = data.status
let code = data.errorCode
let msg = data.errorMsg
if (status ?? "") == "OK" {
let model = data.content
completion(.success(model))
} else {
var toastMsg = autoShowErrMsg
if code == .tokenExpired || code == .tokenIllegal || code == .accountIsFrozen || code == .sign_usernotexist || code == .sign_usernotLoggedIn || code == .sign_userLoginclientNotExist || code == .sign_userNotAuthorizedClient {
//
UserCore.shared.logout()
if let Vc = UIWindow.getTopViewController(), (Vc is CLLoginMainController || Vc is PersonalInformationFillController) {
// do nothing.
} else {
// AppRouter.goBackRootController(jumpIndex: .home) {
// NotificationCenter.post(name: .presentSignInVc, object: nil, userInfo: nil)
// }
NotificationCenter.post(name: .presentSignInVc, object: nil, userInfo: nil)
}
} else if code == .newAccount {
// ToastMsg
toastMsg = false
} else if code == .insufficentCoin {
//
// refresh wallet
toastMsg = false
var handled = false
if let cow = target as? AICowAPI{
switch cow{
case .voiceCallOperate, .voiceAsr2, .voiceTts:
IMAIViewModel.shared.showChatModelInsufficentCoinSheet()
handled = true
default:
break
}
}
if handled == false{
// Sheet
CLPurchase.shared.showIAPBuyCoinSheet()
}
}
if toastMsg, let msgUnpack = msg, msgUnpack.count > 0 {
UIWindow.getTopDisplayWindow()?.makeToast(msgUnpack)
}
dlog("error: code = \(code ?? .common), msg = \(data.errorMsg ?? "业务状态失败")")
completion(.failure(.serviceError(code: code, msg: msg)))
}
} catch {
dlog("⛔️请求成功,但解析失败: \(error), Response\(CodableHelper.jsonString(from: response.data) ?? "x")⛔️")
completion(.failure(.deserializeError))
}
case let .failure(error):
dlog("⛔️ \(target.path) 网络连接失败\(error)")
UIWindow.getTopDisplayWindow()?.makeToast("Internet connection failed")
completion(.failure(.networkError))
}
})
}
}