mirror of
https://github.com/samsonjs/SwiftBatteries.git
synced 2026-04-27 15:07:46 +00:00
add LineEmitter class to parse lines from input streams
This commit is contained in:
parent
7012b60ebb
commit
b2313ebfa7
2 changed files with 98 additions and 2 deletions
|
|
@ -1,2 +0,0 @@
|
||||||
import Foundation
|
|
||||||
|
|
||||||
98
Sources/LineEmitter.swift
Normal file
98
Sources/LineEmitter.swift
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public class LineEmitter: NSObject, NSStreamDelegate {
|
||||||
|
|
||||||
|
var endFunc: (() -> ())?
|
||||||
|
|
||||||
|
private let stream: NSInputStream
|
||||||
|
private let lineFunc: (String) -> ()
|
||||||
|
private var buffer = ""
|
||||||
|
|
||||||
|
init(stream: NSInputStream, lineFunc: (String) -> ()) {
|
||||||
|
self.stream = stream
|
||||||
|
self.lineFunc = lineFunc
|
||||||
|
super.init()
|
||||||
|
openStream()
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience init?(path: String, lineFunc: (String) -> ()) {
|
||||||
|
guard let stream = NSInputStream(fileAtPath: path) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
self.init(stream: stream, lineFunc: lineFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func openStream() {
|
||||||
|
stream.delegate = self
|
||||||
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
|
||||||
|
self.stream.scheduleInRunLoop(.currentRunLoop(), forMode: NSDefaultRunLoopMode)
|
||||||
|
self.stream.open()
|
||||||
|
NSRunLoop.currentRunLoop().run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func closeStream() {
|
||||||
|
stream.delegate = nil
|
||||||
|
stream.close()
|
||||||
|
stream.removeFromRunLoop(.currentRunLoop(), forMode: NSDefaultRunLoopMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: NSStreamDelegate methods
|
||||||
|
|
||||||
|
public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
|
||||||
|
switch (eventCode) {
|
||||||
|
case NSStreamEvent.HasBytesAvailable:
|
||||||
|
bufferFromStream()
|
||||||
|
|
||||||
|
case NSStreamEvent.EndEncountered:
|
||||||
|
checkForLastLine()
|
||||||
|
closeStream()
|
||||||
|
|
||||||
|
case NSStreamEvent.ErrorOccurred:
|
||||||
|
print("stream error: \(stream.streamError)")
|
||||||
|
checkForLastLine()
|
||||||
|
closeStream()
|
||||||
|
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func bufferFromStream() {
|
||||||
|
if stream.hasBytesAvailable {
|
||||||
|
let size = 16_384
|
||||||
|
var bytes = [UInt8](count: size, repeatedValue: 0)
|
||||||
|
let bytesRead = stream.read(&bytes, maxLength: size)
|
||||||
|
bytes.removeRange(Range(start: bytesRead, end: size))
|
||||||
|
guard let string = String(bytes: bytes, encoding: NSUTF8StringEncoding) else {
|
||||||
|
print("failed to create string from bytes")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buffer += string
|
||||||
|
checkForLines()
|
||||||
|
}
|
||||||
|
if stream.streamStatus == .AtEnd {
|
||||||
|
checkForLastLine()
|
||||||
|
closeStream()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkForLines() {
|
||||||
|
while let range = buffer.rangeOfString("\n") {
|
||||||
|
let line = buffer.substringToIndex(range.endIndex)
|
||||||
|
buffer = buffer.substringFromIndex(range.endIndex)
|
||||||
|
lineFunc(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkForLastLine() {
|
||||||
|
if buffer.characters.count > 0 {
|
||||||
|
lineFunc(buffer)
|
||||||
|
buffer = ""
|
||||||
|
}
|
||||||
|
if let f = endFunc {
|
||||||
|
f()
|
||||||
|
endFunc = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue