| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import Foundation |
| |
| public class TFramedTransport: TTransport { |
| public static let headerSize = 4 |
| public static let initFrameSize = 1024 |
| private static let defaultMaxLength = 16384000 |
| |
| public var transport: TTransport |
| private var writeBuffer = Data() |
| |
| private var maxSize = TFramedTransport.defaultMaxLength |
| private var remainingBytes = 0 |
| |
| |
| public init(transport: TTransport, maxSize: Int) { |
| self.transport = transport |
| self.maxSize = maxSize |
| } |
| |
| public convenience init(transport: TTransport) { |
| self.init(transport: transport, maxSize: TFramedTransport.defaultMaxLength) |
| } |
| |
| func readHeader() throws { |
| let read = try transport.readAll(size: TFramedTransport.headerSize) |
| remainingBytes = Int(decodeFrameSize(data: read)) |
| } |
| |
| /// Mark: - TTransport |
| |
| public func read(size: Int) throws -> Data { |
| while (remainingBytes <= 0) { |
| try readHeader() |
| } |
| |
| let toRead = min(size, remainingBytes) |
| |
| if toRead < 0 { |
| try close() |
| throw TTransportError(error: .negativeSize, |
| message: "Read a negative frame size (\(toRead))!") |
| } |
| |
| if toRead > maxSize { |
| try close() |
| throw TTransportError(error: .sizeLimit(limit: maxSize, got: toRead)) |
| } |
| |
| let data = try transport.readAll(size: toRead) |
| remainingBytes -= data.count |
| return data |
| } |
| |
| public func flush() throws { |
| // copy buffer and reset |
| let buff = writeBuffer |
| writeBuffer = Data() |
| |
| let frameSize = encodeFrameSize(size: UInt32(buff.count)) |
| |
| try transport.write(data: frameSize) |
| try transport.write(data: buff) |
| try transport.flush() |
| } |
| |
| public func write(data: Data) throws { |
| writeBuffer.append(data) |
| } |
| |
| |
| |
| private func encodeFrameSize(size: UInt32) -> Data { |
| var data = Data() |
| data.append(Data([UInt8(0xff & (size >> 24))])) |
| data.append(Data([UInt8(0xff & (size >> 16))])) |
| data.append(Data([UInt8(0xff & (size >> 8))])) |
| data.append(Data([UInt8(0xff & (size))])) |
| |
| return data |
| } |
| |
| private func decodeFrameSize(data: Data) -> UInt32 { |
| var size: UInt32 |
| size = (UInt32(data[0] & 0xff) << 24) |
| size |= (UInt32(data[1] & 0xff) << 16) |
| size |= (UInt32(data[2] & 0xff) << 8) |
| size |= (UInt32(data[3] & 0xff)) |
| return size |
| } |
| |
| public func close() throws { |
| try transport.close() |
| } |
| |
| public func open() throws { |
| try transport.open() |
| } |
| |
| public func isOpen() throws -> Bool { |
| return try transport.isOpen() |
| } |
| } |