commit
d36ef10404
@ -5,7 +5,7 @@ Socket.IO-client for iOS/OS X.
|
||||
|
||||
##Example
|
||||
```swift
|
||||
let socket = SocketIOClient(socketURL: "localhost:8080", options: [.Log(true), .ForcePolling(true)])
|
||||
let socket = SocketIOClient(socketURL: NSURL(string: "http://localhost:8080")!, options: [.Log(true), .ForcePolling(true)])
|
||||
|
||||
socket.on("connect") {data, ack in
|
||||
print("socket connected")
|
||||
@ -26,7 +26,8 @@ socket.connect()
|
||||
|
||||
##Objective-C Example
|
||||
```objective-c
|
||||
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8080" options:@{@"log": @YES, @"forcePolling": @YES}];
|
||||
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost:8080"];
|
||||
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url options:@{@"log": @YES, @"forcePolling": @YES}];
|
||||
|
||||
[socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||
NSLog(@"socket connected");
|
||||
@ -136,9 +137,9 @@ Run `seed install`.
|
||||
##API
|
||||
Constructors
|
||||
-----------
|
||||
`init(var socketURL: String, options: Set<SocketIOClientOption> = [])` - Creates a new SocketIOClient. opts is a Set of SocketIOClientOption. If your socket.io server is secure, you need to specify `https` in your socketURL.
|
||||
`init(var socketURL: NSURL, options: Set<SocketIOClientOption> = [])` - Creates a new SocketIOClient. options is a Set of SocketIOClientOption. If your socket.io server is secure, you need to specify `https` in your socketURL.
|
||||
|
||||
`convenience init(socketURL: String, options: NSDictionary?)` - Same as above, but meant for Objective-C. See Options on how convert between SocketIOClientOptions and dictionary keys.
|
||||
`convenience init(socketURL: NSURL, options: NSDictionary?)` - Same as above, but meant for Objective-C. See Options on how convert between SocketIOClientOptions and dictionary keys.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
@ -15,8 +15,8 @@ class SocketEngineTest: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
client = SocketIOClient(socketURL: "")
|
||||
engine = SocketEngine(client: client, url: "", options: nil)
|
||||
client = SocketIOClient(socketURL: NSURL(string: "http://localhost")!)
|
||||
engine = SocketEngine(client: client, url: NSURL(string: "http://localhost")!, options: nil)
|
||||
|
||||
client.setTestable()
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import XCTest
|
||||
@testable import SocketIOClientSwift
|
||||
|
||||
class SocketParserTest: XCTestCase {
|
||||
let testSocket = SocketIOClient(socketURL: "")
|
||||
let testSocket = SocketIOClient(socketURL: NSURL())
|
||||
|
||||
//Format key: message; namespace-data-binary-id
|
||||
static let packetTypes: Dictionary<String, (String, [AnyObject], [NSData], Int)> = [
|
||||
|
||||
@ -16,7 +16,7 @@ class SocketSideEffectTest: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
socket = SocketIOClient(socketURL: "")
|
||||
socket = SocketIOClient(socketURL: NSURL())
|
||||
socket.setTestable()
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,11 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
|
||||
public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL)
|
||||
public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL)
|
||||
|
||||
public var connectParams: [String: AnyObject]? {
|
||||
didSet {
|
||||
(urlPolling, urlWebSocket) = createURLs()
|
||||
}
|
||||
}
|
||||
public var postWait = [String]()
|
||||
public var waitingForPoll = false
|
||||
public var waitingForPost = false
|
||||
@ -46,9 +51,9 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
|
||||
public private(set) var probing = false
|
||||
public private(set) var session: NSURLSession?
|
||||
public private(set) var sid = ""
|
||||
public private(set) var socketPath = "/engine.io"
|
||||
public private(set) var urlPolling = ""
|
||||
public private(set) var urlWebSocket = ""
|
||||
public private(set) var socketPath = "/engine.io/"
|
||||
public private(set) var urlPolling = NSURL()
|
||||
public private(set) var urlWebSocket = NSURL()
|
||||
public private(set) var websocket = false
|
||||
public private(set) var ws: WebSocket?
|
||||
|
||||
@ -59,11 +64,9 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
|
||||
private typealias Probe = (msg: String, type: SocketEnginePacketType, data: [NSData])
|
||||
private typealias ProbeWaitQueue = [Probe]
|
||||
|
||||
private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet
|
||||
private let logType = "SocketEngine"
|
||||
private let url: String
|
||||
private let url: NSURL
|
||||
|
||||
private var connectParams: [String: AnyObject]?
|
||||
private var pingInterval: Double?
|
||||
private var pingTimeout = 0.0 {
|
||||
didSet {
|
||||
@ -76,13 +79,15 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
|
||||
private var secure = false
|
||||
private var selfSigned = false
|
||||
private var voipEnabled = false
|
||||
|
||||
public init(client: SocketEngineClient, url: String, options: Set<SocketIOClientOption>) {
|
||||
|
||||
public init(client: SocketEngineClient, url: NSURL, options: Set<SocketIOClientOption>) {
|
||||
self.client = client
|
||||
self.url = url
|
||||
|
||||
|
||||
for option in options {
|
||||
switch option {
|
||||
case let .ConnectParams(params):
|
||||
connectParams = params
|
||||
case let .SessionDelegate(delegate):
|
||||
sessionDelegate = delegate
|
||||
case let .ForcePolling(force):
|
||||
@ -105,11 +110,26 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
||||
(urlPolling, urlWebSocket) = createURLs()
|
||||
}
|
||||
|
||||
public convenience init(client: SocketEngineClient, url: String, options: NSDictionary?) {
|
||||
self.init(client: client, url: url,
|
||||
options: options?.toSocketOptionsSet() ?? [])
|
||||
public convenience init(client: SocketEngineClient, url: NSURL, options: NSDictionary?) {
|
||||
self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? [])
|
||||
}
|
||||
|
||||
@available(*, deprecated=5.3)
|
||||
public convenience init(client: SocketEngineClient, urlString: String, options: Set<SocketIOClientOption>) {
|
||||
guard let url = NSURL(string: urlString) else { fatalError("Incorrect url") }
|
||||
self.init(client: client, url: url, options: options)
|
||||
}
|
||||
|
||||
@available(*, deprecated=5.3)
|
||||
public convenience init(client: SocketEngineClient, urlString: String, options: NSDictionary?) {
|
||||
guard let url = NSURL(string: urlString) else { fatalError("Incorrect url") }
|
||||
self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? [])
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -131,7 +151,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
|
||||
switch code {
|
||||
case 0: // Unknown transport
|
||||
didError(error)
|
||||
case 1: // Unknown sid. clear and retry connect
|
||||
case 1: // Unknown sid.
|
||||
didError(error)
|
||||
case 2: // Bad handshake request
|
||||
didError(error)
|
||||
@ -188,49 +208,45 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
|
||||
}
|
||||
}
|
||||
|
||||
private func createURLs(params: [String: AnyObject]?) -> (String, String) {
|
||||
private func createURLs() -> (NSURL, NSURL) {
|
||||
if client == nil {
|
||||
return ("", "")
|
||||
return (NSURL(), NSURL())
|
||||
}
|
||||
|
||||
let socketURL = "\(url)\(socketPath)/?transport="
|
||||
var urlPolling: String
|
||||
var urlWebSocket: String
|
||||
let urlPolling = NSURLComponents(string: url.absoluteString)!
|
||||
let urlWebSocket = NSURLComponents(string: url.absoluteString)!
|
||||
var queryString = ""
|
||||
|
||||
urlWebSocket.path = socketPath
|
||||
urlPolling.path = socketPath
|
||||
urlWebSocket.query = "transport=websocket"
|
||||
urlPolling.query = "transport=polling&b64=1"
|
||||
|
||||
if secure {
|
||||
urlPolling = "https://" + socketURL + "polling"
|
||||
urlWebSocket = "wss://" + socketURL + "websocket"
|
||||
urlPolling.scheme = "https"
|
||||
urlWebSocket.scheme = "wss"
|
||||
} else {
|
||||
urlPolling = "http://" + socketURL + "polling"
|
||||
urlWebSocket = "ws://" + socketURL + "websocket"
|
||||
urlPolling.scheme = "http"
|
||||
urlWebSocket.scheme = "ws"
|
||||
}
|
||||
|
||||
if params != nil {
|
||||
for (key, value) in params! {
|
||||
let keyEsc = key.stringByAddingPercentEncodingWithAllowedCharacters(
|
||||
allowedCharacterSet)!
|
||||
urlPolling += "&\(keyEsc)="
|
||||
urlWebSocket += "&\(keyEsc)="
|
||||
|
||||
if value is String {
|
||||
let valueEsc = (value as! String).stringByAddingPercentEncodingWithAllowedCharacters(
|
||||
allowedCharacterSet)!
|
||||
urlPolling += "\(valueEsc)"
|
||||
urlWebSocket += "\(valueEsc)"
|
||||
} else {
|
||||
urlPolling += "\(value)"
|
||||
urlWebSocket += "\(value)"
|
||||
}
|
||||
if connectParams != nil {
|
||||
for (key, value) in connectParams! {
|
||||
queryString += "&\(key)=\(value)"
|
||||
}
|
||||
}
|
||||
|
||||
return (urlPolling, urlWebSocket)
|
||||
urlWebSocket.query = urlWebSocket.query! + queryString
|
||||
urlPolling.query = urlPolling.query! + queryString
|
||||
|
||||
return (urlPolling.URL!, urlWebSocket.URL!)
|
||||
}
|
||||
|
||||
private func createWebsocketAndConnect() {
|
||||
let wsUrl = urlWebSocket + (sid == "" ? "" : "&sid=\(sid)")
|
||||
|
||||
ws = WebSocket(url: NSURL(string: wsUrl)!)
|
||||
let component = NSURLComponents(URL: urlWebSocket, resolvingAgainstBaseURL: false)!
|
||||
component.query = component.query! + (sid == "" ? "" : "&sid=\(sid)")
|
||||
|
||||
ws = WebSocket(url: component.URL!)
|
||||
|
||||
if cookies != nil {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
||||
@ -363,22 +379,18 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
|
||||
}
|
||||
}
|
||||
|
||||
public func open(opts: [String: AnyObject]?) {
|
||||
public func open() {
|
||||
if connected {
|
||||
DefaultSocketLogger.Logger.error("Engine tried opening while connected. This is probably a programming error. "
|
||||
+ "Abandoning open attempt", type: logType)
|
||||
return
|
||||
}
|
||||
|
||||
connectParams = opts
|
||||
|
||||
DefaultSocketLogger.Logger.log("Starting engine", type: logType)
|
||||
DefaultSocketLogger.Logger.log("Handshaking", type: logType)
|
||||
|
||||
resetEngine()
|
||||
|
||||
(urlPolling, urlWebSocket) = createURLs(opts)
|
||||
|
||||
if forceWebsockets {
|
||||
polling = false
|
||||
websocket = true
|
||||
@ -386,7 +398,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
|
||||
return
|
||||
}
|
||||
|
||||
let reqPolling = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&b64=1")!)
|
||||
let reqPolling = NSMutableURLRequest(URL: urlPolling)
|
||||
|
||||
if cookies != nil {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
||||
|
||||
@ -71,7 +71,7 @@ extension SocketEnginePollable {
|
||||
|
||||
postWait.removeAll(keepCapacity: false)
|
||||
|
||||
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!)
|
||||
let req = NSMutableURLRequest(URL: urlPollingWithSid)
|
||||
|
||||
addHeaders(req)
|
||||
|
||||
@ -93,7 +93,7 @@ extension SocketEnginePollable {
|
||||
}
|
||||
|
||||
waitingForPoll = true
|
||||
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)&b64=1")!)
|
||||
let req = NSMutableURLRequest(URL: urlPollingWithSid)
|
||||
|
||||
addHeaders(req)
|
||||
doLongPoll(req)
|
||||
@ -112,7 +112,7 @@ extension SocketEnginePollable {
|
||||
|
||||
func doLongPoll(req: NSURLRequest) {
|
||||
doRequest(req) {[weak self] data, res, err in
|
||||
guard let this = self else {return}
|
||||
guard let this = self else { return }
|
||||
|
||||
if err != nil || data == nil {
|
||||
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
|
||||
|
||||
@ -29,6 +29,7 @@ import Foundation
|
||||
weak var client: SocketEngineClient? { get set }
|
||||
var closed: Bool { get }
|
||||
var connected: Bool { get }
|
||||
var connectParams: [String: AnyObject]? { get set }
|
||||
var cookies: [NSHTTPCookie]? { get }
|
||||
var extraHeaders: [String: String]? { get }
|
||||
var fastUpgrade: Bool { get }
|
||||
@ -42,23 +43,30 @@ import Foundation
|
||||
var handleQueue: dispatch_queue_t! { get }
|
||||
var sid: String { get }
|
||||
var socketPath: String { get }
|
||||
var urlPolling: String { get }
|
||||
var urlWebSocket: String { get }
|
||||
var urlPolling: NSURL { get }
|
||||
var urlWebSocket: NSURL { get }
|
||||
var websocket: Bool { get }
|
||||
|
||||
init(client: SocketEngineClient, url: String, options: NSDictionary?)
|
||||
init(client: SocketEngineClient, url: NSURL, options: NSDictionary?)
|
||||
|
||||
func close(reason: String)
|
||||
func didError(error: String)
|
||||
func doFastUpgrade()
|
||||
func flushWaitingForPostToWebSocket()
|
||||
func open(opts: [String: AnyObject]?)
|
||||
func open()
|
||||
func parseEngineData(data: NSData)
|
||||
func parseEngineMessage(message: String, fromPolling: Bool)
|
||||
func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData])
|
||||
}
|
||||
|
||||
extension SocketEngineSpec {
|
||||
var urlPollingWithSid: NSURL {
|
||||
let com = NSURLComponents(URL: urlPolling, resolvingAgainstBaseURL: false)!
|
||||
com.query = com.query! + "&sid=\(sid)"
|
||||
|
||||
return com.URL!
|
||||
}
|
||||
|
||||
func createBinaryDataForSend(data: NSData) -> Either<NSData, String> {
|
||||
if websocket {
|
||||
var byteArray = [UInt8](count: 1, repeatedValue: 0x4)
|
||||
|
||||
@ -25,12 +25,11 @@
|
||||
import Foundation
|
||||
|
||||
public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable {
|
||||
public let socketURL: String
|
||||
public let socketURL: NSURL
|
||||
|
||||
public private(set) var engine: SocketEngineSpec?
|
||||
public private(set) var status = SocketIOClientStatus.NotConnected
|
||||
|
||||
public var connectParams: [String: AnyObject]?
|
||||
public var forceNew = false
|
||||
public var nsp = "/"
|
||||
public var options: Set<SocketIOClientOption>
|
||||
@ -55,29 +54,20 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
||||
private(set) var reconnectAttempts = -1
|
||||
|
||||
var waitingData = [SocketPacket]()
|
||||
|
||||
|
||||
/**
|
||||
Type safe way to create a new SocketIOClient. opts can be omitted
|
||||
*/
|
||||
public init(socketURL: String, options: Set<SocketIOClientOption> = []) {
|
||||
public init(socketURL: NSURL, options: Set<SocketIOClientOption> = []) {
|
||||
self.options = options
|
||||
|
||||
if socketURL.hasPrefix("https://") {
|
||||
self.socketURL = socketURL
|
||||
|
||||
if socketURL.absoluteString.hasPrefix("https://") {
|
||||
self.options.insertIgnore(.Secure(true))
|
||||
}
|
||||
|
||||
var cleanedURL = socketURL["https?://"] <~ ""
|
||||
|
||||
if cleanedURL.hasSuffix("/") {
|
||||
cleanedURL = String(cleanedURL.characters.dropLast())
|
||||
}
|
||||
|
||||
self.socketURL = cleanedURL
|
||||
|
||||
for option in options {
|
||||
switch option {
|
||||
case let .ConnectParams(params):
|
||||
connectParams = params
|
||||
case let .Reconnects(reconnects):
|
||||
self.reconnects = reconnects
|
||||
case let .ReconnectAttempts(attempts):
|
||||
@ -98,19 +88,32 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
self.options.insertIgnore(.Path("/socket.io"))
|
||||
|
||||
|
||||
self.options.insertIgnore(.Path("/socket.io/"))
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
|
||||
If using Swift it's recommended to use `init(var socketURL: String, options: Set<SocketIOClientOption>)`
|
||||
If using Swift it's recommended to use `init(socketURL: NSURL, options: Set<SocketIOClientOption>)`
|
||||
*/
|
||||
public convenience init(socketURL: String, options: NSDictionary?) {
|
||||
self.init(socketURL: socketURL,
|
||||
options: options?.toSocketOptionsSet() ?? [])
|
||||
public convenience init(socketURL: NSURL, options: NSDictionary?) {
|
||||
self.init(socketURL: socketURL, options: options?.toSocketOptionsSet() ?? [])
|
||||
}
|
||||
|
||||
/// Please use the NSURL based init
|
||||
@available(*, deprecated=5.3)
|
||||
public convenience init(socketURLString: String, options: Set<SocketIOClientOption> = []) {
|
||||
guard let url = NSURL(string: socketURLString) else { fatalError("Incorrect url") }
|
||||
self.init(socketURL: url, options: options)
|
||||
}
|
||||
|
||||
/// Please use the NSURL based init
|
||||
@available(*, deprecated=5.3)
|
||||
public convenience init(socketURLString: String, options: NSDictionary?) {
|
||||
guard let url = NSURL(string: socketURLString) else { fatalError("Incorrect url") }
|
||||
self.init(socketURL: url, options: options?.toSocketOptionsSet() ?? [])
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -158,9 +161,9 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
||||
status = .Connecting
|
||||
|
||||
if engine == nil || forceNew {
|
||||
addEngine().open(connectParams)
|
||||
addEngine().open()
|
||||
} else {
|
||||
engine?.open(connectParams)
|
||||
engine?.open()
|
||||
}
|
||||
|
||||
guard timeoutAfter != 0 else { return }
|
||||
|
||||
@ -15,6 +15,7 @@ import Foundation
|
||||
|
||||
infix operator <~ { associativity none precedence 130 }
|
||||
|
||||
private let lock = dispatch_semaphore_create(1)
|
||||
private var swiftRegexCache = [String: NSRegularExpression]()
|
||||
|
||||
internal final class SwiftRegex: NSObject, BooleanType {
|
||||
@ -22,6 +23,10 @@ internal final class SwiftRegex: NSObject, BooleanType {
|
||||
var regex: NSRegularExpression
|
||||
|
||||
init(target:String, pattern:String, options:NSRegularExpressionOptions?) {
|
||||
if dispatch_semaphore_wait(lock, dispatch_time(DISPATCH_TIME_NOW, Int64(10 * NSEC_PER_MSEC))) != 0 {
|
||||
fatalError("This should never happen")
|
||||
}
|
||||
|
||||
self.target = target
|
||||
if let regex = swiftRegexCache[pattern] {
|
||||
self.regex = regex
|
||||
@ -36,6 +41,7 @@ internal final class SwiftRegex: NSObject, BooleanType {
|
||||
self.regex = NSRegularExpression()
|
||||
}
|
||||
}
|
||||
dispatch_semaphore_signal(lock)
|
||||
super.init()
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user