From 68da96f37dc80f31e0d2e6b0704fd10ac3ba1006 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 16 Mar 2015 09:23:21 -0400 Subject: [PATCH 1/6] fix for objc --- SwiftIO/SocketIOClient.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SwiftIO/SocketIOClient.swift b/SwiftIO/SocketIOClient.swift index 9ec61bc..b43a944 100644 --- a/SwiftIO/SocketIOClient.swift +++ b/SwiftIO/SocketIOClient.swift @@ -116,6 +116,10 @@ public class SocketIOClient: NSObject { self.engine = SocketEngine(client: self, forcePolling: self.forcePolling) } + public convenience init(socketURL:String, opts:NSDictionary?) { + self.init(socketURL: socketURL, opts: opts) + } + // Closes the socket public func close() { self._closed = true From 90187aa4585ed55d277e2432f645c745c79061d5 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 16 Mar 2015 11:47:42 -0400 Subject: [PATCH 2/6] fix convenience constructor. Bump version --- README.md | 10 ++++++---- Socket.IO-Client-Swift.podspec | 4 ++-- SwiftIO/SocketIOClient.swift | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d197693..baa81ce 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,11 @@ import Socket_IO_Client_Swift API === -Constructor +Constructors ----------- -`init(socketURL: String, opts:[String: AnyObject]? = nil)` - Constructs a new client for the given URL. opts can be omitted (will use default values. See example) +`init(socketURL: String, opts:NSDictionary? = nil)` - Constructs a new client for the given URL. opts can be omitted (will use default values. See example) + +`convenience init(socketURL: String, options:NSDictionary? = nil)` - Same as above, but meant for Objective-C. See Objective-C Example. Methods ------- 1. `socket.on(name:String, callback:((data:NSArray?, ack:AckEmitter?) -> Void))` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example. @@ -124,12 +126,12 @@ socket.connect() Objective-C Example =================== ```objective-c -SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8080" opts:nil]; +SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8080" options:nil]; [socket on: @"connect" callback: ^(NSArray* data, void (^ack)(NSArray*)) { NSLog(@"connected"); [socket emitObjc:@"echo" :@[@"echo test"]]; - [[socket emitWithAckObjc:@"ackack" :@[@"test"]] onAck:^(NSArray* data) { + [[socket emitWithAckObjc:@"ackack" :@[@"test"]] onAck:0 withCallback:^(NSArray* data) { NSLog(@"Got data"); }]; }]; diff --git a/Socket.IO-Client-Swift.podspec b/Socket.IO-Client-Swift.podspec index e689e1a..7024656 100644 --- a/Socket.IO-Client-Swift.podspec +++ b/Socket.IO-Client-Swift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Socket.IO-Client-Swift" - s.version = "1.1.4" + s.version = "1.1.5" s.summary = "Socket.IO-client for Swift" s.description = <<-DESC Socket.IO-client for Swift. @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.author = { "Erik" => "nuclear.ace@gmail.com" } s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.10' - s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v1.1.4' } + s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v1.1.5' } s.source_files = "SwiftIO/**/*.swift" s.requires_arc = true # s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files diff --git a/SwiftIO/SocketIOClient.swift b/SwiftIO/SocketIOClient.swift index b43a944..330ffbf 100644 --- a/SwiftIO/SocketIOClient.swift +++ b/SwiftIO/SocketIOClient.swift @@ -74,7 +74,7 @@ public class SocketIOClient: NSObject { return self._sid } - public init(var socketURL:String, opts:[String: AnyObject]? = nil) { + public init(var socketURL:String, opts:NSDictionary? = nil) { if socketURL["https://"].matches().count != 0 { self._secure = true } @@ -116,8 +116,8 @@ public class SocketIOClient: NSObject { self.engine = SocketEngine(client: self, forcePolling: self.forcePolling) } - public convenience init(socketURL:String, opts:NSDictionary?) { - self.init(socketURL: socketURL, opts: opts) + public convenience init(socketURL:String, options:NSDictionary?) { + self.init(socketURL: socketURL, opts: options) } // Closes the socket From 6e84950c05dfda917d8893ddf953ac5e2dd6a078 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 16 Mar 2015 11:49:10 -0400 Subject: [PATCH 3/6] API changed, change version --- Socket.IO-Client-Swift.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Socket.IO-Client-Swift.podspec b/Socket.IO-Client-Swift.podspec index 7024656..67b1fa5 100644 --- a/Socket.IO-Client-Swift.podspec +++ b/Socket.IO-Client-Swift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Socket.IO-Client-Swift" - s.version = "1.1.5" + s.version = "1.2.0" s.summary = "Socket.IO-client for Swift" s.description = <<-DESC Socket.IO-client for Swift. @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.author = { "Erik" => "nuclear.ace@gmail.com" } s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.10' - s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v1.1.5' } + s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v1.2.0' } s.source_files = "SwiftIO/**/*.swift" s.requires_arc = true # s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files From e932d0a26ba81573545ca055660dcb41e277e0fe Mon Sep 17 00:00:00 2001 From: Erik Little Date: Mon, 16 Mar 2015 11:53:14 -0400 Subject: [PATCH 4/6] Fix copypasta --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index baa81ce..87b9da9 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Constructors ----------- `init(socketURL: String, opts:NSDictionary? = nil)` - Constructs a new client for the given URL. opts can be omitted (will use default values. See example) -`convenience init(socketURL: String, options:NSDictionary? = nil)` - Same as above, but meant for Objective-C. See Objective-C Example. +`convenience init(socketURL: String, options:NSDictionary?)` - Same as above, but meant for Objective-C. See Objective-C Example. Methods ------- 1. `socket.on(name:String, callback:((data:NSArray?, ack:AckEmitter?) -> Void))` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example. From fea16879e136c197c08272375c4f7faedf9d4ba1 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 16 Mar 2015 13:12:37 -0400 Subject: [PATCH 5/6] Receive doubly encoded utf8 in polling until https://github.com/Automattic/engine.io/issues/315 is fixed properly --- SwiftIO/SocketEngine.swift | 6 ++- SwiftIO/SocketFixUTF8.swift | 100 ++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 SwiftIO/SocketFixUTF8.swift diff --git a/SwiftIO/SocketEngine.swift b/SwiftIO/SocketEngine.swift index 455a9ee..8ec9ef2 100644 --- a/SwiftIO/SocketEngine.swift +++ b/SwiftIO/SocketEngine.swift @@ -179,7 +179,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { // println(data) - if let str = NSString(data: data, encoding: NSUTF8StringEncoding) { + if var str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String { dispatch_async(self!.parseQueue) {callback(str)} } @@ -221,6 +221,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { for packet in self.postWait { let len = countElements(packet) + postStr += "\(len):\(packet)" } @@ -405,6 +406,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { private func parseEngineMessage(var message:String) { // NSLog("Engine got message: \(message)") + fixDoubleUTF8(&message) // We should upgrade if message == "3probe" { @@ -582,4 +584,4 @@ public class SocketEngine: NSObject, WebSocketDelegate { public func websocketDidReceiveData(socket:WebSocket, data:NSData) { self.parseEngineData(data) } -} \ No newline at end of file +} diff --git a/SwiftIO/SocketFixUTF8.swift b/SwiftIO/SocketFixUTF8.swift new file mode 100644 index 0000000..0d10fcc --- /dev/null +++ b/SwiftIO/SocketFixUTF8.swift @@ -0,0 +1,100 @@ +// +// SocketFixUTF8.swift +// Socket.IO-Swift +// +// Created by Erik Little on 3/16/15. +// 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. +// +// Adapted from: https://github.com/durbrow/fix-double-utf8.swift + +import Foundation + +var memoizer = [String: UnicodeScalar]() + +func lookup(base:UnicodeScalar, combi:UnicodeScalar) -> UnicodeScalar { + let combined = "\(base)\(combi)" + + if let y = memoizer[combined] { + return y + } + + for i in 0x80...0xFF { + let ch = UnicodeScalar(i) + + if String(ch) == combined { + memoizer[combined] = ch + return ch + } + } + let ch = UnicodeScalar(0xFFFD) // Unicode replacement character � + + memoizer[combined] = ch + return ch +} + +func fixDoubleUTF8(inout name:String) { + var isASCII = true + var y = [UInt8]() + + for ch in name.unicodeScalars { + if ch.value < 0x80 { + y.append(UInt8(ch)) + continue + } + isASCII = false + + if ch.value < 0x100 { + y.append(UInt8(ch)) + continue + } + // might be a combining character that when combined with the + // preceeding character maps to a codepoint in the UTF8 range + if y.count == 0 { + return + } + + let last = y.removeLast() + let repl = lookup(UnicodeScalar(last), ch) + + // the replacement needs to be in the UTF8 range + if repl.value >= 0x100 { + return + } + + y.append(UInt8(repl)) + } + + if isASCII { + return + } + + y.append(0) // null terminator + + return y.withUnsafeBufferPointer { + let cstr = UnsafePointer($0.baseAddress) // typecase from uint8_t * to char * + let rslt = String.fromCStringRepairingIllFormedUTF8(cstr) // -> (String, Bool) + if let str = rslt.0 { + if !rslt.hadError { + name = str + } + } + + return + } +} \ No newline at end of file From 44e27810766a6ff4879d888bbab220ea8ef6073b Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 16 Mar 2015 13:24:25 -0400 Subject: [PATCH 6/6] #11 --- SwiftIO/SocketEngine.swift | 2 +- SwiftIO/SocketParser.swift | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/SwiftIO/SocketEngine.swift b/SwiftIO/SocketEngine.swift index 8ec9ef2..33af2fb 100644 --- a/SwiftIO/SocketEngine.swift +++ b/SwiftIO/SocketEngine.swift @@ -179,7 +179,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { // println(data) - if var str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String { + if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String { dispatch_async(self!.parseQueue) {callback(str)} } diff --git a/SwiftIO/SocketParser.swift b/SwiftIO/SocketParser.swift index 921905f..9791a5b 100644 --- a/SwiftIO/SocketParser.swift +++ b/SwiftIO/SocketParser.swift @@ -217,20 +217,16 @@ class SocketParser { return } - /** Begin check for message **/ - let messageGroups = stringMessage["(\\d*)\\/?(\\w*)?,?(\\d*)?\\[\"(.*?)\",?(.*?)?\\]$"].groups() + let messageGroups = stringMessage["(\\d*)\\/?(\\w*)?,?(\\d*)?\\[\"(.*?)\",?(.*?)?\\]$", + NSRegularExpressionOptions.DotMatchesLineSeparators].groups() if messageGroups == nil { NSLog("Error in groups") return } - // let messageGroups = SwiftRegex(target: stringMessage as NSString, - // pattern: "(\\d*)\\/?(\\w*)?,?(\\d*)?\\[\"(.*?)\",?(.*?)?\\]$", - // options: NSRegularExpressionOptions.DotMatchesLineSeparators).groups() - if messageGroups![1].hasPrefix("2") { var mesNum = messageGroups![1] var ackNum:String @@ -343,10 +339,8 @@ class SocketParser { /** Begin check for binary placeholders **/ - let binaryGroup = message["^(\\d*)-\\/?(\\w*)?,?(\\d*)?\\[(\".*?\")?,?(.*)?\\]$"].groups() - // let binaryGroup = SwiftRegex(target: message, - // pattern: "^(\\d*)-\\/?(\\w*)?,?(\\d*)?\\[(\".*?\")?,?(.*)?\\]$", - // options: NSRegularExpressionOptions.DotMatchesLineSeparators).groups() + let binaryGroup = message["^(\\d*)-\\/?(\\w*)?,?(\\d*)?\\[(\".*?\")?,?(.*)?\\]$", + NSRegularExpressionOptions.DotMatchesLineSeparators].groups() if binaryGroup == nil { return @@ -359,6 +353,7 @@ class SocketParser { var mutMessageObject:String var namespace:String? var numberOfPlaceholders:String + let messageType = binaryGroup![1] namespace = binaryGroup![2] @@ -422,4 +417,4 @@ class SocketParser { End check for binary placeholders **/ } -} \ No newline at end of file +}