Thrift Swift 库

许可证

根据 Apache 软件基金会(ASF)的一个或多个贡献者许可协议获得许可。有关版权所有权的更多信息,请参见随本作品分发的 NOTICE 文件。 ASF 根据 Apache 许可证 2.0 版(“许可证”)向您授予本文件的许可;除非遵守许可证,否则您不得使用本文件。您可以在以下位置获得许可证副本:

https://apache.ac.cn/licenses/LICENSE-2.0

除非适用法律要求或书面同意,否则软件是按“原样”分发的,没有任何形式的明示或暗示的担保或条件。 有关许可证下特定权限和限制的完整信息,请参阅许可证。

FiscalNote, Inc 提供

构建

swift build

测试

swift test

安装库

Cocoapods

将以下内容添加到您的 podfile 中

    pod 'Thrift-swift3', :git => 'git@github.com:apache/thrift.git', :branch => 'master'
SPM

不幸的是,由于 SPM 的一些限制,Package manifest 和 Sources 目录必须位于项目的根目录中。 为了暂时解决这个问题,您可以使用这个镜像仓库。 将以下内容添加到您的 Package.swift 中

dependencies: [
    .Package(url: "https://github.com/apocolipse/Thrift-Swift.git", majorVersion: 1)
]

Thrift 编译器

您可以使用以下命令为 Swift 3 编译 IDL 源代码

thrift --gen swift thrift_file

客户端示例

let transport = TSocketTransport(hostname: "localhost", port: 9090)!

//  var proto = TCompactProtocol(transport: transport)
let proto = TBinaryProtocol(on: transport)
//  var client = HermesClient(inoutProtocol: proto)
let client = ThriftTestClient(inoutProtocol: proto)
do {
    try client.testVoid()
} catch let error {
    print("\(error)")
}

库说明

func readString() throws -> String
func writeString(_ val: String) throws

已被重命名以消除冗余单词

func read() throws -> String
func write(_ val: String) throws

生成器说明

生成器标志

标志 描述
async_clients 生成通过块语法异步调用的客户端。 异步类附加 _Async
no_strict* 生成非严格结构体
debug_descriptions 允许使用 debugDescription,以便应用程序可以通过类别/扩展添加描述
log_unexpected 每次遇到意外的字段 ID 或类型时都记录。
safe_enums 生成具有未知 case 的枚举类型,以处理未指定的值,而不是抛出序列化错误

*大多数 thrift 库允许 Structs 的空初始化,使用 nil/null/None(Python 和 Node 生成器)初始化 required 字段。 另一方面,Swift 要求初始化程序初始化所有非 Optional 字段,因此 Swift 3 生成器不提供默认值(与 Swift 2/Cocoa 生成器不同)。 在其他语言中,这允许在标记为 required 的字段中发送 NULL 值,因此将在尝试验证字段的 Swift 客户端中抛出错误。 此处的 no_strict 选项将忽略验证检查,并且行为类似于 Swift2/Cocoa 生成器,并使用空初始化程序初始化必需字段(如果可能)。

已实现什么

传输
协议
生成器

带有 Perfect 的示例 HTTP 服务器

import PerfectLib
import PerfectHTTP
import PerfectHTTPServer
import Dispatch

let logQueue = DispatchQueue(label: "log", qos: .background, attributes: .concurrent)
let pQueue = DispatchQueue(label: "log", qos: .userInitiated, attributes: .concurrent)


class TPerfectServer<InProtocol: TProtocol, OutProtocol: TProtocol> {

 private var server = HTTPServer()
 private var processor: TProcessor

 init(address: String? = nil,
      path: String? = nil,
      port: Int,
      processor: TProcessor,
      inProtocol: InProtocol.Type,
      outProtocol: OutProtocol.Type) throws {

   self.processor = processor

   if let address = address {
     server.serverAddress = address
   }
   server.serverPort = UInt16(port)

   var routes = Routes()
   var uri = "/"
   if let path = path {
     uri += path
   }
   routes.add(method: .post, uri: uri) { request, response in
     pQueue.async {
       response.setHeader(.contentType, value: "application/x-thrift")

       let itrans = TMemoryBufferTransport()
       if let bytes = request.postBodyBytes {
         let data = Data(bytes: bytes)
         itrans.reset(readBuffer: data)
       }

       let otrans = TMemoryBufferTransport(flushHandler: { trans, buff in
         let array = buff.withUnsafeBytes {
           Array<UInt8>(UnsafeBufferPointer(start: $0, count: buff.count))
         }
         response.status = .ok
         response.setBody(bytes: array)
         response.completed()
       })

       let inproto = InProtocol(on: itrans)
       let outproto = OutProtocol(on: otrans)

       do {
         try processor.process(on: inproto, outProtocol: outproto)
         try otrans.flush()
       } catch {
         response.status = .badRequest
         response.completed()
       }
     }
   }
   server.addRoutes(routes)
 }

 func serve() throws {
   try server.start()
 }
}

用法示例

class ServiceHandler : Service {
    ...
}
let server = try? TPerfectServer(port: 9090,
                                processor: ServiceProcessor(service: ServiceHandler()),
                                inProtocol: TBinaryProtocol.self,
                                outProtocol: TBinaryProtocol.self)

try? server?.serve()