@@ -9,6 +9,7 @@ import SwiftyJSON
99import SwiftyXMLParser
1010
1111typealias OCSPath = Array < String >
12+
1213protocol DataSubscriptable {
1314 subscript( path: OCSPath ) -> Self { get }
1415}
@@ -34,6 +35,7 @@ extension OCSPath {
3435
3536public struct NKError : Error , Equatable , Sendable {
3637 static let internalError = - 9999
38+
3739 public let errorCode : Int
3840 public let errorDescription : String
3941 public let error : Error
@@ -57,91 +59,180 @@ public struct NKError: Error, Equatable, Sendable {
5759
5860 public static let success = NKError ( errorCode: 0 , errorDescription: " " )
5961
62+ /// Returns a localized user-facing description for a known error code.
63+ ///
64+ /// - Parameter code: The HTTP, URL loading, WebDAV, OCS, or internal error code.
65+ /// - Returns: A localized description when the code is known, otherwise `nil`.
6066 public static func getErrorDescription( for code: Int ) -> String ? {
6167 switch code {
6268 case - 9999 :
6369 return NSLocalizedString ( " _internal_server_ " , value: " Internal error " , comment: " " )
70+
6471 case - 1001 :
6572 return NSLocalizedString ( " _time_out_ " , value: " Time out " , comment: " " )
73+
6674 case - 1004 :
6775 return NSLocalizedString ( " _server_down_ " , value: " The server appears to be down " , comment: " " )
76+
6877 case - 1005 :
6978 return NSLocalizedString ( " _not_possible_connect_to_server_ " , value: " It is not possible to connect to the server at this time " , comment: " " )
79+
7080 case - 1009 :
7181 return NSLocalizedString ( " _not_connected_internet_ " , value: " Server connection error " , comment: " " )
82+
7283 case - 1011 :
7384 return NSLocalizedString ( " _error_ " , value: " Generic error " , comment: " " )
85+
7486 case - 1012 :
7587 return NSLocalizedString ( " _not_possible_connect_to_server_ " , value: " It is not possible to connect to the server at this time " , comment: " " )
88+
7689 case - 1013 :
7790 return NSLocalizedString ( " _user_authentication_required_ " , value: " User authentication required " , comment: " " )
91+
7892 case - 1200 :
7993 return NSLocalizedString ( " _ssl_connection_error_ " , value: " Connection SSL error, try again " , comment: " " )
94+
8095 case - 1202 :
8196 return NSLocalizedString ( " _ssl_certificate_untrusted_ " , value: " The certificate for this server is invalid " , comment: " " )
82- case 0 : return " "
97+
98+ case 0 :
99+ return " "
100+
83101 case 101 :
84102 return NSLocalizedString ( " _forbidden_characters_from_server_ " , value: " The name contains at least one invalid character " , comment: " " )
103+
104+ case 200 :
105+ return NSLocalizedString ( " _transfer_stopped_ " , value: " Transfer stopped " , comment: " " )
106+
107+ case 207 :
108+ return NSLocalizedString ( " _error_multi_status_ " , value: " WebDAV multistatus " , comment: " " )
109+
85110 case 304 :
86111 return NSLocalizedString ( " _error_not_modified_ " , value: " Resource not modified " , comment: " " )
112+
87113 case 400 :
88114 return NSLocalizedString ( " _bad_request_ " , value: " Bad request " , comment: " " )
115+
89116 case 401 :
90117 return NSLocalizedString ( " _unauthorized_ " , value: " Unauthorized " , comment: " " )
118+
91119 case 403 :
92120 return NSLocalizedString ( " _error_not_permission_ " , value: " You don't have permission to complete the operation " , comment: " " )
121+
93122 case 404 :
94123 return NSLocalizedString ( " _error_not_found_ " , value: " The requested resource could not be found " , comment: " " )
124+
95125 case 405 :
96126 return NSLocalizedString ( " _method_not_allowed_ " , value: " The requested method is not supported " , comment: " " )
127+
128+ case 408 :
129+ return NSLocalizedString ( " _request_timeout_ " , value: " Request timeout " , comment: " " )
130+
97131 case 409 :
98132 return NSLocalizedString ( " _error_conflict_ " , value: " The request could not be completed due to a conflict with the current state of the resource " , comment: " " )
133+
99134 case 412 :
100135 return NSLocalizedString ( " _error_precondition_ " , value: " The server does not meet one of the preconditions that the requester " , comment: " " )
136+
101137 case 413 :
102138 return NSLocalizedString ( " _request_entity_too_large_ " , value: " The file is too large " , comment: " " )
139+
103140 case 417 :
104141 return NSLocalizedString ( " _expectation_failed_ " , value: " Expectation failed " , comment: " " )
142+
105143 case 423 :
106144 return NSLocalizedString ( " _webdav_locked_ " , value: " WebDAV Locked: Trying to access locked resource " , comment: " " )
145+
146+ case 429 :
147+ return NSLocalizedString ( " _too_many_requests_ " , value: " Too many requests " , comment: " " )
148+
107149 case 500 :
108150 return NSLocalizedString ( " _internal_server_ " , value: " Internal server error " , comment: " " )
151+
152+ case 502 :
153+ return NSLocalizedString ( " _bad_gateway_ " , value: " Bad gateway " , comment: " " )
154+
109155 case 503 :
110156 return NSLocalizedString ( " _server_maintenance_mode_ " , value: " Server is currently in maintenance mode " , comment: " " )
157+
158+ case 504 :
159+ return NSLocalizedString ( " _gateway_timeout_ " , value: " Gateway timeout " , comment: " " )
160+
111161 case 507 :
112162 return NSLocalizedString ( " _user_over_quota_ " , value: " Storage quota is reached " , comment: " " )
113- case 200 :
114- return NSLocalizedString ( " _transfer_stopped_ " , value: " Transfer stopped " , comment: " " )
115- case 207 :
116- return NSLocalizedString ( " _error_multi_status_ " , value: " WebDAV multistatus " , comment: " " )
163+
117164 case NSURLErrorCannotDecodeContentData:
118165 return NSLocalizedString ( " _invalid_data_format_ " , value: " Invalid data format " , comment: " " )
166+
119167 default :
120168 return nil
121169 }
122170 }
123171
172+ /// Returns a clean fallback description for an HTTP status code.
173+ ///
174+ /// This method intentionally avoids `HTTPURLResponse.description`, because that value contains
175+ /// the full response dump, including URL and headers, and is not suitable for UI.
176+ ///
177+ /// - Parameter statusCode: The HTTP status code.
178+ /// - Returns: A clean fallback description.
179+ private static func httpFallbackDescription( for statusCode: Int ) -> String {
180+ let description = HTTPURLResponse . localizedString ( forStatusCode: statusCode)
181+
182+ if description. isEmpty {
183+ return NSLocalizedString ( " _error_ " , value: " Generic error " , comment: " " )
184+ }
185+
186+ return description
187+ }
188+
189+ /// Creates an `NKError` from an explicit code and description.
190+ ///
191+ /// - Parameters:
192+ /// - errorCode: The error code.
193+ /// - errorDescription: The user-facing error description.
194+ /// - responseData: Optional raw response data associated with the error.
124195 public init ( errorCode: Int = 0 , errorDescription: String = " " , responseData: Data ? = nil ) {
125196 self . errorCode = errorCode
126197 self . errorDescription = errorDescription
127- self . error = NSError ( domain: NSCocoaErrorDomain, code: self . errorCode, userInfo: [ NSLocalizedDescriptionKey: self . errorDescription] )
198+ self . error = NSError (
199+ domain: NSCocoaErrorDomain,
200+ code: self . errorCode,
201+ userInfo: [ NSLocalizedDescriptionKey: self . errorDescription]
202+ )
128203 self . responseData = responseData
129204 }
130205
206+ /// Creates an `NKError` from a generic Swift `Error`.
207+ ///
208+ /// - Parameters:
209+ /// - error: The source error.
210+ /// - responseData: Optional raw response data associated with the error.
131211 public init ( error: Error , responseData: Data ? = nil ) {
132212 self . errorCode = error. _code
133213 self . errorDescription = error. localizedDescription
134214 self . error = error
135215 self . responseData = responseData
136216 }
137217
218+ /// Creates an `NKError` from an `NSError`.
219+ ///
220+ /// - Parameters:
221+ /// - nsError: The source `NSError`.
222+ /// - responseData: Optional raw response data associated with the error.
138223 public init ( nsError: NSError , responseData: Data ? = nil ) {
139224 self . errorCode = nsError. code
140225 self . errorDescription = nsError. localizedDescription
141226 self . error = nsError
142227 self . responseData = responseData
143228 }
144229
230+ /// Creates an `NKError` from an OCS JSON response.
231+ ///
232+ /// - Parameters:
233+ /// - rootJson: The parsed JSON response.
234+ /// - fallbackStatusCode: The fallback HTTP status code used when the OCS status code is missing.
235+ /// - responseData: Optional raw response data associated with the error.
145236 public init ( rootJson: JSON , fallbackStatusCode: Int ? , responseData: Data ? = nil ) {
146237 let statuscode = rootJson [ . ocsMetaCode] . int ?? fallbackStatusCode ?? NSURLErrorCannotDecodeContentData
147238 errorCode = 200 ..< 300 ~= statuscode ? 0 : statuscode
@@ -151,23 +242,54 @@ public struct NKError: Error, Equatable, Sendable {
151242 } else if let metaMsg = rootJson [ . ocsMetaMsg] . string {
152243 errorDescription = metaMsg
153244 } else {
154- errorDescription = NKError . getErrorDescription ( for: statuscode) ?? " "
245+ errorDescription = NKError . getErrorDescription ( for: statuscode) ?? NKError . httpFallbackDescription ( for : statuscode )
155246 }
247+
156248 self . responseData = responseData
157- self . error = NSError ( domain: NSCocoaErrorDomain, code: self . errorCode, userInfo: [ NSLocalizedDescriptionKey: self . errorDescription] )
249+ self . error = NSError (
250+ domain: NSCocoaErrorDomain,
251+ code: self . errorCode,
252+ userInfo: [ NSLocalizedDescriptionKey: self . errorDescription]
253+ )
158254 }
159255
256+ /// Creates an `NKError` from an HTTP status code.
257+ ///
258+ /// - Parameters:
259+ /// - statusCode: The HTTP status code.
260+ /// - fallbackDescription: A clean fallback description used when the status code is unknown.
261+ /// - responseData: Optional raw response data associated with the error.
160262 public init ( statusCode: Int , fallbackDescription: String , responseData: Data ? = nil ) {
161263 self . errorCode = statusCode
162- self . errorDescription = " \( statusCode) : " + ( NKError . getErrorDescription ( for: statusCode) ?? fallbackDescription)
163- self . error = NSError ( domain: NSCocoaErrorDomain, code: self . errorCode, userInfo: [ NSLocalizedDescriptionKey: self . errorDescription] )
264+
265+ let description = NKError . getErrorDescription ( for: statusCode) ?? fallbackDescription
266+ self . errorDescription = " \( statusCode) : \( description) "
267+
268+ self . error = NSError (
269+ domain: NSCocoaErrorDomain,
270+ code: self . errorCode,
271+ userInfo: [ NSLocalizedDescriptionKey: self . errorDescription]
272+ )
273+
164274 self . responseData = responseData
165275 }
166276
277+ /// Creates an `NKError` from an HTTP response.
278+ ///
279+ /// - Parameter httpResponse: The source HTTP response.
167280 init ( httpResponse: HTTPURLResponse ) {
168- self . init ( statusCode: httpResponse. statusCode, fallbackDescription: httpResponse. description)
281+ self . init (
282+ statusCode: httpResponse. statusCode,
283+ fallbackDescription: Self . httpFallbackDescription ( for: httpResponse. statusCode)
284+ )
169285 }
170286
287+ /// Creates an `NKError` from an OCS or WebDAV XML response.
288+ ///
289+ /// - Parameters:
290+ /// - xmlData: The raw XML response data.
291+ /// - fallbackStatusCode: The fallback HTTP status code used when the OCS status code is missing.
292+ /// - responseData: Optional raw response data associated with the error.
171293 init ( xmlData: Data , fallbackStatusCode: Int ? = nil , responseData: Data ? = nil ) {
172294 let xml = XML . parse ( xmlData)
173295 let statuscode = xml [ . ocsMetaCode] . int ?? fallbackStatusCode ?? NSURLErrorCannotDecodeContentData
@@ -180,18 +302,33 @@ public struct NKError: Error, Equatable, Sendable {
180302 } else if let metaMsg = xml [ . ocsXMLMsg] . text {
181303 errorDescription = metaMsg
182304 } else {
183- errorDescription = NKError . getErrorDescription ( for: statuscode) ?? " "
305+ errorDescription = NKError . getErrorDescription ( for: statuscode) ?? NKError . httpFallbackDescription ( for : statuscode )
184306 }
307+
185308 self . responseData = responseData
186- self . error = NSError ( domain: NSCocoaErrorDomain, code: self . errorCode, userInfo: [ NSLocalizedDescriptionKey: self . errorDescription] )
309+ self . error = NSError (
310+ domain: NSCocoaErrorDomain,
311+ code: self . errorCode,
312+ userInfo: [ NSLocalizedDescriptionKey: self . errorDescription]
313+ )
187314 }
188315
316+ /// Creates an `NKError` from an Alamofire response and optional Alamofire error.
317+ ///
318+ /// - Parameters:
319+ /// - error: The Alamofire error, if available.
320+ /// - afResponse: The Alamofire response.
321+ /// - responseData: Optional raw response data associated with the error.
189322 public init < T: AFResponse > ( error: AFError ? , afResponse: T , responseData: Data ? = nil ) {
190323 if let errorCode = afResponse. response? . statusCode {
191324 guard let dataResponse = afResponse as? Alamofire . DataResponse < T . Success , T . Failure > ,
192325 let errorData = dataResponse. data
193326 else {
194- self . init ( statusCode: errorCode, fallbackDescription: afResponse. response? . description ?? " " , responseData: responseData)
327+ self . init (
328+ statusCode: errorCode,
329+ fallbackDescription: Self . httpFallbackDescription ( for: errorCode) ,
330+ responseData: responseData
331+ )
195332 return
196333 }
197334
@@ -205,14 +342,19 @@ public struct NKError: Error, Equatable, Sendable {
205342 switch error {
206343 case . createUploadableFailed( let error as NSError ) :
207344 self . init ( nsError: error, responseData: responseData)
345+
208346 case . createURLRequestFailed( let error as NSError ) :
209347 self . init ( nsError: error, responseData: responseData)
348+
210349 case . requestAdaptationFailed( let error as NSError ) :
211350 self . init ( nsError: error, responseData: responseData)
351+
212352 case . sessionInvalidated( let error as NSError ) :
213353 self . init ( nsError: error, responseData: responseData)
354+
214355 case . sessionTaskFailed( let error as NSError ) :
215356 self . init ( nsError: error, responseData: responseData)
357+
216358 default :
217359 self . init ( error: error, responseData: responseData)
218360 }
@@ -227,8 +369,9 @@ public struct NKError: Error, Equatable, Sendable {
227369
228370 public static func == ( lhs: NKError , rhs: NKError ? ) -> Bool {
229371 if let rhs {
230- return lhs == rhs;
372+ return lhs == rhs
231373 }
374+
232375 return false
233376 }
234377}
0 commit comments