148 lines
4.3 KiB
Swift
148 lines
4.3 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
|
|
import CoreFoundation
|
|
|
|
#if !swift(>=4.2)
|
|
// Swift 3/4 compatibility
|
|
fileprivate extension RunLoopMode {
|
|
static let `default` = defaultRunLoopMode
|
|
}
|
|
#endif
|
|
|
|
#if os(Linux)
|
|
/// Currently unavailable in Linux
|
|
/// Remove comments and build to fix
|
|
/// Currently kConstants for CFSockets don't exist in linux and not all have been moved
|
|
/// to property structs yet
|
|
#else
|
|
// Must inherit NSObject for NSStreamDelegate conformance
|
|
public class TStreamTransport : NSObject, TTransport {
|
|
public var input: InputStream? = nil
|
|
public var output: OutputStream? = nil
|
|
|
|
public init(inputStream: InputStream?, outputStream: OutputStream?) {
|
|
input = inputStream
|
|
output = outputStream
|
|
}
|
|
|
|
public convenience init(inputStream: InputStream?) {
|
|
self.init(inputStream: inputStream, outputStream: nil)
|
|
}
|
|
|
|
public convenience init(outputStream: OutputStream?) {
|
|
self.init(inputStream: nil, outputStream: outputStream)
|
|
}
|
|
|
|
deinit {
|
|
close()
|
|
}
|
|
|
|
public func readAll(size: Int) throws -> Data {
|
|
guard let input = input else {
|
|
throw TTransportError(error: .unknown)
|
|
}
|
|
|
|
var read = Data()
|
|
while read.count < size {
|
|
var buffer = Array<UInt8>(repeating: 0, count: size - read.count)
|
|
|
|
let bytesRead = buffer.withUnsafeMutableBufferPointer { bufferPtr in
|
|
return input.read(bufferPtr.baseAddress!, maxLength: size - read.count)
|
|
}
|
|
|
|
if bytesRead <= 0 {
|
|
throw TTransportError(error: .notOpen)
|
|
}
|
|
read.append(Data(buffer))
|
|
}
|
|
return read
|
|
}
|
|
|
|
public func read(size: Int) throws -> Data {
|
|
guard let input = input else {
|
|
throw TTransportError(error: .unknown)
|
|
}
|
|
|
|
var read = Data()
|
|
while read.count < size {
|
|
var buffer = Array<UInt8>(repeating: 0, count: size - read.count)
|
|
let bytesRead = buffer.withUnsafeMutableBufferPointer {
|
|
input.read($0.baseAddress!, maxLength: size - read.count)
|
|
}
|
|
|
|
if bytesRead <= 0 {
|
|
break
|
|
}
|
|
|
|
read.append(Data(buffer))
|
|
}
|
|
return read
|
|
}
|
|
|
|
public func write(data: Data) throws {
|
|
guard let output = output else {
|
|
throw TTransportError(error: .unknown)
|
|
}
|
|
|
|
var bytesWritten = 0
|
|
while bytesWritten < data.count {
|
|
bytesWritten = data.withUnsafeBytes { output.write($0.bindMemory(to: UInt8.self).baseAddress!, maxLength: data.count) }
|
|
if bytesWritten == -1 {
|
|
throw TTransportError(error: .notOpen)
|
|
} else if bytesWritten == 0 {
|
|
throw TTransportError(error: .endOfFile)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public func flush() throws {
|
|
return
|
|
}
|
|
|
|
public func close() {
|
|
|
|
if input != nil {
|
|
// Close and reset inputstream
|
|
if let cf: CFReadStream = input {
|
|
CFReadStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue)
|
|
}
|
|
|
|
input?.delegate = nil
|
|
input?.close()
|
|
input?.remove(from: .current, forMode: .default)
|
|
input = nil
|
|
}
|
|
|
|
if output != nil {
|
|
// Close and reset output stream
|
|
if let cf: CFWriteStream = output {
|
|
CFWriteStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue)
|
|
}
|
|
output?.delegate = nil
|
|
output?.close()
|
|
output?.remove(from: .current, forMode: .default)
|
|
output = nil
|
|
}
|
|
}
|
|
}
|
|
#endif
|