diff --git a/SwiftIO/Event.swift b/SwiftIO/Event.swift index bc9edd0..9a89122 100644 --- a/SwiftIO/Event.swift +++ b/SwiftIO/Event.swift @@ -26,9 +26,9 @@ import Foundation class Event { var args:AnyObject! - var currentPlace = 0 - var event:String! + lazy var currentPlace = 0 lazy var datas = [NSData]() + var event:String! var placeholders:Int! init(event:String, args:AnyObject?, placeholders:Int = 0) { @@ -61,48 +61,42 @@ class Event { } } - func createMessage() -> String { - var array = "42[" - array += "\"" + event + "\"" - - if args? != nil { - if args is NSDictionary { - array += "," - var jsonSendError:NSError? - var jsonSend = NSJSONSerialization.dataWithJSONObject(args as NSDictionary, - options: NSJSONWritingOptions(0), error: &jsonSendError) - var jsonString = NSString(data: jsonSend!, encoding: NSUTF8StringEncoding) - return array + jsonString! + "]" + class func createMessageForEvent(event:String, withArgs args:[AnyObject], + hasBinary:Bool, withDatas datas:Int = 0) -> String { + + var message:String + var jsonSendError:NSError? + + if !hasBinary { + message = "42[\"\(event)\"" } else { - array += ",\"\(args!)\"" - return array + "]" + message = "45\(datas)-[\"\(event)\"" } - } else { - return array + "]" - } + + for arg in args { + message += "," + + if arg is NSDictionary || arg is [AnyObject] { + let jsonSend = NSJSONSerialization.dataWithJSONObject(arg, + options: NSJSONWritingOptions(0), error: &jsonSendError) + let jsonString = NSString(data: jsonSend!, encoding: NSUTF8StringEncoding) + + message += jsonString! + continue + } + + if arg is String { + message += "\"\(arg)\"" + continue + } + + message += "\(arg)" + } + + return message + "]" } - func createBinaryMessage() -> String { - var array = "45\(self.placeholders)-[" - array += "\"" + event + "\"" - if args? != nil { - if args is NSDictionary { - array += "," - var jsonSendError:NSError? - var jsonSend = NSJSONSerialization.dataWithJSONObject(args as NSDictionary, - options: NSJSONWritingOptions(0), error: &jsonSendError) - var jsonString = NSString(data: jsonSend!, encoding: NSUTF8StringEncoding) - return array + jsonString! + "]" - } else { - array += ",\"\(args!)\"" - return array + "]" - } - } else { - return array + "]" - } - } - - func fillInPlaceholders(args:AnyObject) -> AnyObject { + func fillInPlaceholders(_ args:AnyObject = true) -> AnyObject { if let dict = args as? NSDictionary { var newDict = [String: AnyObject]() @@ -124,6 +118,27 @@ class Event { if string == "~~\(self.currentPlace)" { return self.datas.removeAtIndex(0) } + } else if args is Bool { + var returnArr = [AnyObject]() + // We have multiple items + // Do it live + let argsAsArray = "[\(self.args)]" + if let parsedArr = SocketIOClient.parseData(argsAsArray) as? NSArray { + for item in parsedArr { + if let strItem = item as? String { + if strItem == "~~\(self.currentPlace)" { + returnArr.append(self.datas[self.currentPlace]) + self.currentPlace++ + continue + } else { + returnArr.append(strItem) + } + } else { + returnArr.append(item) + } + } + return returnArr + } } return false diff --git a/SwiftIO/EventHandler.swift b/SwiftIO/EventHandler.swift index 34e49c4..21a5af0 100644 --- a/SwiftIO/EventHandler.swift +++ b/SwiftIO/EventHandler.swift @@ -22,17 +22,21 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import Foundation - -class EventHandler: NSObject { +class EventHandler { let event:String! let callback:((data:AnyObject?) -> Void)! + var callbackMult:((data:[AnyObject]) -> Void)! - init(event:String, callback:((data:AnyObject?) -> Void)?) { + init(event:String, callback:((data:AnyObject?) -> Void)) { self.event = event self.callback = callback } + init(event:String, callback:((data:[AnyObject]) -> Void)) { + self.event = event + self.callbackMult = callback + } + func executeCallback(args:AnyObject?) { if args != nil { callback(data: args!) @@ -40,4 +44,8 @@ class EventHandler: NSObject { callback(data: nil) } } + + func executeCallback(args:[AnyObject]) { + callbackMult(data: args) + } } \ No newline at end of file diff --git a/SwiftIO/SocketIOClient.swift b/SwiftIO/SocketIOClient.swift index 8c09988..5349b02 100644 --- a/SwiftIO/SocketIOClient.swift +++ b/SwiftIO/SocketIOClient.swift @@ -26,13 +26,13 @@ import Foundation class SocketIOClient: NSObject, SRWebSocketDelegate { let socketURL:String! - let secure:Bool! + private let secure:Bool! private var handlers = [EventHandler]() private var lastSocketMessage:Event? + private var pingTimer:NSTimer! var connected = false var connecting = false var io:SRWebSocket? - var pingTimer:NSTimer! var reconnnects = true var reconnecting = false var reconnectAttempts = -1 @@ -110,14 +110,13 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } var frame:Event! - var str:String! + var str:String if let dict = args as? NSDictionary { // Check for binary data - let (newDict, hadBinary, binaryDatas) = self.parseNSDictionary(dict: dict) + let (newDict, hadBinary, binaryDatas) = self.parseNSDictionary(dict) if hadBinary { - frame = Event(event: event, args: newDict, placeholders: binaryDatas!.count) - str = frame.createBinaryMessage() + str = Event.createMessageForEvent(event, withArgs: [newDict], hasBinary: true, withDatas: binaryDatas!.count) self.io?.send(str) for data in binaryDatas! { @@ -129,51 +128,169 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } } else if let binaryData = args as? NSData { // args is just binary - frame = Event(event: event, args: ["_placeholder": true, "num": 0], placeholders: 1) - str = frame.createBinaryMessage() + str = Event.createMessageForEvent(event, withArgs: [["_placeholder": true, "num": 0]], + hasBinary: true, withDatas: 1) + self.io?.send(str) let sendData = self.createBinaryDataForSend(binaryData) self.io?.send(sendData) return + } else if let arr = args as? NSArray { + var hadBinary = false + var placeholders = [AnyObject](count: arr.count, repeatedValue: 1) + var datas = [NSData]() + var placeNum = 0 + + for i in 0.. Void)) { let handler = EventHandler(event: name, callback: callback) self.handlers.append(handler) } + // Adds handler for multiple arg message + func onMultipleArgs(name:String, callback:((data:[AnyObject]) -> Void)) { + let handler = EventHandler(event: name, callback: callback) + self.handlers.append(handler) + } + // Opens the connection to the socket func open() { self.connect() } // Parses data for events - private func parseData(data:String?) -> AnyObject? { + class func parseData(data:String?) -> AnyObject? { if data == nil { return nil } @@ -192,9 +309,9 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } // Parses a NSDictionary, looking for NSData objects - private func parseNSDictionary(#dict:NSDictionary) -> (NSDictionary, Bool, [NSData]?) { + private func parseNSDictionary(dict:NSDictionary, placeholders:Int = 0) -> (NSDictionary, Bool, [NSData]?) { var returnDict = NSMutableDictionary() - var placeholder = 0 + var placeholder = placeholders var containedData = false var returnDatas = [NSData]() for (key, value) in dict { @@ -262,13 +379,22 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { data = messageInternals[2] } - if let json:AnyObject = self.parseData(data) { - self.handleEvent(event: event, data: json) + // 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) { + self.handleEvent(event: event, data: parsed) 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) { + self.handleEvent(event: event, data: parsed, multipleItems: true) + return + } } - - self.handleEvent(event: event, data: data) - return } } /** @@ -286,12 +412,12 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } // Tries to parse a message that contains binary - func parseBinaryMessage(#message:AnyObject) { + private func parseBinaryMessage(#message:AnyObject) { if let stringMessage = message as? String { var mutMessage = RegexMutable(stringMessage) /** - Begin check for binary placeholder + Begin check for binary placeholders **/ let binaryGroup = mutMessage["(\\d*)-\\[\"(.*)\",(\\{.*\\})\\]$"].groups() @@ -301,28 +427,50 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { let numberOfPlaceholders = messageType["45"] ~= "" let event = binaryGroup[2] let mutMessageObject = RegexMutable(binaryGroup[3]) - let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] ~= "\"~~$2\"" + let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] + ~= "\"~~$2\"" let mes = Event(event: event, args: placeholdersRemoved, placeholders: numberOfPlaceholders.integerValue) self.lastSocketMessage = mes return + } else { + // There are multiple items in binary message + let binaryGroups = mutMessage["(\\d*)-\\[(\".*?\"),(.*)\\]$"].groups() + if binaryGroups != nil { + let messageType = RegexMutable(binaryGroups[1]) + let numberOfPlaceholders = messageType["45"] ~= "" + let event = RegexMutable(binaryGroups[2] as String)["\""] ~= "" + let mutMessageObject = RegexMutable(binaryGroups[3]) + let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] + ~= "\"~~$2\"" + let mes = Event(event: event, args: placeholdersRemoved, + placeholders: numberOfPlaceholders.integerValue) + self.lastSocketMessage = mes + return + } } /** - End check for binary placeholder + End check for binary placeholders **/ } } // Handles binary data - func parseBinaryData(data:NSData) { + private func parseBinaryData(data:NSData) { let shouldExecute = self.lastSocketMessage?.addData(data) if shouldExecute != nil && shouldExecute! { var event = self.lastSocketMessage!.event - var parsedArgs:AnyObject? = self.parseData(self.lastSocketMessage!.args as? String) + var parsedArgs:AnyObject? = SocketIOClient.parseData(self.lastSocketMessage!.args as? String) + if let args:AnyObject = parsedArgs { let filledInArgs:AnyObject = self.lastSocketMessage!.fillInPlaceholders(args) self.handleEvent(event: event, data: filledInArgs) + } else { + // We have multiple items + let filledInArgs:AnyObject = self.lastSocketMessage!.fillInPlaceholders() + self.handleEvent(event: event, data: filledInArgs, multipleItems: true) + return } } }