122 lines
3.2 KiB
Swift
122 lines
3.2 KiB
Swift
/*
|
|
* 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()
|
|
}
|
|
}
|