-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSTNetworkTypes.swift
More file actions
314 lines (269 loc) · 9.27 KB
/
STNetworkTypes.swift
File metadata and controls
314 lines (269 loc) · 9.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
//
// STNetworkTypes.swift
// STBaseProject
//
// Created by 寒江孤影 on 2018/12/10.
//
import Foundation
import UIKit
// MARK: - HTTP 方法枚举
public enum STHTTPMethod: String {
case connect = "CONNECT"
case delete = "DELETE"
case get = "GET"
case head = "HEAD"
case options = "OPTIONS"
case patch = "PATCH"
case post = "POST"
case put = "PUT"
case query = "QUERY"
case trace = "TRACE"
}
// MARK: - 请求配置
public struct STRequestConfig: Sendable {
public var retryCount: Int = 0
public var retryDelay: TimeInterval = 1.0
public var allowsCellularAccess: Bool = true
public var httpShouldHandleCookies: Bool = true
public var httpShouldUsePipelining: Bool = true
public var timeoutInterval: TimeInterval = 30
public var cachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy
public var networkServiceType: URLRequest.NetworkServiceType = .default
public var showLoading: Bool = true
public var showError: Bool = true
public var enableEncryption: Bool = false
public var encryptionKey: String?
public var enableRequestSigning: Bool = false
public var signingSecret: String?
public init(
retryCount: Int = 0,
retryDelay: TimeInterval = 1.0,
timeoutInterval: TimeInterval = 30,
allowsCellularAccess: Bool = true,
httpShouldHandleCookies: Bool = true,
httpShouldUsePipelining: Bool = true,
networkServiceType: URLRequest.NetworkServiceType = .default,
cachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,
showLoading: Bool = true,
showError: Bool = true,
enableEncryption: Bool = false,
encryptionKey: String? = nil,
enableRequestSigning: Bool = false,
signingSecret: String? = nil) {
self.cachePolicy = cachePolicy
self.retryCount = retryCount
self.retryDelay = retryDelay
self.timeoutInterval = timeoutInterval
self.networkServiceType = networkServiceType
self.allowsCellularAccess = allowsCellularAccess
self.httpShouldHandleCookies = httpShouldHandleCookies
self.httpShouldUsePipelining = httpShouldUsePipelining
self.showLoading = showLoading
self.showError = showError
self.enableEncryption = enableEncryption
self.encryptionKey = encryptionKey
self.enableRequestSigning = enableRequestSigning
self.signingSecret = signingSecret
}
}
// MARK: - 请求头管理
public struct STRequestHeaders {
private var headers: [String: String]
public init(headers: [String: String] = [:]) {
self.headers = headers
}
public mutating func st_setHeader(_ value: String, forKey key: String) {
headers[key] = value
}
public mutating func st_setHeaders(_ newHeaders: [String: String]) {
for (key, value) in newHeaders {
headers[key] = value
}
}
public mutating func st_removeHeader(forKey key: String) {
headers.removeValue(forKey: key)
}
public mutating func st_clearHeaders() {
headers.removeAll()
}
public func st_getHeaders() -> [String: String] {
return headers
}
/// 设置自定义认证方式
public mutating func st_setAuthorization(_ token: String, type: STAuthorizationType) {
switch type {
case .bearer:
st_setHeader("Bearer \(token)", forKey: "Authorization")
case .basic:
st_setHeader("Basic \(token)", forKey: "Authorization")
case .custom(let prefix):
st_setHeader("\(prefix) \(token)", forKey: "Authorization")
case .tokenOnly:
st_setHeader(token, forKey: "Authorization")
}
}
/// 设置自定义认证头
public mutating func st_setCustomAuthorization(_ value: String) {
st_setHeader(value, forKey: "Authorization")
}
public mutating func st_setContentType(_ contentType: String) {
st_setHeader(contentType, forKey: "Content-Type")
}
public mutating func st_setAccept(_ accept: String) {
st_setHeader(accept, forKey: "Accept")
}
public mutating func st_setUserAgent(_ userAgent: String) {
st_setHeader(userAgent, forKey: "User-Agent")
}
}
// MARK: - HTTP 响应基础协议
public protocol STHTTPResponseProtocol {
var data: Data? { get }
var response: URLResponse? { get }
var error: Error? { get }
}
// MARK: - HTTP 响应扩展
public extension STHTTPResponseProtocol {
var statusCode: Int {
if let httpResponse = response as? HTTPURLResponse {
return httpResponse.statusCode
}
return 0
}
var headers: [String: String] {
if let httpResponse = response as? HTTPURLResponse {
var result: [String: String] = [:]
for (key, value) in httpResponse.allHeaderFields {
if let stringKey = key as? String, let stringValue = value as? String {
result[stringKey] = stringValue
}
}
return result
}
return [:]
}
var isSuccess: Bool {
guard let httpResponse = response as? HTTPURLResponse else { return false }
return httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 && error == nil
}
var isNetworkError: Bool {
return response == nil || error != nil
}
var isHTTPError: Bool {
guard let httpResponse = response as? HTTPURLResponse else { return false }
return httpResponse.statusCode >= 400
}
var hasData: Bool {
return data != nil && !(data?.isEmpty ?? true)
}
var json: Any? {
guard let data = data else { return nil }
return try? JSONSerialization.jsonObject(with: data)
}
var string: String? {
guard let data = data else { return nil }
return String(data: data, encoding: .utf8)
}
}
// MARK: - 统一响应处理
public struct STHTTPResponse: STHTTPResponseProtocol {
public let data: Data?
public let response: URLResponse?
public let error: Error?
public init(data: Data?, response: URLResponse?, error: Error?) {
self.data = data
self.response = response
self.error = error
}
}
// MARK: - 泛型响应处理
public struct STHTTPResponseWithModel<T: Codable>: STHTTPResponseProtocol {
public let data: Data?
public let response: URLResponse?
public let error: Error?
public let model: T?
public init(data: Data?, response: URLResponse?, error: Error?, model: T? = nil) {
self.data = data
self.response = response
self.error = error
self.model = model
}
}
// MARK: - 上传文件
public struct STUploadFile {
public let data: Data
public let name: String // 服务器定义:比如 file, jumped 等等
public let fileName: String
public let mimeType: String
public init(data: Data, name: String, fileName: String, mimeType: String) {
self.data = data
self.name = name
self.fileName = fileName
self.mimeType = mimeType
}
}
// MARK: - 上传进度
public struct STUploadProgress {
public let bytesWritten: Int64
public let totalBytes: Int64
public let progress: Float
public init(bytesWritten: Int64, totalBytes: Int64) {
self.bytesWritten = bytesWritten
self.totalBytes = totalBytes
self.progress = totalBytes > 0 ? Float(bytesWritten) / Float(totalBytes) : 0.0
}
}
// MARK: - 认证类型
public enum STAuthorizationType {
case bearer
case basic
case custom(String) // 自定义前缀,如 "Token"
case tokenOnly // 只发送 token,不加前缀
}
// MARK: - 网络可达性状态
public enum STNetworkReachabilityStatus {
case unknown
case notReachable
case reachableViaWiFi
case reachableViaCellular
}
// MARK: - 请求生命周期状态
public enum STRequestState: Int, Sendable {
case initialized
case resumed
case suspended
case cancelled
case finished
}
// MARK: - 重试结果
public enum STRetryResult {
case retry
case retryWithDelay(TimeInterval)
case doNotRetry
case doNotRetryWithError(Error)
}
// MARK: - 下载进度
public struct STDownloadProgress {
public let bytesWritten: Int64
public let totalBytesWritten: Int64
public let totalBytesExpectedToWrite: Int64
public var fractionCompleted: Double {
guard self.totalBytesExpectedToWrite > 0 else { return 0 }
return Double(self.totalBytesWritten) / Double(self.totalBytesExpectedToWrite)
}
public init(bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
self.bytesWritten = bytesWritten
self.totalBytesWritten = totalBytesWritten
self.totalBytesExpectedToWrite = totalBytesExpectedToWrite
}
}
// MARK: - 下载选项
public struct STDownloadOptions {
public var createIntermediateDirectories: Bool
public var removePreviousFile: Bool
public static let `default` = STDownloadOptions()
public init(createIntermediateDirectories: Bool = true, removePreviousFile: Bool = true) {
self.createIntermediateDirectories = createIntermediateDirectories
self.removePreviousFile = removePreviousFile
}
}