update 1.2

This commit is contained in:
Erik 2015-03-13 10:08:41 -04:00
parent 560235353d
commit 4551cad9e1
5 changed files with 715 additions and 671 deletions

View File

@ -42,7 +42,7 @@ private enum PacketType: String {
case NOOP = "6" case NOOP = "6"
} }
class SocketEngine: NSObject, WebSocketDelegate { public class SocketEngine: NSObject, WebSocketDelegate {
unowned let client:SocketIOClient unowned let client:SocketIOClient
private let workQueue = NSOperationQueue() private let workQueue = NSOperationQueue()
private let emitQueue = dispatch_queue_create( private let emitQueue = dispatch_queue_create(
@ -78,19 +78,19 @@ class SocketEngine: NSObject, WebSocketDelegate {
return self._websocket return self._websocket
} }
var ws:WebSocket? var ws:WebSocket?
init(client:SocketIOClient, forcePolling:Bool = false) { init(client:SocketIOClient, forcePolling:Bool = false) {
self.client = client self.client = client
self.forcePolling = forcePolling self.forcePolling = forcePolling
self.session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration(), self.session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration(),
delegate: nil, delegateQueue: self.workQueue) delegate: nil, delegateQueue: self.workQueue)
} }
func close() { func close() {
self.pingTimer?.invalidate() self.pingTimer?.invalidate()
self.send(PacketType.CLOSE.rawValue) self.send(PacketType.CLOSE.rawValue)
} }
private func createBinaryDataForSend(data:NSData) -> (NSData?, String?) { private func createBinaryDataForSend(data:NSData) -> (NSData?, String?) {
if self.websocket { if self.websocket {
var byteArray = [UInt8](count: 1, repeatedValue: 0x0) var byteArray = [UInt8](count: 1, repeatedValue: 0x0)
@ -102,16 +102,16 @@ class SocketEngine: NSObject, WebSocketDelegate {
var str = "b4" var str = "b4"
str += data.base64EncodedStringWithOptions( str += data.base64EncodedStringWithOptions(
NSDataBase64EncodingOptions.Encoding64CharacterLineLength) NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
return (nil, str) return (nil, str)
} }
} }
private func createURLs(params:[String: AnyObject]? = nil) -> (String, String) { private func createURLs(params:[String: AnyObject]? = nil) -> (String, String) {
var url = "\(self.client.socketURL)/socket.io/?transport=" var url = "\(self.client.socketURL)/socket.io/?transport="
var urlPolling:String var urlPolling:String
var urlWebSocket:String var urlWebSocket:String
if self.client.secure { if self.client.secure {
urlPolling = "https://" + url + "polling" urlPolling = "https://" + url + "polling"
urlWebSocket = "wss://" + url + "websocket" urlWebSocket = "wss://" + url + "websocket"
@ -119,14 +119,14 @@ class SocketEngine: NSObject, WebSocketDelegate {
urlPolling = "http://" + url + "polling" urlPolling = "http://" + url + "polling"
urlWebSocket = "ws://" + url + "websocket" urlWebSocket = "ws://" + url + "websocket"
} }
if params != nil { if params != nil {
for (key, value) in params! { for (key, value) in params! {
let keyEsc = key.stringByAddingPercentEncodingWithAllowedCharacters( let keyEsc = key.stringByAddingPercentEncodingWithAllowedCharacters(
NSCharacterSet.URLHostAllowedCharacterSet())! NSCharacterSet.URLHostAllowedCharacterSet())!
urlPolling += "&\(keyEsc)=" urlPolling += "&\(keyEsc)="
urlWebSocket += "&\(keyEsc)=" urlWebSocket += "&\(keyEsc)="
if value is String { if value is String {
let valueEsc = (value as! String).stringByAddingPercentEncodingWithAllowedCharacters( let valueEsc = (value as! String).stringByAddingPercentEncodingWithAllowedCharacters(
NSCharacterSet.URLHostAllowedCharacterSet())! NSCharacterSet.URLHostAllowedCharacterSet())!
@ -138,10 +138,10 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
} }
} }
return (urlPolling, urlWebSocket) return (urlPolling, urlWebSocket)
} }
private func doFastUpgrade() { private func doFastUpgrade() {
self.sendWebSocketMessage("", withType: PacketType.UPGRADE) self.sendWebSocketMessage("", withType: PacketType.UPGRADE)
self._websocket = true self._websocket = true
@ -149,23 +149,23 @@ class SocketEngine: NSObject, WebSocketDelegate {
self.fastUpgrade = false self.fastUpgrade = false
self.flushProbeWait() self.flushProbeWait()
} }
private func doPoll() { private func doPoll() {
if self.websocket || self.waitingForPoll || !self.connected { if self.websocket || self.waitingForPoll || !self.connected {
return return
} }
self.waitingForPoll = true self.waitingForPoll = true
self.doRequest(self.parsePollingMessage) self.doRequest(self.parsePollingMessage)
} }
private func doRequest(callback:(String) -> Void) { private func doRequest(callback:(String) -> Void) {
if !self.polling { if !self.polling {
return return
} }
let req = NSURLRequest(URL: NSURL(string: self.urlPolling! + "&sid=\(self.sid)")!) let req = NSURLRequest(URL: NSURL(string: self.urlPolling! + "&sid=\(self.sid)")!)
self.session.dataTaskWithRequest(req) {[weak self] data, res, err in self.session.dataTaskWithRequest(req) {[weak self] data, res, err in
if self == nil { if self == nil {
return return
@ -173,20 +173,18 @@ class SocketEngine: NSObject, WebSocketDelegate {
if self!.polling { if self!.polling {
self?.handlePollingFailed(err) self?.handlePollingFailed(err)
} }
return return
} }
// println(data) // println(data)
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String { if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
// println(str) // println(str)
dispatch_async(self!.parseQueue) {callback(str)} dispatch_async(self!.parseQueue) {callback(str)}
} }
self?.waitingForPoll = false self?.waitingForPoll = false
if self!.fastUpgrade { if self!.fastUpgrade {
self?.doFastUpgrade() self?.doFastUpgrade()
return return
@ -195,22 +193,22 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
}.resume() }.resume()
} }
private func flushProbeWait() { private func flushProbeWait() {
// println("flushing probe wait") // println("flushing probe wait")
dispatch_async(self.emitQueue) {[weak self] in dispatch_async(self.emitQueue) {[weak self] in
if self == nil { if self == nil {
return return
} }
for waiter in self!.probeWait { for waiter in self!.probeWait {
waiter() waiter()
} }
self?.probeWait.removeAll(keepCapacity: false) self?.probeWait.removeAll(keepCapacity: false)
} }
} }
private func flushWaitingForPost() { private func flushWaitingForPost() {
if self.postWait.count == 0 || !self.connected { if self.postWait.count == 0 || !self.connected {
return return
@ -218,31 +216,30 @@ class SocketEngine: NSObject, WebSocketDelegate {
self.flushWaitingForPostToWebSocket() self.flushWaitingForPostToWebSocket()
return return
} }
var postStr = "" var postStr = ""
for packet in self.postWait { for packet in self.postWait {
let len = count(packet) let len = count(packet)
postStr += "\(len):\(packet)" postStr += "\(len):\(packet)"
} }
self.postWait.removeAll(keepCapacity: false) self.postWait.removeAll(keepCapacity: false)
let req = NSMutableURLRequest(URL: NSURL(string: self.urlPolling! + "&sid=\(self.sid)")!) let req = NSMutableURLRequest(URL: NSURL(string: self.urlPolling! + "&sid=\(self.sid)")!)
req.HTTPMethod = "POST" req.HTTPMethod = "POST"
req.setValue("application/html-text", forHTTPHeaderField: "Content-Type") req.setValue("application/html-text", forHTTPHeaderField: "Content-Type")
let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding, let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding,
allowLossyConversion: false)! allowLossyConversion: false)!
req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length") req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length")
req.HTTPBody = postData req.HTTPBody = postData
self.waitingForPost = true self.waitingForPost = true
self.session.dataTaskWithRequest(req) {[weak self] data, res, err in self.session.dataTaskWithRequest(req) {[weak self] data, res, err in
if self == nil { if self == nil {
return return
@ -250,7 +247,7 @@ class SocketEngine: NSObject, WebSocketDelegate {
self?.handlePollingFailed(err) self?.handlePollingFailed(err)
return return
} }
self?.waitingForPost = false self?.waitingForPost = false
dispatch_async(self!.emitQueue) { dispatch_async(self!.emitQueue) {
self?.flushWaitingForPost() self?.flushWaitingForPost()
@ -258,21 +255,21 @@ class SocketEngine: NSObject, WebSocketDelegate {
return return
}}.resume() }}.resume()
} }
// We had packets waiting for send when we upgraded // We had packets waiting for send when we upgraded
// Send them raw // Send them raw
private func flushWaitingForPostToWebSocket() { private func flushWaitingForPostToWebSocket() {
for msg in self.postWait { for msg in self.postWait {
self.ws?.writeString(msg) self.ws?.writeString(msg)
} }
self.postWait.removeAll(keepCapacity: true) self.postWait.removeAll(keepCapacity: true)
} }
// A poll failed, tell the client about it // A poll failed, tell the client about it
private func handlePollingFailed(reason:NSError?) { private func handlePollingFailed(reason:NSError?) {
assert(self.polling, "Polling failed when we're not polling") assert(self.polling, "Polling failed when we're not polling")
if !self.client.reconnecting { if !self.client.reconnecting {
self._connected = false self._connected = false
self.ws?.disconnect() self.ws?.disconnect()
@ -282,18 +279,17 @@ class SocketEngine: NSObject, WebSocketDelegate {
self.client.pollingDidFail(reason) self.client.pollingDidFail(reason)
} }
} }
func open(opts:[String: AnyObject]? = nil) { func open(opts:[String: AnyObject]? = nil) {
if self.connected { if self.connected {
assert(false, "We're in a bad state, this shouldn't happen.") assert(false, "We're in a bad state, this shouldn't happen.")
} }
let (urlPolling, urlWebSocket) = self.createURLs(params: opts) let (urlPolling, urlWebSocket) = self.createURLs(params: opts)
self.urlPolling = urlPolling self.urlPolling = urlPolling
self.urlWebSocket = urlWebSocket self.urlWebSocket = urlWebSocket
let reqPolling = NSURLRequest(URL: NSURL(string: urlPolling + "&b64=1")!) let reqPolling = NSURLRequest(URL: NSURL(string: urlPolling + "&b64=1")!)
self.session.dataTaskWithRequest(reqPolling) {[weak self] data, res, err in self.session.dataTaskWithRequest(reqPolling) {[weak self] data, res, err in
var err2:NSError? var err2:NSError?
if self == nil { if self == nil {
@ -302,31 +298,31 @@ class SocketEngine: NSObject, WebSocketDelegate {
self?.handlePollingFailed(err) self?.handlePollingFailed(err)
return return
} }
if let dataString = NSString(data: data, encoding: NSUTF8StringEncoding) { if let dataString = NSString(data: data, encoding: NSUTF8StringEncoding) {
var mutString = RegexMutable(dataString) var mutString = RegexMutable(dataString)
let parsed:[String]? = mutString["(\\d*):(\\d)(\\{.*\\})?"].groups() let parsed:[String]? = mutString["(\\d*):(\\d)(\\{.*\\})?"].groups()
if parsed == nil || parsed?.count != 4 { if parsed == nil || parsed?.count != 4 {
return return
} }
let length = parsed![1] let length = parsed![1]
let type = parsed![2] let type = parsed![2]
let jsonData = parsed![3].dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) let jsonData = parsed![3].dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
if type != "0" { if type != "0" {
NSLog("Error handshaking") NSLog("Error handshaking")
return return
} }
if let json = NSJSONSerialization.JSONObjectWithData(jsonData!, if let json = NSJSONSerialization.JSONObjectWithData(jsonData!,
options: NSJSONReadingOptions.AllowFragments, error: &err2) as? NSDictionary { options: NSJSONReadingOptions.AllowFragments, error: &err2) as? NSDictionary {
if let sid = json["sid"] as? String { if let sid = json["sid"] as? String {
// println(json) // println(json)
self?.sid = sid self?.sid = sid
self?._connected = true self?._connected = true
if !self!.forcePolling { if !self!.forcePolling {
self?.ws = WebSocket(url: NSURL(string: urlWebSocket + "&sid=\(self!.sid)")!) self?.ws = WebSocket(url: NSURL(string: urlWebSocket + "&sid=\(self!.sid)")!)
self?.ws?.queue = self?.handleQueue self?.ws?.queue = self?.handleQueue
@ -337,43 +333,43 @@ class SocketEngine: NSObject, WebSocketDelegate {
NSLog("Error handshaking") NSLog("Error handshaking")
return return
} }
if let pingInterval = json["pingInterval"] as? Int { if let pingInterval = json["pingInterval"] as? Int {
self?.pingInterval = pingInterval / 1000 self?.pingInterval = pingInterval / 1000
} }
} }
self?.doPoll() self?.doPoll()
self?.startPingTimer() self?.startPingTimer()
}}.resume() }}.resume()
} }
// Translatation of engine.io-parser#decodePayload // Translatation of engine.io-parser#decodePayload
private func parsePollingMessage(str:String) { private func parsePollingMessage(str:String) {
if str.length == 1 { if str.length == 1 {
return return
} }
// println(str) // println(str)
let strArray = Array(str) let strArray = Array(str)
var length = "" var length = ""
var n = 0 var n = 0
var msg = "" var msg = ""
func testLength(length:String, inout n:Int) -> Bool { func testLength(length:String, inout n:Int) -> Bool {
if let num = length.toInt() { if let num = length.toInt() {
n = num n = num
} else { } else {
return true return true
} }
return false return false
} }
for var i = 0, l = str.length; i < l; i = i &+ 1 { for var i = 0, l = str.length; i < l; i = i &+ 1 {
let chr = String(strArray[i]) let chr = String(strArray[i])
if chr != ":" { if chr != ":" {
length += chr length += chr
} else { } else {
@ -381,16 +377,16 @@ class SocketEngine: NSObject, WebSocketDelegate {
println("failure in parsePollingMessage") println("failure in parsePollingMessage")
return return
} }
msg = String(strArray[i&+1...i&+n]) msg = String(strArray[i&+1...i&+n])
if let lengthInt = length.toInt() { if let lengthInt = length.toInt() {
if lengthInt != msg.length { if lengthInt != msg.length {
println("parsing error") println("parsing error")
return return
} }
} }
if msg.length != 0 { if msg.length != 0 {
// Be sure to capture the value of the msg // Be sure to capture the value of the msg
dispatch_async(self.handleQueue) {[weak self, msg] in dispatch_async(self.handleQueue) {[weak self, msg] in
@ -398,50 +394,50 @@ class SocketEngine: NSObject, WebSocketDelegate {
return return
} }
} }
i += n i += n
length = "" length = ""
} }
} }
} }
private func parseEngineData(data:NSData) { private func parseEngineData(data:NSData) {
self.client.parseBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1))) self.client.parseBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
} }
private func parseEngineMessage(var message:String) { private func parseEngineMessage(var message:String) {
// println(message!) // println(message!)
var strMessage = RegexMutable(message) var strMessage = RegexMutable(message)
// We should upgrade // We should upgrade
if strMessage == "3probe" { if strMessage == "3probe" {
self.upgradeTransport() self.upgradeTransport()
return return
} }
let type = strMessage["^(\\d)"].groups()?[1] let type = strMessage["^(\\d)"].groups()?[1]
if type != PacketType.MESSAGE.rawValue { if type != PacketType.MESSAGE.rawValue {
// TODO Handle other packets // TODO Handle other packets
if message.hasPrefix("b4") { if message.hasPrefix("b4") {
// binary in base64 string // binary in base64 string
message.removeRange(Range<String.Index>(start: message.startIndex, message.removeRange(Range<String.Index>(start: message.startIndex,
end: advance(message.startIndex, 2))) end: advance(message.startIndex, 2)))
if let data = NSData(base64EncodedString: message, if let data = NSData(base64EncodedString: message,
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) { options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) {
// println("sending \(data)") // println("sending \(data)")
self.client.parseBinaryData(data) self.client.parseBinaryData(data)
} }
return return
} else if type == PacketType.NOOP.rawValue { } else if type == PacketType.NOOP.rawValue {
self.doPoll() self.doPoll()
return return
} }
if message == PacketType.CLOSE.rawValue { if message == PacketType.CLOSE.rawValue {
// do nothing // do nothing
return return
@ -449,42 +445,42 @@ class SocketEngine: NSObject, WebSocketDelegate {
// println("Got something idk what to do with") // println("Got something idk what to do with")
// println(messageString) // println(messageString)
} }
// Remove message type // Remove message type
message.removeAtIndex(message.startIndex) message.removeAtIndex(message.startIndex)
// println("sending \(messageString)") // println("sending \(messageString)")
self.client.parseSocketMessage(message) self.client.parseSocketMessage(message)
} }
private func probeWebSocket() { private func probeWebSocket() {
if self.websocketConnected { if self.websocketConnected {
self.sendWebSocketMessage("probe", withType: PacketType.PING) self.sendWebSocketMessage("probe", withType: PacketType.PING)
} }
} }
func send(msg:String, datas:[NSData]? = nil) { public func send(msg:String, datas:[NSData]? = nil) {
let _send = {[weak self] (msg:String, datas:[NSData]?) -> () -> Void in let _send = {[weak self] (msg:String, datas:[NSData]?) -> () -> Void in
return { return {
if self == nil || !self!.connected { if self == nil || !self!.connected {
return return
} }
if self!.websocket { if self!.websocket {
// println("sending ws: \(msg):\(datas)") // println("sending ws: \(msg):\(datas)")
self?.sendWebSocketMessage(msg, withType: PacketType.MESSAGE, datas: datas) self?.sendWebSocketMessage(msg, withType: PacketType.MESSAGE, datas: datas)
} else { } else {
// println("sending poll: \(msg):\(datas)") // println("sending poll: \(msg):\(datas)")
self?.sendPollMessage(msg, withType: PacketType.MESSAGE, datas: datas, doPoll: true) self?.sendPollMessage(msg, withType: PacketType.MESSAGE, datas: datas)
} }
} }
} }
dispatch_async(self.emitQueue) {[weak self] in dispatch_async(self.emitQueue) {[weak self] in
if self == nil { if self == nil {
return return
} }
if self!.probing { if self!.probing {
self?.probeWait.append(_send(msg, datas)) self?.probeWait.append(_send(msg, datas))
} else { } else {
@ -492,41 +488,37 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
} }
} }
func sendPing() { func sendPing() {
if self.websocket { if self.websocket {
self.sendWebSocketMessage("", withType: PacketType.PING) self.sendWebSocketMessage("", withType: PacketType.PING)
} else { } else {
self.sendPollMessage("", withType: PacketType.PING, doPoll: false) self.sendPollMessage("", withType: PacketType.PING)
} }
} }
private func sendPollMessage(msg:String, withType type:PacketType, private func sendPollMessage(msg:String, withType type:PacketType,
datas:[NSData]? = nil, doPoll poll:Bool) { datas:[NSData]? = nil) {
// println("Sending poll: \(msg) as type: \(type.rawValue)") // println("Sending poll: \(msg) as type: \(type.rawValue)")
let strMsg = "\(type.rawValue)\(msg)" let strMsg = "\(type.rawValue)\(msg)"
self.postWait.append(strMsg) self.postWait.append(strMsg)
if datas != nil { if datas != nil {
for data in datas! { for data in datas! {
let (nilData, b64Data) = self.createBinaryDataForSend(data) let (nilData, b64Data) = self.createBinaryDataForSend(data)
self.postWait.append(b64Data!) self.postWait.append(b64Data!)
} }
} }
if !self.waitingForPoll && self.waitingForPost && poll { self.flushWaitingForPost()
self.doPoll()
} else {
self.flushWaitingForPost()
}
} }
private func sendWebSocketMessage(str:String, withType type:PacketType, datas:[NSData]? = nil) { private func sendWebSocketMessage(str:String, withType type:PacketType, datas:[NSData]? = nil) {
// println("Sending ws: \(str) as type: \(type.rawValue)") // println("Sending ws: \(str) as type: \(type.rawValue)")
self.ws?.writeString("\(type.rawValue)\(str)") self.ws?.writeString("\(type.rawValue)\(str)")
if datas != nil { if datas != nil {
for data in datas! { for data in datas! {
let (data, nilString) = self.createBinaryDataForSend(data) let (data, nilString) = self.createBinaryDataForSend(data)
@ -536,39 +528,39 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
} }
} }
// Starts the ping timer // Starts the ping timer
private func startPingTimer() { private func startPingTimer() {
if self.pingInterval == nil { if self.pingInterval == nil {
return return
} }
self.pingTimer?.invalidate() self.pingTimer?.invalidate()
dispatch_async(dispatch_get_main_queue()) { dispatch_async(dispatch_get_main_queue()) {
self.pingTimer = NSTimer.scheduledTimerWithTimeInterval(NSTimeInterval(self.pingInterval!), target: self, self.pingTimer = NSTimer.scheduledTimerWithTimeInterval(NSTimeInterval(self.pingInterval!), target: self,
selector: Selector("sendPing"), userInfo: nil, repeats: true) selector: Selector("sendPing"), userInfo: nil, repeats: true)
} }
} }
private func upgradeTransport() { private func upgradeTransport() {
if self.websocketConnected { if self.websocketConnected {
// Do a fast upgrade // Do a fast upgrade
self.fastUpgrade = true self.fastUpgrade = true
self.probing = false self.probing = false
self.sendPollMessage("", withType: PacketType.NOOP, doPoll: false) self.sendPollMessage("", withType: PacketType.NOOP)
} }
} }
func websocketDidConnect(socket:WebSocket) { public func websocketDidConnect(socket:WebSocket) {
self.websocketConnected = true self.websocketConnected = true
self.probing = true self.probing = true
self.probeWebSocket() self.probeWebSocket()
} }
func websocketDidDisconnect(socket:WebSocket, error:NSError?) { public func websocketDidDisconnect(socket:WebSocket, error:NSError?) {
self.websocketConnected = false self.websocketConnected = false
self.probing = false self.probing = false
if self.websocket { if self.websocket {
self.pingTimer?.invalidate() self.pingTimer?.invalidate()
self._connected = false self._connected = false
@ -579,12 +571,12 @@ class SocketEngine: NSObject, WebSocketDelegate {
self.flushProbeWait() self.flushProbeWait()
} }
} }
func websocketDidReceiveMessage(socket:WebSocket, text:String) { public func websocketDidReceiveMessage(socket:WebSocket, text:String) {
self.parseEngineMessage(text) self.parseEngineMessage(text)
} }
func websocketDidReceiveData(socket:WebSocket, data:NSData) { public func websocketDidReceiveData(socket:WebSocket, data:NSData) {
self.parseEngineData(data) self.parseEngineData(data)
} }
} }

View File

@ -226,7 +226,7 @@ class SocketEvent {
// We have multiple items // We have multiple items
// Do it live // Do it live
let argsAsArray = "[\(self.args)]" let argsAsArray = "[\(self.args)]"
if let parsedArr = SocketIOClient.parseData(argsAsArray) as? NSArray { if let parsedArr = SocketParser.parseData(argsAsArray) as? NSArray {
var returnArr = [AnyObject](count: parsedArr.count, repeatedValue: 0) var returnArr = [AnyObject](count: parsedArr.count, repeatedValue: 0)
for i in 0..<parsedArr.count { for i in 0..<parsedArr.count {

View File

@ -36,126 +36,145 @@ public class SocketIOClient: NSObject {
private lazy var params = [String: AnyObject]() private lazy var params = [String: AnyObject]()
private var ackHandlers = [SocketAckHandler]() private var ackHandlers = [SocketAckHandler]()
private var anyHandler:((AnyHandler) -> Void)? private var anyHandler:((AnyHandler) -> Void)?
private var currentAck = -1 private var _closed = false
private var _connected = false
private var _connecting = false
private var currentReconnectAttempt = 0 private var currentReconnectAttempt = 0
private var forcePolling = false private var forcePolling = false
private var handlers = [SocketEventHandler]() private var handlers = [SocketEventHandler]()
private var waitingData = [SocketEvent]()
private var paramConnect = false private var paramConnect = false
private var _secure = false private var _secure = false
private var _sid:String?
private var _reconnecting = false
private var reconnectTimer:NSTimer? private var reconnectTimer:NSTimer?
var closed = false
var connected = false internal var currentAck = -1
var connecting = false internal var waitingData = [SocketEvent]()
var engine:SocketEngine?
var nsp:String? public var closed:Bool {
var reconnects = true return self._closed
var reconnecting = false }
var reconnectWait = 10 public var connected:Bool {
var secure:Bool { return self._connected
}
public var connecting:Bool {
return self._connecting
}
public var engine:SocketEngine?
public var nsp:String?
public var reconnects = true
public var reconnecting:Bool {
return self._reconnecting
}
public var reconnectWait = 10
public var secure:Bool {
return self._secure return self._secure
} }
var sid:String? public var sid:String? {
return self._sid
}
public init(socketURL:String, opts:[String: AnyObject]? = nil) { public init(socketURL:String, opts:[String: AnyObject]? = nil) {
var mutURL = RegexMutable(socketURL) var mutURL = RegexMutable(socketURL)
if mutURL["https://"].matches().count != 0 { if mutURL["https://"].matches().count != 0 {
self._secure = true self._secure = true
} }
mutURL = mutURL["http://"] ~= "" mutURL = mutURL["http://"] ~= ""
mutURL = mutURL["https://"] ~= "" mutURL = mutURL["https://"] ~= ""
self.socketURL = mutURL self.socketURL = mutURL
// Set options // Set options
if opts != nil { if opts != nil {
if let reconnects = opts!["reconnects"] as? Bool { if let reconnects = opts!["reconnects"] as? Bool {
self.reconnects = reconnects self.reconnects = reconnects
} }
if let reconnectAttempts = opts!["reconnectAttempts"] as? Int { if let reconnectAttempts = opts!["reconnectAttempts"] as? Int {
self.reconnectAttempts = reconnectAttempts self.reconnectAttempts = reconnectAttempts
} else { } else {
self.reconnectAttempts = -1 self.reconnectAttempts = -1
} }
if let reconnectWait = opts!["reconnectWait"] as? Int { if let reconnectWait = opts!["reconnectWait"] as? Int {
self.reconnectWait = abs(reconnectWait) self.reconnectWait = abs(reconnectWait)
} }
if let nsp = opts!["nsp"] as? String { if let nsp = opts!["nsp"] as? String {
self.nsp = nsp self.nsp = nsp
} }
if let polling = opts!["forcePolling"] as? Bool { if let polling = opts!["forcePolling"] as? Bool {
self.forcePolling = polling self.forcePolling = polling
} }
} else { } else {
self.reconnectAttempts = -1 self.reconnectAttempts = -1
} }
super.init() super.init()
self.engine = SocketEngine(client: self, forcePolling: self.forcePolling) self.engine = SocketEngine(client: self, forcePolling: self.forcePolling)
} }
// Closes the socket // Closes the socket
public func close() { public func close() {
self.closed = true self._closed = true
self.connecting = false self._connecting = false
self.connected = false self._connected = false
self.reconnecting = false self._reconnecting = false
self.engine?.close() self.engine?.close()
} }
// Connects to the server // Connects to the server
public func connect() { public func connect() {
if self.closed { if self.closed {
println("Warning! This socket was previously closed. This might be dangerous!") println("Warning! This socket was previously closed. This might be dangerous!")
self.closed = false self._closed = false
} }
self.engine?.open() self.engine?.open()
} }
// Connect to the server using params // Connect to the server using params
public func connectWithParams(params:[String: AnyObject]) { public func connectWithParams(params:[String: AnyObject]) {
if self.closed { if self.closed {
println("Warning! This socket was previously closed. This might be dangerous!") println("Warning! This socket was previously closed. This might be dangerous!")
self.closed = false self._closed = false
} }
self.params = params self.params = params
self.paramConnect = true self.paramConnect = true
self.engine?.open(opts: params) self.engine?.open(opts: params)
} }
func didConnect() { func didConnect() {
self.closed = false self._closed = false
self.connected = true self._connected = true
self.connecting = false self._connecting = false
self.reconnecting = false self._reconnecting = false
self.currentReconnectAttempt = 0 self.currentReconnectAttempt = 0
self.reconnectTimer?.invalidate() self.reconnectTimer?.invalidate()
self.reconnectTimer = nil self.reconnectTimer = nil
self.sid = self.engine?.sid self._sid = self.engine?.sid
// Don't handle as internal because something crazy could happen where
// we disconnect before it's handled
self.handleEvent("connect", data: nil, isInternalMessage: false) self.handleEvent("connect", data: nil, isInternalMessage: false)
} }
// Server wants us to die // Server wants us to die
func didForceClose() { func didForceClose() {
self.closed = true self._closed = true
self.connected = false self._connected = false
self.reconnects = false self.reconnects = false
self.connecting = false self._connecting = false
self.reconnecting = false self._reconnecting = false
self.handleEvent("disconnect", data: "closed", isInternalMessage: true) self.handleEvent("disconnect", data: "closed", isInternalMessage: true)
} }
// Sends a message with multiple args // Sends a message with multiple args
// If a message contains binary we have to send those // If a message contains binary we have to send those
// seperately. // seperately.
@ -163,49 +182,49 @@ public class SocketIOClient: NSObject {
if !self.connected { if !self.connected {
return return
} }
dispatch_async(self.emitQueue) {[weak self] in dispatch_async(self.emitQueue) {[weak self] in
self?._emit(event, args) self?._emit(event, args)
return return
} }
} }
// Objc doesn't have variadics // Objc doesn't have variadics
public func emitObjc(event:String, _ args:[AnyObject]) { public func emitObjc(event:String, _ args:[AnyObject]) {
self.emit(event, args) self.emit(event, args)
} }
public func emitWithAck(event:String, _ args:AnyObject...) -> SocketAckHandler { public func emitWithAck(event:String, _ args:AnyObject...) -> SocketAckHandler {
if !self.connected { if !self.connected {
return SocketAckHandler(event: "fail") return SocketAckHandler(event: "fail")
} }
self.currentAck++ self.currentAck++
let ackHandler = SocketAckHandler(event: event, ackNum: self.currentAck) let ackHandler = SocketAckHandler(event: event, ackNum: self.currentAck)
self.ackHandlers.append(ackHandler) self.ackHandlers.append(ackHandler)
dispatch_async(self.emitQueue) {[weak self] in dispatch_async(self.emitQueue) {[weak self] in
self?._emit(event, args, ack: true) self?._emit(event, args, ack: true)
return return
} }
return ackHandler return ackHandler
} }
public func emitWithAckObjc(event:String, _ args:[AnyObject]) -> SocketAckHandler { public func emitWithAckObjc(event:String, _ args:[AnyObject]) -> SocketAckHandler {
return self.emitWithAck(event, args) return self.emitWithAck(event, args)
} }
private func _emit(event:String, _ args:[AnyObject], ack:Bool = false) { private func _emit(event:String, _ args:[AnyObject], ack:Bool = false) {
var frame:SocketEvent var frame:SocketEvent
var str:String var str:String
let (items, hasBinary, emitDatas) = SocketIOClient.parseEmitArgs(args) let (items, hasBinary, emitDatas) = SocketParser.parseEmitArgs(args)
if !self.connected { if !self.connected {
return return
} }
if hasBinary { if hasBinary {
if !ack { if !ack {
str = SocketEvent.createMessageForEvent(event, withArgs: items, str = SocketEvent.createMessageForEvent(event, withArgs: items,
@ -214,7 +233,7 @@ public class SocketIOClient: NSObject {
str = SocketEvent.createMessageForEvent(event, withArgs: items, str = SocketEvent.createMessageForEvent(event, withArgs: items,
hasBinary: true, withDatas: emitDatas.count, toNamespace: self.nsp, wantsAck: self.currentAck) hasBinary: true, withDatas: emitDatas.count, toNamespace: self.nsp, wantsAck: self.currentAck)
} }
self.engine?.send(str, datas: emitDatas) self.engine?.send(str, datas: emitDatas)
} else { } else {
if !ack { if !ack {
@ -224,21 +243,21 @@ public class SocketIOClient: NSObject {
str = SocketEvent.createMessageForEvent(event, withArgs: items, hasBinary: false, str = SocketEvent.createMessageForEvent(event, withArgs: items, hasBinary: false,
withDatas: 0, toNamespace: self.nsp, wantsAck: self.currentAck) withDatas: 0, toNamespace: self.nsp, wantsAck: self.currentAck)
} }
self.engine?.send(str) self.engine?.send(str)
} }
} }
// If the server wants to know that the client received data // If the server wants to know that the client received data
internal func emitAck(ack:Int, withData data:[AnyObject]?, withAckType ackType:Int) { func emitAck(ack:Int, withData data:[AnyObject]?, withAckType ackType:Int) {
dispatch_async(self.ackQueue) {[weak self] in dispatch_async(self.ackQueue) {[weak self] in
if self == nil || !self!.connected || data == nil { if self == nil || !self!.connected || data == nil {
return return
} }
let (items, hasBinary, emitDatas) = SocketIOClient.parseEmitArgs(data!) let (items, hasBinary, emitDatas) = SocketParser.parseEmitArgs(data!)
var str:String var str:String
if !hasBinary { if !hasBinary {
if self?.nsp == nil { if self?.nsp == nil {
str = SocketEvent.createAck(ack, withArgs: items, str = SocketEvent.createAck(ack, withArgs: items,
@ -247,7 +266,7 @@ public class SocketIOClient: NSObject {
str = SocketEvent.createAck(ack, withArgs: items, str = SocketEvent.createAck(ack, withArgs: items,
withAckType: 3, withNsp: self!.nsp!) withAckType: 3, withNsp: self!.nsp!)
} }
self?.engine?.send(str) self?.engine?.send(str)
} else { } else {
if self?.nsp == nil { if self?.nsp == nil {
@ -257,14 +276,14 @@ public class SocketIOClient: NSObject {
str = SocketEvent.createAck(ack, withArgs: items, str = SocketEvent.createAck(ack, withArgs: items,
withAckType: 6, withNsp: self!.nsp!, withBinary: emitDatas.count) withAckType: 6, withNsp: self!.nsp!, withBinary: emitDatas.count)
} }
self?.engine?.send(str, datas: emitDatas) self?.engine?.send(str, datas: emitDatas)
} }
} }
} }
// Called when the socket gets an ack for something it sent // Called when the socket gets an ack for something it sent
private func handleAck(ack:Int, data:AnyObject?) { func handleAck(ack:Int, data:AnyObject?) {
self.ackHandlers = self.ackHandlers.filter {handler in self.ackHandlers = self.ackHandlers.filter {handler in
if handler.ackNum != ack { if handler.ackNum != ack {
return true return true
@ -276,12 +295,12 @@ public class SocketIOClient: NSObject {
} else { } else {
handler.executeAck(nil) handler.executeAck(nil)
} }
return false return false
} }
} }
} }
// Handles events // Handles events
public func handleEvent(event:String, data:AnyObject?, isInternalMessage:Bool = false, public func handleEvent(event:String, data:AnyObject?, isInternalMessage:Bool = false,
wantsAck ack:Int? = nil, withAckType ackType:Int = 3) { wantsAck ack:Int? = nil, withAckType ackType:Int = 3) {
@ -289,7 +308,7 @@ public class SocketIOClient: NSObject {
if !self.connected && !isInternalMessage { if !self.connected && !isInternalMessage {
return return
} }
dispatch_async(dispatch_get_main_queue()) {[weak self] in dispatch_async(dispatch_get_main_queue()) {[weak self] in
self?.anyHandler?((event, data)) self?.anyHandler?((event, data))
return return
@ -304,15 +323,15 @@ public class SocketIOClient: NSObject {
handler.executeCallback(data as? NSArray) handler.executeCallback(data as? NSArray)
} }
} else { } else {
// Trying to do a ternary expression in the executeCallback method // Trying to do a ternary expression in the executeCallback method
// seemed to crash Swift // seemed to crash Swift
var dataArr:NSArray? = nil var dataArr:NSArray? = nil
if let data:AnyObject = data { if let data:AnyObject = data {
dataArr = [data] dataArr = [data]
} }
if ack != nil { if ack != nil {
handler.executeCallback(dataArr, withAck: ack!, handler.executeCallback(dataArr, withAck: ack!,
withAckType: ackType, withSocket: self) withAckType: ackType, withSocket: self)
@ -323,492 +342,74 @@ public class SocketIOClient: NSObject {
} }
} }
} }
// Should be removed and moved to SocketEngine // Should be removed and moved to SocketEngine
func joinNamespace() { func joinNamespace() {
if self.nsp != nil { if self.nsp != nil {
self.engine?.send("0/\(self.nsp!)") self.engine?.send("0/\(self.nsp!)")
} }
} }
// Adds handler for an event // Adds handler for an event
public func on(name:String, callback:NormalCallback) { public func on(name:String, callback:NormalCallback) {
let handler = SocketEventHandler(event: name, callback: callback) let handler = SocketEventHandler(event: name, callback: callback)
self.handlers.append(handler) self.handlers.append(handler)
} }
// Adds a handler for any event // Adds a handler for any event
public func onAny(handler:(AnyHandler) -> Void) { public func onAny(handler:(AnyHandler) -> Void) {
self.anyHandler = handler self.anyHandler = handler
} }
// Opens the connection to the socket // Opens the connection to the socket
public func open() { public func open() {
self.connect() self.connect()
} }
// Parse an NSArray looking for binary data func parseSocketMessage(msg:String) {
private class func parseArray(arr:NSArray, var currentPlaceholder:Int) -> (NSArray, Bool, [NSData]) { SocketParser.parseSocketMessage(msg, socket: self)
var replacementArr = [AnyObject](count: arr.count, repeatedValue: 1)
var hasBinary = false
var arrayDatas = [NSData]()
for g in 0..<arr.count {
if arr[g] is NSData {
hasBinary = true
currentPlaceholder++
let sendData = arr[g] as! NSData
arrayDatas.append(sendData)
replacementArr[g] = ["_placeholder": true,
"num": currentPlaceholder]
} else if let dict = arr[g] as? NSDictionary {
let (nestDict, hadBinary, dictArrs) = self.parseNSDictionary(dict,
currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
currentPlaceholder += dictArrs.count
replacementArr[g] = nestDict
arrayDatas.extend(dictArrs)
} else {
replacementArr[g] = dict
}
} else if let nestArr = arr[g] as? NSArray {
// Recursive
let (nested, hadBinary, nestDatas) = self.parseArray(nestArr,
currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
currentPlaceholder += nestDatas.count
replacementArr[g] = nested
arrayDatas.extend(nestDatas)
} else {
replacementArr[g] = arr[g]
}
} else {
replacementArr[g] = arr[g]
}
}
return (replacementArr, hasBinary, arrayDatas)
} }
// Parses data for events func parseBinaryData(data:NSData) {
class func parseData(data:String?) -> AnyObject? { SocketParser.parseBinaryData(data, socket: self)
if data == nil {
return nil
}
var err:NSError?
let stringData = data!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let parsed:AnyObject? = NSJSONSerialization.JSONObjectWithData(stringData!,
options: NSJSONReadingOptions.AllowFragments, error: &err)
if err != nil {
// println(err)
return nil
}
return parsed
} }
private class func parseEmitArgs(args:[AnyObject]) -> ([AnyObject], Bool, [NSData]) {
var items = [AnyObject](count: args.count, repeatedValue: 1)
var currentPlaceholder = -1
var hasBinary = false
var emitDatas = [NSData]()
for i in 0..<args.count {
if let dict = args[i] as? NSDictionary {
// Check for binary data
let (newDict, hadBinary, binaryDatas) = SocketIOClient.parseNSDictionary(dict,
currentPlaceholder: currentPlaceholder)
if hadBinary {
currentPlaceholder += binaryDatas.count
emitDatas.extend(binaryDatas)
hasBinary = true
items[i] = newDict
} else {
items[i] = dict
}
} else if let arr = args[i] as? NSArray {
// arg is array, check for binary
let (replace, hadData, newDatas) = SocketIOClient.parseArray(arr,
currentPlaceholder: currentPlaceholder)
if hadData {
hasBinary = true
currentPlaceholder += newDatas.count
for data in newDatas {
emitDatas.append(data)
}
items[i] = replace
} else {
items[i] = arr
}
} else if let binaryData = args[i] as? NSData {
// args is just binary
hasBinary = true
currentPlaceholder++
items[i] = ["_placeholder": true, "num": currentPlaceholder]
emitDatas.append(binaryData)
} else {
items[i] = args[i]
}
}
return (items, hasBinary, emitDatas)
}
// Parses a NSDictionary, looking for NSData objects
private class func parseNSDictionary(dict:NSDictionary, var currentPlaceholder:Int) -> (NSDictionary, Bool, [NSData]) {
var returnDict = NSMutableDictionary()
var hasBinary = false
var returnDatas = [NSData]()
for (key, value) in dict {
if let binaryData = value as? NSData {
currentPlaceholder++
hasBinary = true
returnDatas.append(binaryData)
returnDict[key as! String] = ["_placeholder": true, "num": currentPlaceholder++]
} else if let arr = value as? NSArray {
let (replace, hadBinary, arrDatas) = self.parseArray(arr, currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
returnDict[key as! String] = replace
currentPlaceholder += arrDatas.count
returnDatas.extend(arrDatas)
} else {
returnDict[key as! String] = arr
}
} else if let dict = value as? NSDictionary {
// Recursive
let (nestDict, hadBinary, nestDatas) = self.parseNSDictionary(dict, currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
returnDict[key as! String] = nestDict
currentPlaceholder += nestDatas.count
returnDatas.extend(nestDatas)
} else {
returnDict[key as! String] = dict
}
} else {
returnDict[key as! String] = value
}
}
return (returnDict, hasBinary, returnDatas)
}
// Parses messages recieved
internal func parseSocketMessage(stringMessage:String) {
// println(message!)
// Check for successful namepsace connect
if self.nsp != nil {
if stringMessage == "0/\(self.nsp!)" {
self.didConnect()
return
}
}
if stringMessage == "0" {
if self.nsp != nil {
// Join namespace
self.joinNamespace()
return
} else {
// Don't handle as internal because something crazy could happen where
// we disconnect before it's handled
self.didConnect()
return
}
}
var mutMessage = RegexMutable(stringMessage)
/**
Begin check for message
**/
let messageGroups = mutMessage["(\\d*)\\/?(\\w*)?,?(\\d*)?(\\[.*\\])?"].groups()
if messageGroups[1].hasPrefix("2") {
var mesNum = messageGroups[1]
var ackNum:String
var namespace:String?
var messagePart:String!
if messageGroups[3] != "" {
ackNum = messageGroups[3]
} else {
let range = Range<String.Index>(start: mesNum.startIndex, end: advance(mesNum.startIndex, 1))
mesNum.replaceRange(range, with: "")
ackNum = mesNum
}
namespace = messageGroups[2]
messagePart = messageGroups[4]
if namespace == "" && self.nsp != nil {
return
}
let messageInternals = RegexMutable(messagePart)["\\[\"(.*?)\",(.*?)?\\]$"].groups()
if messageInternals != nil && messageInternals.count > 2 {
let event = messageInternals[1]
var data:String?
if messageInternals[2] == "" {
data = nil
} else {
data = messageInternals[2]
}
// It would be nice if socket.io only allowed one thing
// per message, but alas, it doesn't.
if let parsed:AnyObject = SocketIOClient.parseData(data) {
if ackNum == "" {
self.handleEvent(event, data: parsed)
} else {
self.currentAck = ackNum.toInt()!
self.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
} else if let strData = data {
// There are multiple items in the message
// Turn it into a String and run it through
// parseData to try and get an array.
let asArray = "[\(strData)]"
if let parsed:AnyObject = SocketIOClient.parseData(asArray) {
if ackNum == "" {
self.handleEvent(event, data: parsed)
} else {
self.currentAck = ackNum.toInt()!
self.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
}
}
}
// Check for no item event
let noItemMessage = RegexMutable(messagePart)["\\[\"(.*?)\"]$"].groups()
if noItemMessage != nil && noItemMessage.count == 2 {
let event = noItemMessage[1]
if ackNum == "" {
self.handleEvent(event, data: nil)
} else {
self.currentAck = ackNum.toInt()!
self.handleEvent(event, data: nil, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
}
} else if messageGroups[1].hasPrefix("3") {
let arr = Array(messageGroups[1])
var ackNum:String
let nsp = messageGroups[2]
if nsp == "" && self.nsp != nil {
return
}
if nsp == "" {
ackNum = String(arr[1...arr.count-1])
} else {
ackNum = messageGroups[3]
}
let ackData:AnyObject? = SocketIOClient.parseData(messageGroups[4])
self.handleAck(ackNum.toInt()!, data: ackData)
return
}
/**
End Check for message
**/
// Check for message with binary placeholders
self.parseBinaryMessage(message: stringMessage)
}
// Tries to parse a message that contains binary
private func parseBinaryMessage(#message:String) {
// println(message)
var mutMessage = RegexMutable(message)
/**
Begin check for binary placeholders
**/
let binaryGroup = mutMessage["^(\\d*)-\\/?(\\w*)?,?(\\d*)?\\[(\".*?\")?,?(.*)?\\]$"].groups()
if binaryGroup == nil {
return
}
if binaryGroup[1].hasPrefix("5") {
// println(binaryGroup)
var ackNum:String
var event:String
var mutMessageObject:NSMutableString
var namespace:String?
var numberOfPlaceholders:String
let messageType = RegexMutable(binaryGroup[1])
namespace = binaryGroup[2]
if binaryGroup[3] != "" {
ackNum = binaryGroup[3] as String
} else if self.nsp == nil && binaryGroup[2] != "" {
ackNum = binaryGroup[2]
} else {
ackNum = ""
}
numberOfPlaceholders = (messageType["5"] ~= "") as String
event = (RegexMutable(binaryGroup[4])["\""] ~= "") as String
mutMessageObject = RegexMutable(binaryGroup[5])
if namespace == "" && self.nsp != nil {
return
}
let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"]
~= "\"~~$2\""
var mes:SocketEvent
if ackNum == "" {
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!)
} else {
self.currentAck = ackNum.toInt()!
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt())
}
self.waitingData.append(mes)
} else if binaryGroup[1].hasPrefix("6") {
let messageType = RegexMutable(binaryGroup[1])
let numberOfPlaceholders = (messageType["6"] ~= "") as String
var ackNum:String
var nsp:String
if binaryGroup[3] == "" {
ackNum = binaryGroup[2]
nsp = ""
} else {
ackNum = binaryGroup[3]
nsp = binaryGroup[2]
}
if nsp == "" && self.nsp != nil {
return
}
var mutMessageObject = RegexMutable(binaryGroup[5])
let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"]
~= "\"~~$2\""
let event = SocketEvent(event: "", args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt(), justAck: true)
self.waitingData.append(event)
}
/**
End check for binary placeholders
**/
}
// Handles binary data
internal func parseBinaryData(data:NSData) {
let shouldExecute = self.waitingData[0].addData(data)
if shouldExecute {
let socketEvent = self.waitingData.removeAtIndex(0)
var event = socketEvent.event
var parsedArgs:AnyObject? = SocketIOClient.parseData(socketEvent.args as? String)
if let args:AnyObject = parsedArgs {
let filledInArgs:AnyObject = socketEvent.fillInPlaceholders(args)
if socketEvent.justAck! {
// Should handle ack
self.handleAck(socketEvent.ack!, data: filledInArgs)
return
}
// Should do event
if socketEvent.ack != nil {
self.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: socketEvent.ack!, withAckType: 6)
} else {
self.handleEvent(event, data: filledInArgs)
}
} else {
let filledInArgs:AnyObject = socketEvent.fillInPlaceholders()
// Should handle ack
if socketEvent.justAck! {
self.handleAck(socketEvent.ack!, data: filledInArgs)
return
}
// Should handle ack
if socketEvent.ack != nil {
self.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: socketEvent.ack!, withAckType: 6)
} else {
self.handleEvent(event, data: filledInArgs)
}
}
}
}
// Something happened while polling // Something happened while polling
internal func pollingDidFail(err:NSError?) { func pollingDidFail(err:NSError?) {
if !self.reconnecting { if !self.reconnecting {
self.connected = false self._connected = false
self.handleEvent("reconnect", data: err?.localizedDescription, isInternalMessage: true) self.handleEvent("reconnect", data: err?.localizedDescription, isInternalMessage: true)
self.tryReconnect() self.tryReconnect()
} }
} }
// We lost connection and should attempt to reestablish // We lost connection and should attempt to reestablish
internal func tryReconnect() { func tryReconnect() {
if self.reconnectAttempts != -1 && self.currentReconnectAttempt + 1 > self.reconnectAttempts { if self.reconnectAttempts != -1 && self.currentReconnectAttempt + 1 > self.reconnectAttempts {
self.didForceClose() self.didForceClose()
return return
} else if self.connected { } else if self.connected {
self.connecting = false self._connecting = false
self.reconnecting = false self._reconnecting = false
return return
} }
if self.reconnectTimer == nil { if self.reconnectTimer == nil {
self.reconnecting = true self._reconnecting = true
dispatch_async(dispatch_get_main_queue()) {[weak self] in dispatch_async(dispatch_get_main_queue()) {[weak self] in
if self == nil { if self == nil {
return return
} }
self?.reconnectTimer = NSTimer.scheduledTimerWithTimeInterval(Double(self!.reconnectWait), self?.reconnectTimer = NSTimer.scheduledTimerWithTimeInterval(Double(self!.reconnectWait),
target: self!, selector: "tryReconnect", userInfo: nil, repeats: true) target: self!, selector: "tryReconnect", userInfo: nil, repeats: true)
return return
} }
} }
self.handleEvent("reconnectAttempt", data: self.reconnectAttempts - self.currentReconnectAttempt, self.handleEvent("reconnectAttempt", data: self.reconnectAttempts - self.currentReconnectAttempt,
isInternalMessage: true) isInternalMessage: true)
self.currentReconnectAttempt++ self.currentReconnectAttempt++
if self.paramConnect { if self.paramConnect {
self.connectWithParams(self.params) self.connectWithParams(self.params)
@ -816,11 +417,11 @@ public class SocketIOClient: NSObject {
self.connect() self.connect()
} }
} }
// Called when the socket is closed // Called when the socket is closed
func webSocketDidCloseWithCode(code:Int, reason:String!, wasClean:Bool) { func webSocketDidCloseWithCode(code:Int, reason:String!, wasClean:Bool) {
self.connected = false self._connected = false
self.connecting = false self._connecting = false
if self.closed || !self.reconnects { if self.closed || !self.reconnects {
self.didForceClose() self.didForceClose()
} else { } else {
@ -828,11 +429,11 @@ public class SocketIOClient: NSObject {
self.tryReconnect() self.tryReconnect()
} }
} }
// Called when an error occurs. // Called when an error occurs.
func webSocketDidFailWithError(error:NSError!) { func webSocketDidFailWithError(error:NSError!) {
self.connected = false self._connected = false
self.connecting = false self._connecting = false
self.handleEvent("error", data: error.localizedDescription, isInternalMessage: true) self.handleEvent("error", data: error.localizedDescription, isInternalMessage: true)
if self.closed || !self.reconnects { if self.closed || !self.reconnects {
self.didForceClose() self.didForceClose()
@ -841,4 +442,4 @@ public class SocketIOClient: NSObject {
self.tryReconnect() self.tryReconnect()
} }
} }
} }

451
SwiftIO/SocketParser.swift Normal file
View File

@ -0,0 +1,451 @@
//
// SocketParser.swift
// Socket.IO-Swift
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
class SocketParser {
// Parse an NSArray looking for binary data
class func parseArray(arr:NSArray, var currentPlaceholder:Int) -> (NSArray, Bool, [NSData]) {
var replacementArr = [AnyObject](count: arr.count, repeatedValue: 1)
var hasBinary = false
var arrayDatas = [NSData]()
for g in 0..<arr.count {
if arr[g] is NSData {
hasBinary = true
currentPlaceholder++
let sendData = arr[g] as! NSData
arrayDatas.append(sendData)
replacementArr[g] = ["_placeholder": true,
"num": currentPlaceholder]
} else if let dict = arr[g] as? NSDictionary {
let (nestDict, hadBinary, dictArrs) = self.parseNSDictionary(dict,
currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
currentPlaceholder += dictArrs.count
replacementArr[g] = nestDict
arrayDatas.extend(dictArrs)
} else {
replacementArr[g] = dict
}
} else if let nestArr = arr[g] as? NSArray {
// Recursive
let (nested, hadBinary, nestDatas) = self.parseArray(nestArr,
currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
currentPlaceholder += nestDatas.count
replacementArr[g] = nested
arrayDatas.extend(nestDatas)
} else {
replacementArr[g] = arr[g]
}
} else {
replacementArr[g] = arr[g]
}
}
return (replacementArr, hasBinary, arrayDatas)
}
// Parses data for events
class func parseData(data:String?) -> AnyObject? {
if data == nil {
return nil
}
var err:NSError?
let stringData = data!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let parsed:AnyObject? = NSJSONSerialization.JSONObjectWithData(stringData!,
options: NSJSONReadingOptions.AllowFragments, error: &err)
if err != nil {
// println(err)
return nil
}
return parsed
}
class func parseEmitArgs(args:[AnyObject]) -> ([AnyObject], Bool, [NSData]) {
var items = [AnyObject](count: args.count, repeatedValue: 1)
var currentPlaceholder = -1
var hasBinary = false
var emitDatas = [NSData]()
for i in 0..<args.count {
if let dict = args[i] as? NSDictionary {
// Check for binary data
let (newDict, hadBinary, binaryDatas) = self.parseNSDictionary(dict,
currentPlaceholder: currentPlaceholder)
if hadBinary {
currentPlaceholder += binaryDatas.count
emitDatas.extend(binaryDatas)
hasBinary = true
items[i] = newDict
} else {
items[i] = dict
}
} else if let arr = args[i] as? NSArray {
// arg is array, check for binary
let (replace, hadData, newDatas) = self.parseArray(arr,
currentPlaceholder: currentPlaceholder)
if hadData {
hasBinary = true
currentPlaceholder += newDatas.count
for data in newDatas {
emitDatas.append(data)
}
items[i] = replace
} else {
items[i] = arr
}
} else if let binaryData = args[i] as? NSData {
// args is just binary
hasBinary = true
currentPlaceholder++
items[i] = ["_placeholder": true, "num": currentPlaceholder]
emitDatas.append(binaryData)
} else {
items[i] = args[i]
}
}
return (items, hasBinary, emitDatas)
}
// Parses a NSDictionary, looking for NSData objects
class func parseNSDictionary(dict:NSDictionary, var currentPlaceholder:Int) -> (NSDictionary, Bool, [NSData]) {
var returnDict = NSMutableDictionary()
var hasBinary = false
var returnDatas = [NSData]()
for (key, value) in dict {
if let binaryData = value as? NSData {
currentPlaceholder++
hasBinary = true
returnDatas.append(binaryData)
returnDict[key as! String] = ["_placeholder": true, "num": currentPlaceholder]
} else if let arr = value as? NSArray {
let (replace, hadBinary, arrDatas) = self.parseArray(arr, currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
returnDict[key as! String] = replace
currentPlaceholder += arrDatas.count
returnDatas.extend(arrDatas)
} else {
returnDict[key as! String] = arr
}
} else if let dict = value as? NSDictionary {
// Recursive
let (nestDict, hadBinary, nestDatas) = self.parseNSDictionary(dict, currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
returnDict[key as! String] = nestDict
currentPlaceholder += nestDatas.count
returnDatas.extend(nestDatas)
} else {
returnDict[key as! String] = dict
}
} else {
returnDict[key as! String] = value
}
}
return (returnDict, hasBinary, returnDatas)
}
// Parses messages recieved
class func parseSocketMessage(stringMessage:String, socket:SocketIOClient) {
// println(message!)
// Check for successful namepsace connect
if socket.nsp != nil {
if stringMessage == "0/\(socket.nsp!)" {
socket.didConnect()
return
}
}
if stringMessage == "0" {
if socket.nsp != nil {
// Join namespace
socket.joinNamespace()
return
} else {
socket.didConnect()
return
}
}
var mutMessage = RegexMutable(stringMessage)
/**
Begin check for message
**/
let messageGroups = mutMessage["(\\d*)\\/?(\\w*)?,?(\\d*)?(\\[.*\\])?"].groups()
if messageGroups[1].hasPrefix("2") {
var mesNum = messageGroups[1]
var ackNum:String
var namespace:String?
var messagePart:String!
if messageGroups[3] != "" {
ackNum = messageGroups[3]
} else {
let range = Range<String.Index>(start: mesNum.startIndex,
end: advance(mesNum.startIndex, 1))
mesNum.replaceRange(range, with: "")
ackNum = mesNum
}
namespace = messageGroups[2]
messagePart = messageGroups[4]
if namespace == "" && socket.nsp != nil {
return
}
let messageInternals = RegexMutable(messagePart)["\\[\"(.*?)\",(.*?)?\\]$"].groups()
if messageInternals != nil && messageInternals.count > 2 {
let event = messageInternals[1]
var data:String?
if messageInternals[2] == "" {
data = nil
} else {
data = messageInternals[2]
}
// It would be nice if socket.io only allowed one thing
// per message, but alas, it doesn't.
if let parsed:AnyObject = self.parseData(data) {
if ackNum == "" {
socket.handleEvent(event, data: parsed)
} else {
socket.currentAck = ackNum.toInt()!
socket.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
} else if let strData = data {
// There are multiple items in the message
// Turn it into a String and run it through
// parseData to try and get an array.
let asArray = "[\(strData)]"
if let parsed:AnyObject = self.parseData(asArray) {
if ackNum == "" {
socket.handleEvent(event, data: parsed)
} else {
socket.currentAck = ackNum.toInt()!
socket.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
}
}
}
// Check for no item event
let noItemMessage = RegexMutable(messagePart)["\\[\"(.*?)\"]$"].groups()
if noItemMessage != nil && noItemMessage.count == 2 {
let event = noItemMessage[1]
if ackNum == "" {
socket.handleEvent(event, data: nil)
} else {
socket.currentAck = ackNum.toInt()!
socket.handleEvent(event, data: nil, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
}
} else if messageGroups[1].hasPrefix("3") {
let arr = Array(messageGroups[1])
var ackNum:String
let nsp = messageGroups[2]
if nsp == "" && socket.nsp != nil {
return
}
if nsp == "" {
ackNum = String(arr[1...arr.count-1])
} else {
ackNum = messageGroups[3]
}
let ackData:AnyObject? = self.parseData(messageGroups[4])
socket.handleAck(ackNum.toInt()!, data: ackData)
return
}
/**
End Check for message
**/
// Check for message with binary placeholders
self.parseBinaryMessage(stringMessage, socket: socket)
}
// Handles binary data
class func parseBinaryData(data:NSData, socket:SocketIOClient) {
let shouldExecute = socket.waitingData[0].addData(data)
if shouldExecute {
let socketEvent = socket.waitingData.removeAtIndex(0)
var event = socketEvent.event
var parsedArgs:AnyObject? = self.parseData(socketEvent.args as? String)
if let args:AnyObject = parsedArgs {
let filledInArgs:AnyObject = socketEvent.fillInPlaceholders(args)
if socketEvent.justAck! {
// Should handle ack
socket.handleAck(socketEvent.ack!, data: filledInArgs)
return
}
// Should do event
if socketEvent.ack != nil {
socket.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: socketEvent.ack!, withAckType: 6)
} else {
socket.handleEvent(event, data: filledInArgs)
}
} else {
let filledInArgs:AnyObject = socketEvent.fillInPlaceholders()
// Should handle ack
if socketEvent.justAck! {
socket.handleAck(socketEvent.ack!, data: filledInArgs)
return
}
// Should handle ack
if socketEvent.ack != nil {
socket.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: socketEvent.ack!, withAckType: 6)
} else {
socket.handleEvent(event, data: filledInArgs)
}
}
}
}
// Tries to parse a message that contains binary
class func parseBinaryMessage(message:String, socket:SocketIOClient) {
// println(message)
var mutMessage = RegexMutable(message)
/**
Begin check for binary placeholders
**/
let binaryGroup = mutMessage["^(\\d*)-\\/?(\\w*)?,?(\\d*)?\\[(\".*?\")?,?(.*)?\\]$"].groups()
if binaryGroup == nil {
return
}
if binaryGroup[1].hasPrefix("5") {
// println(binaryGroup)
var ackNum:String
var event:String
var mutMessageObject:NSMutableString
var namespace:String?
var numberOfPlaceholders:String
let messageType = RegexMutable(binaryGroup[1])
namespace = binaryGroup[2]
if binaryGroup[3] != "" {
ackNum = binaryGroup[3] as String
} else if socket.nsp == nil && binaryGroup[2] != "" {
ackNum = binaryGroup[2]
} else {
ackNum = ""
}
numberOfPlaceholders = (messageType["5"] ~= "") as String
event = (RegexMutable(binaryGroup[4])["\""] ~= "") as String
mutMessageObject = RegexMutable(binaryGroup[5])
if namespace == "" && socket.nsp != nil {
return
}
let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"]
~= "\"~~$2\""
var mes:SocketEvent
if ackNum == "" {
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!)
} else {
socket.currentAck = ackNum.toInt()!
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt())
}
socket.waitingData.append(mes)
} else if binaryGroup[1].hasPrefix("6") {
let messageType = RegexMutable(binaryGroup[1])
let numberOfPlaceholders = (messageType["6"] ~= "") as String
var ackNum:String
var nsp:String
if binaryGroup[3] == "" {
ackNum = binaryGroup[2]
nsp = ""
} else {
ackNum = binaryGroup[3]
nsp = binaryGroup[2]
}
if nsp == "" && socket.nsp != nil {
return
}
var mutMessageObject = RegexMutable(binaryGroup[5])
let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"]
~= "\"~~$2\""
let event = SocketEvent(event: "", args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt(), justAck: true)
socket.waitingData.append(event)
}
/**
End check for binary placeholders
**/
}
}

View File

@ -16,7 +16,7 @@ public protocol WebSocketDelegate: class {
} }
public class WebSocket : NSObject, NSStreamDelegate { public class WebSocket : NSObject, NSStreamDelegate {
enum OpCode : UInt8 { enum OpCode : UInt8 {
case ContinueFrame = 0x0 case ContinueFrame = 0x0
case TextFrame = 0x1 case TextFrame = 0x1
@ -27,7 +27,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
case Pong = 0xA case Pong = 0xA
//B-F reserved. //B-F reserved.
} }
enum CloseCode : UInt16 { enum CloseCode : UInt16 {
case Normal = 1000 case Normal = 1000
case GoingAway = 1001 case GoingAway = 1001
@ -40,15 +40,15 @@ public class WebSocket : NSObject, NSStreamDelegate {
case PolicyViolated = 1008 case PolicyViolated = 1008
case MessageTooBig = 1009 case MessageTooBig = 1009
} }
enum InternalErrorCode : UInt16 { enum InternalErrorCode : UInt16 {
// 0-999 WebSocket status codes not used // 0-999 WebSocket status codes not used
case OutputStreamWriteError = 1 case OutputStreamWriteError = 1
} }
//Where the callback is executed. It defaults to the main UI thread queue. //Where the callback is executed. It defaults to the main UI thread queue.
public var queue = dispatch_get_main_queue() public var queue = dispatch_get_main_queue()
var optionalProtocols : Array<String>? var optionalProtocols : Array<String>?
//Constant Values. //Constant Values.
let headerWSUpgradeName = "Upgrade" let headerWSUpgradeName = "Upgrade"
@ -69,7 +69,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
let MaskMask: UInt8 = 0x80 let MaskMask: UInt8 = 0x80
let PayloadLenMask: UInt8 = 0x7F let PayloadLenMask: UInt8 = 0x7F
let MaxFrameSize: Int = 32 let MaxFrameSize: Int = 32
class WSResponse { class WSResponse {
var isFin = false var isFin = false
var code: OpCode = .ContinueFrame var code: OpCode = .ContinueFrame
@ -77,7 +77,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
var frameCount = 0 var frameCount = 0
var buffer: NSMutableData? var buffer: NSMutableData?
} }
public weak var delegate: WebSocketDelegate? public weak var delegate: WebSocketDelegate?
private var url: NSURL private var url: NSURL
private var inputStream: NSInputStream? private var inputStream: NSInputStream?
@ -98,7 +98,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
public var isConnected :Bool { public var isConnected :Bool {
return connected return connected
} }
//init the websocket with a url //init the websocket with a url
public init(url: NSURL) { public init(url: NSURL) {
self.url = url self.url = url
@ -130,43 +130,43 @@ public class WebSocket : NSObject, NSStreamDelegate {
disconnectedBlock = disconnect disconnectedBlock = disconnect
receivedDataBlock = data receivedDataBlock = data
} }
///Connect to the websocket server on a background thread ///Connect to the websocket server on a background thread
public func connect() { public func connect() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), {
self.createHTTPRequest() self.createHTTPRequest()
}) })
} }
///disconnect from the websocket server ///disconnect from the websocket server
public func disconnect() { public func disconnect() {
writeError(CloseCode.Normal.rawValue) writeError(CloseCode.Normal.rawValue)
} }
///write a string to the websocket. This sends it as a text frame. ///write a string to the websocket. This sends it as a text frame.
public func writeString(str: String) { public func writeString(str: String) {
dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame) dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame)
} }
///write binary data to the websocket. This sends it as a binary frame. ///write binary data to the websocket. This sends it as a binary frame.
public func writeData(data: NSData) { public func writeData(data: NSData) {
dequeueWrite(data, code: .BinaryFrame) dequeueWrite(data, code: .BinaryFrame)
} }
//write a ping to the websocket. This sends it as a control frame. //write a ping to the websocket. This sends it as a control frame.
//yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s //yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s
public func writePing(data: NSData) { public func writePing(data: NSData) {
dequeueWrite(data, code: .Ping) dequeueWrite(data, code: .Ping)
} }
//private methods below! //private methods below!
//private method that starts the connection //private method that starts the connection
private func createHTTPRequest() { private func createHTTPRequest() {
let str: NSString = url.absoluteString! let str: NSString = url.absoluteString!
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET", let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET",
url, kCFHTTPVersion1_1) url, kCFHTTPVersion1_1)
var port = url.port var port = url.port
if port == nil { if port == nil {
if url.scheme == "wss" || url.scheme == "https" { if url.scheme == "wss" || url.scheme == "https" {
@ -187,7 +187,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
for (key,value) in headers { for (key,value) in headers {
self.addHeader(urlRequest, key: key, val: value) self.addHeader(urlRequest, key: key, val: value)
} }
let serializedRequest: NSData = CFHTTPMessageCopySerializedMessage(urlRequest.takeUnretainedValue()).takeUnretainedValue() let serializedRequest: NSData = CFHTTPMessageCopySerializedMessage(urlRequest.takeUnretainedValue()).takeUnretainedValue()
self.initStreamsWithData(serializedRequest, Int(port!)) self.initStreamsWithData(serializedRequest, Int(port!))
} }
@ -215,14 +215,14 @@ public class WebSocket : NSObject, NSStreamDelegate {
private func initStreamsWithData(data: NSData, _ port: Int) { private func initStreamsWithData(data: NSData, _ port: Int) {
//higher level API we will cut over to at some point //higher level API we will cut over to at some point
//NSStream.getStreamsToHostWithName(url.host, port: url.port.integerValue, inputStream: &inputStream, outputStream: &outputStream) //NSStream.getStreamsToHostWithName(url.host, port: url.port.integerValue, inputStream: &inputStream, outputStream: &outputStream)
var readStream: Unmanaged<CFReadStream>? var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>? var writeStream: Unmanaged<CFWriteStream>?
let h: NSString = url.host! let h: NSString = url.host!
CFStreamCreatePairWithSocketToHost(nil, h, UInt32(port), &readStream, &writeStream) CFStreamCreatePairWithSocketToHost(nil, h, UInt32(port), &readStream, &writeStream)
inputStream = readStream!.takeUnretainedValue() inputStream = readStream!.takeUnretainedValue()
outputStream = writeStream!.takeUnretainedValue() outputStream = writeStream!.takeUnretainedValue()
inputStream!.delegate = self inputStream!.delegate = self
outputStream!.delegate = self outputStream!.delegate = self
if url.scheme == "wss" || url.scheme == "https" { if url.scheme == "wss" || url.scheme == "https" {
@ -251,7 +251,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
//delegate for the stream methods. Processes incoming bytes //delegate for the stream methods. Processes incoming bytes
public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) { public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
if eventCode == .HasBytesAvailable { if eventCode == .HasBytesAvailable {
if(aStream == inputStream) { if(aStream == inputStream) {
processInputStream() processInputStream()
@ -282,7 +282,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
self.delegate?.websocketDidDisconnect(self, error: error) self.delegate?.websocketDidDisconnect(self, error: error)
}) })
} }
///handles the incoming bytes and sending them to the proper processing method ///handles the incoming bytes and sending them to the proper processing method
private func processInputStream() { private func processInputStream() {
let buf = NSMutableData(capacity: BUFFER_MAX) let buf = NSMutableData(capacity: BUFFER_MAX)
@ -365,7 +365,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
return false return false
} }
///validates the HTTP is a 101 as per the RFC spec ///validates the HTTP is a 101 as per the RFC spec
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool { private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, 0) let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, 0)
@ -381,7 +381,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
return false return false
} }
///process the websocket data ///process the websocket data
private func processRawMessage(buffer: UnsafePointer<UInt8>, bufferLen: Int) { private func processRawMessage(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
var response = readStack.last var response = readStack.last
@ -563,16 +563,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
processResponse(response!) processResponse(response!)
} }
let step = offset + Int(len) let step = offset + Int(len)
let extra = bufferLen-step let extra = bufferLen-step
if(extra > 0) { if(extra > 0) {
processExtra((buffer+step), bufferLen: extra) processExtra((buffer+step), bufferLen: extra)
} }
} }
} }
///process the extra of a buffer ///process the extra of a buffer
private func processExtra(buffer: UnsafePointer<UInt8>, bufferLen: Int) { private func processExtra(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
if bufferLen < 2 { if bufferLen < 2 {
@ -581,7 +581,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
processRawMessage(buffer, bufferLen: bufferLen) processRawMessage(buffer, bufferLen: bufferLen)
} }
} }
///process the finished response of a buffer ///process the finished response of a buffer
private func processResponse(response: WSResponse) -> Bool { private func processResponse(response: WSResponse) -> Bool {
if response.isFin && response.bytesLeft <= 0 { if response.isFin && response.bytesLeft <= 0 {
@ -615,14 +615,14 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
return false return false
} }
///Create an error ///Create an error
private func errorWithDetail(detail: String, code: UInt16) -> NSError { private func errorWithDetail(detail: String, code: UInt16) -> NSError {
var details = Dictionary<String,String>() var details = Dictionary<String,String>()
details[NSLocalizedDescriptionKey] = detail details[NSLocalizedDescriptionKey] = detail
return NSError(domain: "Websocket", code: Int(code), userInfo: details) return NSError(domain: "Websocket", code: Int(code), userInfo: details)
} }
///write a an error to the socket ///write a an error to the socket
private func writeError(code: UInt16) { private func writeError(code: UInt16) {
let buf = NSMutableData(capacity: sizeof(UInt16)) let buf = NSMutableData(capacity: sizeof(UInt16))
@ -674,7 +674,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
var maskKey = UnsafeMutablePointer<UInt8>(buffer + offset) var maskKey = UnsafeMutablePointer<UInt8>(buffer + offset)
SecRandomCopyBytes(kSecRandomDefault, Int(sizeof(UInt32)), maskKey) SecRandomCopyBytes(kSecRandomDefault, Int(sizeof(UInt32)), maskKey)
offset += sizeof(UInt32) offset += sizeof(UInt32)
for (var i = 0; i < dataLength; i++) { for (var i = 0; i < dataLength; i++) {
buffer[offset] = bytes[i] ^ maskKey[i % sizeof(UInt32)] buffer[offset] = bytes[i] ^ maskKey[i % sizeof(UInt32)]
offset += 1 offset += 1
@ -706,8 +706,8 @@ public class WebSocket : NSObject, NSStreamDelegate {
break break
} }
} }
} }
} }
} }