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