Ind.ie is now Small Technology Foundation.
SocketConnection.swift 2.37 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import Foundation
import SwiftBytes
import CocoaAsyncSocket

class SocketConnection: NSObject, GCDAsyncSocketDelegate, Connection {
    
    let socket: GCDAsyncSocket
    var incomingMessageBytes: [UInt8] = []
    var onMessage: (Message) -> ()
    var onError: (NSError) -> ()
    
    init(socket: GCDAsyncSocket, onMessage: (Message) -> (), onError: (NSError) -> ()) {
        self.socket = socket
        self.onMessage = onMessage
        self.onError = onError
        super.init()
        self.socket.synchronouslySetDelegate(self)
        readHeader()
    }
20 21 22 23 24 25

    func send(hello: Hello) {
        let data = NSData(bytes: hello.serialize())
        self.socket.writeData(data, withTimeout: -1, tag: 0)
    }

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    func send(message: Message) {
        let data = NSData(bytes: message.encode().serialize())
        self.socket.writeData(data, withTimeout:-1, tag: 0)
    }
    
    func disconnect() {
        self.socket.disconnect()
    }
    
    func socket(socket: GCDAsyncSocket!, didReadData data: NSData!, withTag tag: Int) {
        incomingMessageBytes += data.bytes
        if tag == readingHeaderTag {
            onHeaderRead(incomingMessageBytes)
        }
        if tag == readingContentsTag {
            onContentsRead(incomingMessageBytes)
        }
    }
    
    private func readHeader() {
        socket.readDataToLength(8, withTimeout: timeout, tag: readingHeaderTag)
    }
    
    private func readContents(length length: UInt32) {
        socket.readDataToLength(UInt(length), withTimeout: timeout, tag: readingContentsTag)
    }
    
    private func onHeaderRead(headerBytes: [UInt8]) {
        let length = concatenateBytes(headerBytes[4], headerBytes[5], headerBytes[6], headerBytes[7])
        if length > 0 {
            readContents(length: length)
        } else {
            onContentsRead(headerBytes)
        }
    }
    
    private func onContentsRead(messageBytes: [UInt8]) {
        incomingMessageBytes = []
        if let encodedMessage = EncodedMessage.deserialize(messageBytes) {
            let message = Message.decode(encodedMessage)!
            onMessage(message)
            readHeader()
        }
        else {
            disconnect()
            onError(NSError(domain:PulseNSError.domain, code:PulseNSError.protocolError, userInfo:nil))
        }
    }
    
    let readingHeaderTag = 0;
    let readingContentsTag = 1;
    let timeout: NSTimeInterval = 30;
    
}