#2. Add support for messages that have multiple items. Add support for sending messages with multiple messages

This commit is contained in:
Erik 2015-01-19 19:33:16 -05:00
parent 2298cb2a1a
commit a5db559bed
3 changed files with 242 additions and 71 deletions

View File

@ -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

View File

@ -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)
}
}

View File

@ -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..<arr.count {
if arr[i] is NSData {
hadBinary = true
placeholders[i] = ["_placeholder": true, "num": placeNum]
datas.append(self.createBinaryDataForSend(arr[i] as NSData))
placeNum++
} else {
placeholders[i] = arr[i]
}
}
if hadBinary {
str = Event.createMessageForEvent(event, withArgs: [placeholders],
hasBinary: true, withDatas: datas.count)
self.io?.send(str)
for data in datas {
self.io?.send(data)
}
return
}
}
frame = Event(event: event, args: args)
str = frame.createMessage()
if args == nil {
str = "42[\"\(event)\"]"
} else {
str = Event.createMessageForEvent(event, withArgs: [args!], hasBinary: false)
}
// println("Sending: \(str)")
self.io?.send(str)
}
// Sends a message with multiple args
// If a message contains binary we have to send those
// seperately.
func emitMultiple(event:String, args:AnyObject...) {
if !self.connected {
return
}
var frame:Event
var str:String
var items = [AnyObject](count: args.count, repeatedValue: 1)
var numberOfPlaceholders = -1
var hasBinary = false
var datas = [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,
placeholders: numberOfPlaceholders + 1)
if hadBinary {
numberOfPlaceholders = binaryDatas!.count
for data in binaryDatas! {
let sendData = self.createBinaryDataForSend(data)
datas.append(sendData)
}
hasBinary = true
items[i] = newDict
continue
}
items[i] = dict
} else if let arr = args[i] as? NSArray {
// arg is array, check for binary
var replacementArr = [AnyObject](count: arr.count, repeatedValue: 1)
for g in 0..<arr.count {
if arr[g] is NSData {
hasBinary = true
numberOfPlaceholders++
let sendData = self.createBinaryDataForSend(arr[g] as NSData)
datas.append(sendData)
replacementArr[g] = ["_placeholder": true,
"num": numberOfPlaceholders]
} else {
replacementArr[g] = arr[g]
}
}
items[i] = replacementArr
} else if let binaryData = args[i] as? NSData {
// args is just binary
hasBinary = true
let sendData = self.createBinaryDataForSend(binaryData)
numberOfPlaceholders++
items[i] = ["_placeholder": true, "num": numberOfPlaceholders]
datas.append(sendData)
} else {
items[i] = args[i]
}
}
if hasBinary {
str = Event.createMessageForEvent(event, withArgs: items,
hasBinary: true, withDatas: datas.count)
self.io?.send(str)
for data in datas {
self.io?.send(data)
}
} else {
str = Event.createMessageForEvent(event, withArgs: items, hasBinary: false)
self.io?.send(str)
}
}
// Handles events
func handleEvent(#event:String, data:AnyObject?) {
func handleEvent(#event:String, data:AnyObject?, multipleItems:Bool = false) {
// println("Should do event: \(event) with data: \(data)")
for handler in self.handlers {
if handler.event == event {
if handler.event == event && !multipleItems {
if data == nil {
handler.executeCallback(nil)
continue
}
handler.executeCallback(data)
} else if handler.event == event && multipleItems {
if let arr = data as? [AnyObject] {
handler.executeCallback(arr)
continue
}
}
}
}
// Adds handlers to the socket
// Adds handler for single arg message
func on(name:String, callback:((data:AnyObject?) -> 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
}
}
}