1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20 import Foundation 21 22 public struct TProtocolError : TError { 23 public init() { } 24 25 public enum Code : TErrorCode { 26 case unknown 27 case invalidData 28 case negativeSize 29 case sizeLimit(limit: Int, got: Int) 30 case badVersion(expected: String, got: String) 31 case notImplemented 32 case depthLimit 33 34 public var thriftErrorCode: Int { 35 switch self { 36 case .unknown: return 0 37 case .invalidData: return 1 38 case .negativeSize: return 2 39 case .sizeLimit: return 3 40 case .badVersion: return 4 41 case .notImplemented: return 5 42 case .depthLimit: return 6 43 } 44 45 } 46 public var description: String { 47 switch self { 48 case .unknown: return "Unknown TProtocolError" 49 case .invalidData: return "Invalid Data" 50 case .negativeSize: return "Negative Size" 51 case .sizeLimit(let limit, let got): 52 return "Message exceeds size limit of \(limit) (received: \(got)" 53 case .badVersion(let expected, let got): 54 return "Bad Version. (Expected: \(expected), Got: \(got)" 55 case .notImplemented: return "Not Implemented" 56 case .depthLimit: return "Depth Limit" 57 } 58 } 59 } 60 61 public enum ExtendedErrorCode : TErrorCode { 62 case unknown 63 case missingRequiredField(fieldName: String) 64 case unexpectedType(type: TType) 65 case mismatchedProtocol(expected: String, got: String) 66 public var thriftErrorCode: Int { 67 switch self { 68 case .unknown: return 1000 69 case .missingRequiredField: return 1001 70 case .unexpectedType: return 1002 71 case .mismatchedProtocol: return 1003 72 } 73 } 74 public var description: String { 75 switch self { 76 case .unknown: return "Unknown TProtocolExtendedError" 77 case .missingRequiredField(let fieldName): return "Missing Required Field: \(fieldName)" 78 case .unexpectedType(let type): return "Unexpected Type \(type.self)" 79 case .mismatchedProtocol(let expected, let got): return "Mismatched Protocol. (Expected: \(expected), got \(got))" 80 } 81 } 82 } 83 84 public var extendedError: ExtendedErrorCode? = nil 85 86 public init(error: Code = .unknown, 87 message: String? = nil, 88 extendedError: ExtendedErrorCode? = nil) { 89 self.error = error 90 self.message = message 91 self.extendedError = extendedError 92 } 93 94 /// Mark: TError 95 public var error: Code = .unknown 96 public var message: String? = nil 97 public static var defaultCase: Code { return .unknown } 98 99 public var description: String { 100 var out = "\(TProtocolError.self): (\(error.thriftErrorCode) \(error.description)\n" 101 if let extendedError = extendedError { 102 out += "TProtocolExtendedError (\(extendedError.thriftErrorCode)): \(extendedError.description)" 103 } 104 if let message = message { 105 out += "Message: \(message)" 106 } 107 return out 108 } 109 } 110 111 112 /// Wrapper for Transport errors in Protocols. Inspired by Thrift-Cocoa PROTOCOL_TRANSPORT_ERROR 113 /// macro. Modified to be more Swift-y. Catches any TError thrown within the block and 114 /// rethrows a given TProtocolError, the original error's description is appended to the new 115 /// TProtocolError's message. sourceFile, sourceLine, sourceMethod are auto-populated and should 116 /// be ignored when calling. 117 /// 118 /// - parameter error: TProtocolError to throw if the block throws 119 /// - parameter sourceFile: throwing file, autopopulated 120 /// - parameter sourceLine: throwing line, autopopulated 121 /// - parameter sourceMethod: throwing method, autopopulated 122 /// - parameter block: throwing block 123 /// 124 /// - throws: TProtocolError Default is TProtocolError.ErrorCode.unknown. Underlying 125 /// error's description appended to TProtocolError.message 126 func ProtocolTransportTry(error: TProtocolError = TProtocolError(), 127 sourceFile: String = #file, 128 sourceLine: Int = #line, 129 sourceMethod: String = #function, 130 block: () throws -> ()) throws { 131 // Need mutable copy 132 var error = error 133 do { 134 try block() 135 } catch let err as TError { 136 var message = error.message ?? "" 137 message += "\nFile: \(sourceFile)\n" 138 message += "Line: \(sourceLine)\n" 139 message += "Method: \(sourceMethod)" 140 message += "\nOriginal Error:\n" + err.description 141 error.message = message 142 throw error 143 } 144 } 145 146 147