xcode 8
This commit is contained in:
parent
7500ea83a0
commit
9a4ec5a82a
@ -536,9 +536,11 @@
|
|||||||
};
|
};
|
||||||
572EF2371B51F18A00EEBB58 = {
|
572EF2371B51F18A00EEBB58 = {
|
||||||
CreatedOnToolsVersion = 6.4;
|
CreatedOnToolsVersion = 6.4;
|
||||||
|
LastSwiftMigration = 0800;
|
||||||
};
|
};
|
||||||
572EF2411B51F18A00EEBB58 = {
|
572EF2411B51F18A00EEBB58 = {
|
||||||
CreatedOnToolsVersion = 6.4;
|
CreatedOnToolsVersion = 6.4;
|
||||||
|
LastSwiftMigration = 0800;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -1081,6 +1083,7 @@
|
|||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
VERSION_INFO_PREFIX = "";
|
VERSION_INFO_PREFIX = "";
|
||||||
};
|
};
|
||||||
@ -1132,6 +1135,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
VERSION_INFO_PREFIX = "";
|
VERSION_INFO_PREFIX = "";
|
||||||
};
|
};
|
||||||
@ -1188,6 +1192,7 @@
|
|||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@ -1234,6 +1239,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -15,7 +15,7 @@ class SocketAckManagerTest: XCTestCase {
|
|||||||
func testAddAcks() {
|
func testAddAcks() {
|
||||||
let callbackExpection = self.expectation(withDescription: "callbackExpection")
|
let callbackExpection = self.expectation(withDescription: "callbackExpection")
|
||||||
let itemsArray = ["Hi", "ho"]
|
let itemsArray = ["Hi", "ho"]
|
||||||
func callback(items: [AnyObject]) {
|
func callback(_ items: [AnyObject]) {
|
||||||
callbackExpection.fulfill()
|
callbackExpection.fulfill()
|
||||||
}
|
}
|
||||||
ackManager.addAck(1, callback: callback)
|
ackManager.addAck(1, callback: callback)
|
||||||
|
|||||||
@ -10,13 +10,13 @@ import XCTest
|
|||||||
@testable import SocketIOClientSwift
|
@testable import SocketIOClientSwift
|
||||||
|
|
||||||
class SocketBasicPacketTest: XCTestCase {
|
class SocketBasicPacketTest: XCTestCase {
|
||||||
let data = "test".data(using: NSUTF8StringEncoding)!
|
let data = "test".data(using: String.Encoding.utf8)!
|
||||||
let data2 = "test2".data(using: NSUTF8StringEncoding)!
|
let data2 = "test2".data(using: String.Encoding.utf8)!
|
||||||
|
|
||||||
func testEmpyEmit() {
|
func testEmpyEmit() {
|
||||||
let expectedSendString = "2[\"test\"]"
|
let expectedSendString = "2[\"test\"]"
|
||||||
let sendData = ["test"]
|
let sendData = ["test"]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testNullEmit() {
|
func testNullEmit() {
|
||||||
let expectedSendString = "2[\"test\",null]"
|
let expectedSendString = "2[\"test\",null]"
|
||||||
let sendData = ["test", NSNull()]
|
let sendData = ["test", NSNull()]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testStringEmit() {
|
func testStringEmit() {
|
||||||
let expectedSendString = "2[\"test\",\"foo bar\"]"
|
let expectedSendString = "2[\"test\",\"foo bar\"]"
|
||||||
let sendData = ["test", "foo bar"]
|
let sendData = ["test", "foo bar"]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testStringEmitWithQuotes() {
|
func testStringEmitWithQuotes() {
|
||||||
let expectedSendString = "2[\"test\",\"\\\"he\\\"llo world\\\"\"]"
|
let expectedSendString = "2[\"test\",\"\\\"he\\\"llo world\\\"\"]"
|
||||||
let sendData = ["test", "\"he\"llo world\""]
|
let sendData = ["test", "\"he\"llo world\""]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testJSONEmit() {
|
func testJSONEmit() {
|
||||||
let expectedSendString = "2[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
let expectedSendString = "2[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
||||||
let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testArrayEmit() {
|
func testArrayEmit() {
|
||||||
let expectedSendString = "2[\"test\",[\"hello\",1,{\"test\":\"test\"}]]"
|
let expectedSendString = "2[\"test\",[\"hello\",1,{\"test\":\"test\"}]]"
|
||||||
let sendData = ["test", ["hello", 1, ["test": "test"]]]
|
let sendData = ["test", ["hello", 1, ["test": "test"]]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testBinaryEmit() {
|
func testBinaryEmit() {
|
||||||
let expectedSendString = "51-[\"test\",{\"_placeholder\":true,\"num\":0}]"
|
let expectedSendString = "51-[\"test\",{\"_placeholder\":true,\"num\":0}]"
|
||||||
let sendData = ["test", data]
|
let sendData = ["test", data]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData as [AnyObject], id: -1, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data])
|
XCTAssertEqual(packet.binary, [data])
|
||||||
@ -73,7 +73,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testMultipleBinaryEmit() {
|
func testMultipleBinaryEmit() {
|
||||||
let expectedSendString = "52-[\"test\",{\"data1\":{\"_placeholder\":true,\"num\":0},\"data2\":{\"_placeholder\":true,\"num\":1}}]"
|
let expectedSendString = "52-[\"test\",{\"data1\":{\"_placeholder\":true,\"num\":0},\"data2\":{\"_placeholder\":true,\"num\":1}}]"
|
||||||
let sendData = ["test", ["data1": data, "data2": data2]]
|
let sendData = ["test", ["data1": data, "data2": data2]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data, data2])
|
XCTAssertEqual(packet.binary, [data, data2])
|
||||||
@ -82,7 +82,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testEmitWithAck() {
|
func testEmitWithAck() {
|
||||||
let expectedSendString = "20[\"test\"]"
|
let expectedSendString = "20[\"test\"]"
|
||||||
let sendData = ["test"]
|
let sendData = ["test"]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testEmitDataWithAck() {
|
func testEmitDataWithAck() {
|
||||||
let expectedSendString = "51-0[\"test\",{\"_placeholder\":true,\"num\":0}]"
|
let expectedSendString = "51-0[\"test\",{\"_placeholder\":true,\"num\":0}]"
|
||||||
let sendData = ["test", data]
|
let sendData = ["test", data]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData as [AnyObject], id: 0, nsp: "/", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data])
|
XCTAssertEqual(packet.binary, [data])
|
||||||
@ -99,7 +99,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
// Acks
|
// Acks
|
||||||
func testEmptyAck() {
|
func testEmptyAck() {
|
||||||
let expectedSendString = "30[]"
|
let expectedSendString = "30[]"
|
||||||
let packet = SocketPacket.packetFromEmit(items: [], id: 0, nsp: "/", ack: true)
|
let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testNullAck() {
|
func testNullAck() {
|
||||||
let expectedSendString = "30[null]"
|
let expectedSendString = "30[null]"
|
||||||
let sendData = [NSNull()]
|
let sendData = [NSNull()]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testStringAck() {
|
func testStringAck() {
|
||||||
let expectedSendString = "30[\"test\"]"
|
let expectedSendString = "30[\"test\"]"
|
||||||
let sendData = ["test"]
|
let sendData = ["test"]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testJSONAck() {
|
func testJSONAck() {
|
||||||
let expectedSendString = "30[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
let expectedSendString = "30[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
||||||
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -131,7 +131,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testBinaryAck() {
|
func testBinaryAck() {
|
||||||
let expectedSendString = "61-0[{\"_placeholder\":true,\"num\":0}]"
|
let expectedSendString = "61-0[{\"_placeholder\":true,\"num\":0}]"
|
||||||
let sendData = [data]
|
let sendData = [data]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data])
|
XCTAssertEqual(packet.binary, [data])
|
||||||
@ -140,7 +140,7 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
func testMultipleBinaryAck() {
|
func testMultipleBinaryAck() {
|
||||||
let expectedSendString = "62-0[{\"data2\":{\"_placeholder\":true,\"num\":0},\"data1\":{\"_placeholder\":true,\"num\":1}}]"
|
let expectedSendString = "62-0[{\"data2\":{\"_placeholder\":true,\"num\":0},\"data1\":{\"_placeholder\":true,\"num\":1}}]"
|
||||||
let sendData = [["data1": data, "data2": data2]]
|
let sendData = [["data1": data, "data2": data2]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data2, data])
|
XCTAssertEqual(packet.binary, [data2, data])
|
||||||
@ -148,10 +148,10 @@ class SocketBasicPacketTest: XCTestCase {
|
|||||||
|
|
||||||
func testBinaryStringPlaceholderInMessage() {
|
func testBinaryStringPlaceholderInMessage() {
|
||||||
let engineString = "52-[\"test\",\"~~0\",{\"num\":0,\"_placeholder\":true},{\"_placeholder\":true,\"num\":1}]"
|
let engineString = "52-[\"test\",\"~~0\",{\"num\":0,\"_placeholder\":true},{\"_placeholder\":true,\"num\":1}]"
|
||||||
let socket = SocketIOClient(socketURL: NSURL())
|
let socket = SocketIOClient(socketURL: URL(string: "http://localhost/")!)
|
||||||
socket.setTestable()
|
socket.setTestable()
|
||||||
|
|
||||||
if case let .Right(packet) = socket.parseString(engineString) {
|
if case let .right(packet) = socket.parseString(engineString) {
|
||||||
var packet = packet
|
var packet = packet
|
||||||
XCTAssertEqual(packet.event, "test")
|
XCTAssertEqual(packet.event, "test")
|
||||||
packet.addData(data)
|
packet.addData(data)
|
||||||
|
|||||||
@ -15,8 +15,8 @@ class SocketEngineTest: XCTestCase {
|
|||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
client = SocketIOClient(socketURL: NSURL(string: "http://localhost")!)
|
client = SocketIOClient(socketURL: URL(string: "http://localhost")!)
|
||||||
engine = SocketEngine(client: client, url: NSURL(string: "http://localhost")!, options: nil)
|
engine = SocketEngine(client: client, url: URL(string: "http://localhost")!, options: nil)
|
||||||
|
|
||||||
client.setTestable()
|
client.setTestable()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,13 +10,13 @@ import XCTest
|
|||||||
@testable import SocketIOClientSwift
|
@testable import SocketIOClientSwift
|
||||||
|
|
||||||
class SocketNamespacePacketTest: XCTestCase {
|
class SocketNamespacePacketTest: XCTestCase {
|
||||||
let data = "test".data(using: NSUTF8StringEncoding)!
|
let data = "test".data(using: String.Encoding.utf8)!
|
||||||
let data2 = "test2".data(using: NSUTF8StringEncoding)!
|
let data2 = "test2".data(using: String.Encoding.utf8)!
|
||||||
|
|
||||||
func testEmpyEmit() {
|
func testEmpyEmit() {
|
||||||
let expectedSendString = "2/swift,[\"test\"]"
|
let expectedSendString = "2/swift,[\"test\"]"
|
||||||
let sendData = ["test"]
|
let sendData = ["test"]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/swift", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testNullEmit() {
|
func testNullEmit() {
|
||||||
let expectedSendString = "2/swift,[\"test\",null]"
|
let expectedSendString = "2/swift,[\"test\",null]"
|
||||||
let sendData = ["test", NSNull()]
|
let sendData = ["test", NSNull()]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/swift", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testStringEmit() {
|
func testStringEmit() {
|
||||||
let expectedSendString = "2/swift,[\"test\",\"foo bar\"]"
|
let expectedSendString = "2/swift,[\"test\",\"foo bar\"]"
|
||||||
let sendData = ["test", "foo bar"]
|
let sendData = ["test", "foo bar"]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/swift", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testJSONEmit() {
|
func testJSONEmit() {
|
||||||
let expectedSendString = "2/swift,[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
let expectedSendString = "2/swift,[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
||||||
let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/swift", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testArrayEmit() {
|
func testArrayEmit() {
|
||||||
let expectedSendString = "2/swift,[\"test\",[\"hello\",1,{\"test\":\"test\"}]]"
|
let expectedSendString = "2/swift,[\"test\",[\"hello\",1,{\"test\":\"test\"}]]"
|
||||||
let sendData = ["test", ["hello", 1, ["test": "test"]]]
|
let sendData = ["test", ["hello", 1, ["test": "test"]]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/swift", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testBinaryEmit() {
|
func testBinaryEmit() {
|
||||||
let expectedSendString = "51-/swift,[\"test\",{\"_placeholder\":true,\"num\":0}]"
|
let expectedSendString = "51-/swift,[\"test\",{\"_placeholder\":true,\"num\":0}]"
|
||||||
let sendData = ["test", data]
|
let sendData = ["test", data]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/swift", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData as [AnyObject], id: -1, nsp: "/swift", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data])
|
XCTAssertEqual(packet.binary, [data])
|
||||||
@ -65,7 +65,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testMultipleBinaryEmit() {
|
func testMultipleBinaryEmit() {
|
||||||
let expectedSendString = "52-/swift,[\"test\",{\"data1\":{\"_placeholder\":true,\"num\":0},\"data2\":{\"_placeholder\":true,\"num\":1}}]"
|
let expectedSendString = "52-/swift,[\"test\",{\"data1\":{\"_placeholder\":true,\"num\":0},\"data2\":{\"_placeholder\":true,\"num\":1}}]"
|
||||||
let sendData = ["test", ["data1": data, "data2": data2]]
|
let sendData = ["test", ["data1": data, "data2": data2]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: -1, nsp: "/swift", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data, data2])
|
XCTAssertEqual(packet.binary, [data, data2])
|
||||||
@ -74,7 +74,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testEmitWithAck() {
|
func testEmitWithAck() {
|
||||||
let expectedSendString = "2/swift,0[\"test\"]"
|
let expectedSendString = "2/swift,0[\"test\"]"
|
||||||
let sendData = ["test"]
|
let sendData = ["test"]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/swift", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testEmitDataWithAck() {
|
func testEmitDataWithAck() {
|
||||||
let expectedSendString = "51-/swift,0[\"test\",{\"_placeholder\":true,\"num\":0}]"
|
let expectedSendString = "51-/swift,0[\"test\",{\"_placeholder\":true,\"num\":0}]"
|
||||||
let sendData = ["test", data]
|
let sendData = ["test", data]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/swift", ack: false)
|
let packet = SocketPacket.packetFromEmit(sendData as [AnyObject], id: 0, nsp: "/swift", ack: false)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data])
|
XCTAssertEqual(packet.binary, [data])
|
||||||
@ -91,7 +91,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
// Acks
|
// Acks
|
||||||
func testEmptyAck() {
|
func testEmptyAck() {
|
||||||
let expectedSendString = "3/swift,0[]"
|
let expectedSendString = "3/swift,0[]"
|
||||||
let packet = SocketPacket.packetFromEmit(items: [], id: 0, nsp: "/swift", ack: true)
|
let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/swift", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testNullAck() {
|
func testNullAck() {
|
||||||
let expectedSendString = "3/swift,0[null]"
|
let expectedSendString = "3/swift,0[null]"
|
||||||
let sendData = [NSNull()]
|
let sendData = [NSNull()]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/swift", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testStringAck() {
|
func testStringAck() {
|
||||||
let expectedSendString = "3/swift,0[\"test\"]"
|
let expectedSendString = "3/swift,0[\"test\"]"
|
||||||
let sendData = ["test"]
|
let sendData = ["test"]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/swift", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testJSONAck() {
|
func testJSONAck() {
|
||||||
let expectedSendString = "3/swift,0[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
let expectedSendString = "3/swift,0[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
||||||
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/swift", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testBinaryAck() {
|
func testBinaryAck() {
|
||||||
let expectedSendString = "61-/swift,0[{\"_placeholder\":true,\"num\":0}]"
|
let expectedSendString = "61-/swift,0[{\"_placeholder\":true,\"num\":0}]"
|
||||||
let sendData = [data]
|
let sendData = [data]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/swift", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data])
|
XCTAssertEqual(packet.binary, [data])
|
||||||
@ -132,7 +132,7 @@ class SocketNamespacePacketTest: XCTestCase {
|
|||||||
func testMultipleBinaryAck() {
|
func testMultipleBinaryAck() {
|
||||||
let expectedSendString = "62-/swift,0[{\"data2\":{\"_placeholder\":true,\"num\":0},\"data1\":{\"_placeholder\":true,\"num\":1}}]"
|
let expectedSendString = "62-/swift,0[{\"data2\":{\"_placeholder\":true,\"num\":0},\"data1\":{\"_placeholder\":true,\"num\":1}}]"
|
||||||
let sendData = [["data1": data, "data2": data2]]
|
let sendData = [["data1": data, "data2": data2]]
|
||||||
let packet = SocketPacket.packetFromEmit(items: sendData, id: 0, nsp: "/swift", ack: true)
|
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||||
|
|
||||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||||
XCTAssertEqual(packet.binary, [data2, data])
|
XCTAssertEqual(packet.binary, [data2, data])
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
- (void)testSocketManager {
|
- (void)testSocketManager {
|
||||||
SocketClientManager* manager = [SocketClientManager sharedManager];
|
SocketClientManager* manager = [SocketClientManager sharedManager];
|
||||||
[manager addSocketWithSocket:self.socket labeledAs:@"test"];
|
[manager addSocket:self.socket labeledAs:@"test"];
|
||||||
[manager removeSocketWithLabel:@"test"];
|
[manager removeSocketWithLabel:@"test"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,10 +10,10 @@ import XCTest
|
|||||||
@testable import SocketIOClientSwift
|
@testable import SocketIOClientSwift
|
||||||
|
|
||||||
class SocketParserTest: XCTestCase {
|
class SocketParserTest: XCTestCase {
|
||||||
let testSocket = SocketIOClient(socketURL: NSURL())
|
let testSocket = SocketIOClient(socketURL: URL(string: "http://localhost/")!)
|
||||||
|
|
||||||
//Format key: message; namespace-data-binary-id
|
//Format key: message; namespace-data-binary-id
|
||||||
static let packetTypes: [String: (String, [AnyObject], [NSData], Int)] = [
|
static let packetTypes: [String: (String, [AnyObject], [Data], Int)] = [
|
||||||
"0": ("/", [], [], -1), "1": ("/", [], [], -1),
|
"0": ("/", [], [], -1), "1": ("/", [], [], -1),
|
||||||
"25[\"test\"]": ("/", ["test"], [], 5),
|
"25[\"test\"]": ("/", ["test"], [], 5),
|
||||||
"2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1),
|
"2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1),
|
||||||
@ -31,97 +31,97 @@ class SocketParserTest: XCTestCase {
|
|||||||
|
|
||||||
func testDisconnect() {
|
func testDisconnect() {
|
||||||
let message = "1"
|
let message = "1"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testConnect() {
|
func testConnect() {
|
||||||
let message = "0"
|
let message = "0"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDisconnectNameSpace() {
|
func testDisconnectNameSpace() {
|
||||||
let message = "1/swift"
|
let message = "1/swift"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testConnecttNameSpace() {
|
func testConnecttNameSpace() {
|
||||||
let message = "0/swift"
|
let message = "0/swift"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIdEvent() {
|
func testIdEvent() {
|
||||||
let message = "25[\"test\"]"
|
let message = "25[\"test\"]"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBinaryPlaceholderAsString() {
|
func testBinaryPlaceholderAsString() {
|
||||||
let message = "2[\"test\",\"~~0\"]"
|
let message = "2[\"test\",\"~~0\"]"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNameSpaceArrayParse() {
|
func testNameSpaceArrayParse() {
|
||||||
let message = "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]"
|
let message = "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNameSpaceArrayAckParse() {
|
func testNameSpaceArrayAckParse() {
|
||||||
let message = "3/swift,0[[\"test3\",\"test4\"]]"
|
let message = "3/swift,0[[\"test3\",\"test4\"]]"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNameSpaceBinaryEventParse() {
|
func testNameSpaceBinaryEventParse() {
|
||||||
let message = "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
|
let message = "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNameSpaceBinaryAckParse() {
|
func testNameSpaceBinaryAckParse() {
|
||||||
let message = "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
|
let message = "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNamespaceErrorParse() {
|
func testNamespaceErrorParse() {
|
||||||
let message = "4/swift,"
|
let message = "4/swift,"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testErrorTypeString() {
|
func testErrorTypeString() {
|
||||||
let message = "4\"ERROR\""
|
let message = "4\"ERROR\""
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testErrorTypeDictionary() {
|
func testErrorTypeDictionary() {
|
||||||
let message = "4{\"test\":2}"
|
let message = "4{\"test\":2}"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testErrorTypeInt() {
|
func testErrorTypeInt() {
|
||||||
let message = "41"
|
let message = "41"
|
||||||
validateParseResult(message: message)
|
validateParseResult(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInvalidInput() {
|
func testInvalidInput() {
|
||||||
let message = "8"
|
let message = "8"
|
||||||
switch testSocket.parseString(message) {
|
switch testSocket.parseString(message) {
|
||||||
case .Left(_):
|
case .left(_):
|
||||||
return
|
return
|
||||||
case .Right(_):
|
case .right(_):
|
||||||
XCTFail("Created packet when shouldn't have")
|
XCTFail("Created packet when shouldn't have")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGenericParser() {
|
func testGenericParser() {
|
||||||
var parser = SocketStringReader(message: "61-/swift,")
|
var parser = SocketStringReader(message: "61-/swift,")
|
||||||
XCTAssertEqual(parser.read(length: 1), "6")
|
XCTAssertEqual(parser.read(1), "6")
|
||||||
XCTAssertEqual(parser.currentCharacter, "1")
|
XCTAssertEqual(parser.currentCharacter, "1")
|
||||||
XCTAssertEqual(parser.readUntilStringOccurence("-"), "1")
|
XCTAssertEqual(parser.readUntilStringOccurence("-"), "1")
|
||||||
XCTAssertEqual(parser.currentCharacter, "/")
|
XCTAssertEqual(parser.currentCharacter, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateParseResult(message: String) {
|
func validateParseResult(_ message: String) {
|
||||||
let validValues = SocketParserTest.packetTypes[message]!
|
let validValues = SocketParserTest.packetTypes[message]!
|
||||||
let packet = testSocket.parseString(message)
|
let packet = testSocket.parseString(message)
|
||||||
let type = message.substring(with: Range<String.Index>(message.startIndex..<message.characters.index(message.startIndex, offsetBy: 1)))
|
let type = message.substring(with: Range<String.Index>(message.startIndex..<message.characters.index(message.startIndex, offsetBy: 1)))
|
||||||
if case let .Right(packet) = packet {
|
if case let .right(packet) = packet {
|
||||||
XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
|
XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
|
||||||
XCTAssertEqual(packet.nsp, validValues.0)
|
XCTAssertEqual(packet.nsp, validValues.0)
|
||||||
XCTAssertTrue((packet.data as NSArray).isEqual(to: validValues.1), "\(packet.data)")
|
XCTAssertTrue((packet.data as NSArray).isEqual(to: validValues.1), "\(packet.data)")
|
||||||
|
|||||||
@ -10,13 +10,13 @@ import XCTest
|
|||||||
@testable import SocketIOClientSwift
|
@testable import SocketIOClientSwift
|
||||||
|
|
||||||
class SocketSideEffectTest: XCTestCase {
|
class SocketSideEffectTest: XCTestCase {
|
||||||
let data = "test".data(using: NSUTF8StringEncoding)!
|
let data = "test".data(using: String.Encoding.utf8)!
|
||||||
let data2 = "test2".data(using: NSUTF8StringEncoding)!
|
let data2 = "test2".data(using: String.Encoding.utf8)!
|
||||||
private var socket: SocketIOClient!
|
private var socket: SocketIOClient!
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
socket = SocketIOClient(socketURL: NSURL())
|
socket = SocketIOClient(socketURL: URL(string: "http://localhost/")!)
|
||||||
socket.setTestable()
|
socket.setTestable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ class SocketSideEffectTest: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
socket.parseSocketMessage("61-0[{\"_placeholder\":true,\"num\":0},{\"test\":true}]")
|
socket.parseSocketMessage("61-0[{\"_placeholder\":true,\"num\":0},{\"test\":true}]")
|
||||||
socket.parseBinaryData(NSData())
|
socket.parseBinaryData(Data())
|
||||||
waitForExpectations(withTimeout: 3, handler: nil)
|
waitForExpectations(withTimeout: 3, handler: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ class SocketSideEffectTest: XCTestCase {
|
|||||||
|
|
||||||
func testHandleOnceEvent() {
|
func testHandleOnceEvent() {
|
||||||
let expect = expectation(withDescription: "handled event")
|
let expect = expectation(withDescription: "handled event")
|
||||||
socket.once(event: "test") {data, ack in
|
socket.once("test") {data, ack in
|
||||||
XCTAssertEqual(data[0] as? String, "hello world")
|
XCTAssertEqual(data[0] as? String, "hello world")
|
||||||
XCTAssertEqual(self.socket.testHandlers.count, 0)
|
XCTAssertEqual(self.socket.testHandlers.count, 0)
|
||||||
expect.fulfill()
|
expect.fulfill()
|
||||||
@ -140,7 +140,7 @@ class SocketSideEffectTest: XCTestCase {
|
|||||||
func testSocketDataToAnyObject() {
|
func testSocketDataToAnyObject() {
|
||||||
let data = ["test", 1, 2.2, ["Hello": 2, "bob": 2.2], true, [1, 2], [1.1, 2]] as [SocketData]
|
let data = ["test", 1, 2.2, ["Hello": 2, "bob": 2.2], true, [1, 2], [1.1, 2]] as [SocketData]
|
||||||
|
|
||||||
XCTAssertEqual(data.count, socket.socketDataToAnyObject(data: data).count)
|
XCTAssertEqual(data.count, socket.socketDataToAnyObject(data).count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testHandleMultipleBinaryEvent() {
|
func testHandleMultipleBinaryEvent() {
|
||||||
|
|||||||
@ -24,8 +24,8 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension NSCharacterSet {
|
extension CharacterSet {
|
||||||
class var allowedURLCharacterSet: NSCharacterSet {
|
static var allowedURLCharacterSet: CharacterSet {
|
||||||
return NSCharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]\" {}").inverted
|
return CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]\" {}").inverted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ public final class SocketAckEmitter : NSObject {
|
|||||||
public func with(_ items: SocketData...) {
|
public func with(_ items: SocketData...) {
|
||||||
guard ackNum != -1 else { return }
|
guard ackNum != -1 else { return }
|
||||||
|
|
||||||
socket.emitAck(ackNum, with: socket.socketDataToAnyObject(data: items))
|
socket.emitAck(ackNum, with: socket.socketDataToAnyObject(items))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func with(_ items: [AnyObject]) {
|
public func with(_ items: [AnyObject]) {
|
||||||
|
|||||||
@ -59,7 +59,7 @@ struct SocketAckManager {
|
|||||||
mutating func executeAck(_ ack: Int, items: [AnyObject]) {
|
mutating func executeAck(_ ack: Int, items: [AnyObject]) {
|
||||||
let callback = acks.remove(SocketAck(ack: ack))
|
let callback = acks.remove(SocketAck(ack: ack))
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue()) {
|
DispatchQueue.main.async {
|
||||||
callback?.callback(items)
|
callback?.callback(items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ struct SocketAckManager {
|
|||||||
mutating func timeoutAck(_ ack: Int) {
|
mutating func timeoutAck(_ ack: Int) {
|
||||||
let callback = acks.remove(SocketAck(ack: ack))
|
let callback = acks.remove(SocketAck(ack: ack))
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue()) {
|
DispatchQueue.main.async {
|
||||||
callback?.callback(["NO ACK"])
|
callback?.callback(["NO ACK"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,7 @@ public final class SocketClientManager : NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func addSocket(socket: SocketIOClient, labeledAs label: String) {
|
public func addSocket(_ socket: SocketIOClient, labeledAs label: String) {
|
||||||
sockets[label] = socket
|
sockets[label] = socket
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ public final class SocketClientManager : NSObject {
|
|||||||
return sockets.removeValue(forKey: label)
|
return sockets.removeValue(forKey: label)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeSocket(socket: SocketIOClient) -> SocketIOClient? {
|
public func removeSocket(_ socket: SocketIOClient) -> SocketIOClient? {
|
||||||
var returnSocket: SocketIOClient?
|
var returnSocket: SocketIOClient?
|
||||||
|
|
||||||
for (label, dictSocket) in sockets where dictSocket === socket {
|
for (label, dictSocket) in sockets where dictSocket === socket {
|
||||||
|
|||||||
@ -25,9 +25,9 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWebsocket {
|
public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWebsocket {
|
||||||
public let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL)!
|
public let emitQueue = DispatchQueue(label: "com.socketio.engineEmitQueue", attributes: DispatchQueueAttributes.serial)
|
||||||
public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL)!
|
public let handleQueue = DispatchQueue(label: "com.socketio.engineHandleQueue", attributes: DispatchQueueAttributes.serial)
|
||||||
public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL)!
|
public let parseQueue = DispatchQueue(label: "com.socketio.engineParseQueue", attributes: DispatchQueueAttributes.serial)
|
||||||
|
|
||||||
public var connectParams: [String: AnyObject]? {
|
public var connectParams: [String: AnyObject]? {
|
||||||
didSet {
|
didSet {
|
||||||
@ -41,7 +41,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
|
|
||||||
public private(set) var closed = false
|
public private(set) var closed = false
|
||||||
public private(set) var connected = false
|
public private(set) var connected = false
|
||||||
public private(set) var cookies: [NSHTTPCookie]?
|
public private(set) var cookies: [HTTPCookie]?
|
||||||
public private(set) var doubleEncodeUTF8 = true
|
public private(set) var doubleEncodeUTF8 = true
|
||||||
public private(set) var extraHeaders: [String: String]?
|
public private(set) var extraHeaders: [String: String]?
|
||||||
public private(set) var fastUpgrade = false
|
public private(set) var fastUpgrade = false
|
||||||
@ -50,20 +50,20 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
public private(set) var invalidated = false
|
public private(set) var invalidated = false
|
||||||
public private(set) var polling = true
|
public private(set) var polling = true
|
||||||
public private(set) var probing = false
|
public private(set) var probing = false
|
||||||
public private(set) var session: NSURLSession?
|
public private(set) var session: URLSession?
|
||||||
public private(set) var sid = ""
|
public private(set) var sid = ""
|
||||||
public private(set) var socketPath = "/engine.io/"
|
public private(set) var socketPath = "/engine.io/"
|
||||||
public private(set) var urlPolling = NSURL()
|
public private(set) var urlPolling = URL(string: "http://localhost/")!
|
||||||
public private(set) var urlWebSocket = NSURL()
|
public private(set) var urlWebSocket = URL(string: "http://localhost/")!
|
||||||
public private(set) var websocket = false
|
public private(set) var websocket = false
|
||||||
public private(set) var ws: WebSocket?
|
public private(set) var ws: WebSocket?
|
||||||
|
|
||||||
public weak var client: SocketEngineClient?
|
public weak var client: SocketEngineClient?
|
||||||
|
|
||||||
private weak var sessionDelegate: NSURLSessionDelegate?
|
private weak var sessionDelegate: URLSessionDelegate?
|
||||||
|
|
||||||
private let logType = "SocketEngine"
|
private let logType = "SocketEngine"
|
||||||
private let url: NSURL
|
private let url: URL
|
||||||
|
|
||||||
private var pingInterval: Double?
|
private var pingInterval: Double?
|
||||||
private var pingTimeout = 0.0 {
|
private var pingTimeout = 0.0 {
|
||||||
@ -80,7 +80,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
private var selfSigned = false
|
private var selfSigned = false
|
||||||
private var voipEnabled = false
|
private var voipEnabled = false
|
||||||
|
|
||||||
public init(client: SocketEngineClient, url: NSURL, options: Set<SocketIOClientOption>) {
|
public init(client: SocketEngineClient, url: URL, options: Set<SocketIOClientOption>) {
|
||||||
self.client = client
|
self.client = client
|
||||||
self.url = url
|
self.url = url
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
(urlPolling, urlWebSocket) = createURLs()
|
(urlPolling, urlWebSocket) = createURLs()
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init(client: SocketEngineClient, url: NSURL, options: NSDictionary?) {
|
public convenience init(client: SocketEngineClient, url: URL, options: NSDictionary?) {
|
||||||
self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? [])
|
self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? [])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,11 +131,11 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func checkAndHandleEngineError(_ msg: String) {
|
private func checkAndHandleEngineError(_ msg: String) {
|
||||||
guard let stringData = msg.data(using: NSUTF8StringEncoding,
|
guard let stringData = msg.data(using: String.Encoding.utf8,
|
||||||
allowLossyConversion: false) else { return }
|
allowLossyConversion: false) else { return }
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if let dict = try NSJSONSerialization.jsonObject(with: stringData, options: .mutableContainers) as? NSDictionary {
|
if let dict = try JSONSerialization.jsonObject(with: stringData, options: .mutableContainers) as? NSDictionary {
|
||||||
guard let error = dict["message"] as? String else { return }
|
guard let error = dict["message"] as? String else { return }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -144,10 +144,10 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
2: Bad handshake request
|
2: Bad handshake request
|
||||||
3: Bad request
|
3: Bad request
|
||||||
*/
|
*/
|
||||||
didError(error: error)
|
didError(error)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
didError(error: "Got unknown error from server \(msg)")
|
didError("Got unknown error from server \(msg)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
// binary in base64 string
|
// binary in base64 string
|
||||||
let noPrefix = message[message.characters.index(message.startIndex, offsetBy: 2)..<message.endIndex]
|
let noPrefix = message[message.characters.index(message.startIndex, offsetBy: 2)..<message.endIndex]
|
||||||
|
|
||||||
if let data = NSData(base64Encoded: noPrefix, options: .ignoreUnknownCharacters) {
|
if let data = Data(base64Encoded: noPrefix, options: NSData.Base64EncodingOptions(rawValue: 0)) {
|
||||||
client?.parseEngineBinaryData(data)
|
client?.parseEngineBinaryData(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
public func connect() {
|
public func connect() {
|
||||||
if connected {
|
if connected {
|
||||||
DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect", type: logType)
|
DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect", type: logType)
|
||||||
disconnect(reason: "reconnect")
|
disconnect("reconnect")
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Starting engine. Server: %@", type: logType, args: url)
|
DefaultSocketLogger.Logger.log("Starting engine. Server: %@", type: logType, args: url)
|
||||||
@ -198,7 +198,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
let reqPolling = NSMutableURLRequest(url: urlPolling)
|
let reqPolling = NSMutableURLRequest(url: urlPolling)
|
||||||
|
|
||||||
if cookies != nil {
|
if cookies != nil {
|
||||||
let headers = NSHTTPCookie.requestHeaderFields(with: cookies!)
|
let headers = HTTPCookie.requestHeaderFields(with: cookies!)
|
||||||
reqPolling.allHTTPHeaderFields = headers
|
reqPolling.allHTTPHeaderFields = headers
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,18 +208,18 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_async(emitQueue) {
|
(emitQueue).async {
|
||||||
self.doLongPoll(for: reqPolling)
|
self.doLongPoll(for: reqPolling as URLRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createURLs() -> (NSURL, NSURL) {
|
private func createURLs() -> (URL, URL) {
|
||||||
if client == nil {
|
if client == nil {
|
||||||
return (NSURL(), NSURL())
|
return (URL(string: "http://localhost/")!, URL(string: "http://localhost/")!)
|
||||||
}
|
}
|
||||||
|
|
||||||
let urlPolling = NSURLComponents(string: url.absoluteString)!
|
var urlPolling = URLComponents(string: url.absoluteString!)!
|
||||||
let urlWebSocket = NSURLComponents(string: url.absoluteString)!
|
var urlWebSocket = URLComponents(string: url.absoluteString!)!
|
||||||
var queryString = ""
|
var queryString = ""
|
||||||
|
|
||||||
urlWebSocket.path = socketPath
|
urlWebSocket.path = socketPath
|
||||||
@ -252,7 +252,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
ws = WebSocket(url: urlWebSocketWithSid)
|
ws = WebSocket(url: urlWebSocketWithSid)
|
||||||
|
|
||||||
if cookies != nil {
|
if cookies != nil {
|
||||||
let headers = NSHTTPCookie.requestHeaderFields(with: cookies!)
|
let headers = HTTPCookie.requestHeaderFields(with: cookies!)
|
||||||
for (key, value) in headers {
|
for (key, value) in headers {
|
||||||
ws?.headers[key] = value
|
ws?.headers[key] = value
|
||||||
}
|
}
|
||||||
@ -273,20 +273,20 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
ws?.connect()
|
ws?.connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func didError(error: String) {
|
public func didError(_ error: String) {
|
||||||
DefaultSocketLogger.Logger.error("%@", type: logType, args: error)
|
DefaultSocketLogger.Logger.error("%@", type: logType, args: error)
|
||||||
client?.engineDidError(reason: error)
|
client?.engineDidError(error)
|
||||||
disconnect(reason: error)
|
disconnect(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func disconnect(reason: String) {
|
public func disconnect(_ reason: String) {
|
||||||
guard connected else { return closeOutEngine() }
|
guard connected else { return closeOutEngine() }
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType)
|
DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType)
|
||||||
|
|
||||||
if closed {
|
if closed {
|
||||||
closeOutEngine()
|
closeOutEngine()
|
||||||
client?.engineDidClose(reason: reason)
|
client?.engineDidClose(reason)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +301,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
// We need to take special care when we're polling that we send it ASAP
|
// We need to take special care when we're polling that we send it ASAP
|
||||||
// Also make sure we're on the emitQueue since we're touching postWait
|
// Also make sure we're on the emitQueue since we're touching postWait
|
||||||
private func disconnectPolling() {
|
private func disconnectPolling() {
|
||||||
dispatch_sync(emitQueue) {
|
emitQueue.sync {
|
||||||
self.postWait.append(String(SocketEnginePacketType.close.rawValue))
|
self.postWait.append(String(SocketEnginePacketType.close.rawValue))
|
||||||
let req = self.createRequestForPostWithPostWait()
|
let req = self.createRequestForPostWithPostWait()
|
||||||
self.doRequest(for: req) {_, _, _ in }
|
self.doRequest(for: req) {_, _, _ in }
|
||||||
@ -326,7 +326,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
private func flushProbeWait() {
|
private func flushProbeWait() {
|
||||||
DefaultSocketLogger.Logger.log("Flushing probe wait", type: logType)
|
DefaultSocketLogger.Logger.log("Flushing probe wait", type: logType)
|
||||||
|
|
||||||
dispatch_async(emitQueue) {
|
emitQueue.async {
|
||||||
for waiter in self.probeWait {
|
for waiter in self.probeWait {
|
||||||
self.write(waiter.msg, withType: waiter.type, withData: waiter.data)
|
self.write(waiter.msg, withType: waiter.type, withData: waiter.data)
|
||||||
}
|
}
|
||||||
@ -345,14 +345,14 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
guard let ws = self.ws else { return }
|
guard let ws = self.ws else { return }
|
||||||
|
|
||||||
for msg in postWait {
|
for msg in postWait {
|
||||||
ws.writeString(str: msg)
|
ws.writeString(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
postWait.removeAll(keepingCapacity: true)
|
postWait.removeAll(keepingCapacity: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleClose(reason: String) {
|
private func handleClose(_ reason: String) {
|
||||||
client?.engineDidClose(reason: reason)
|
client?.engineDidClose(reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleMessage(_ message: String) {
|
private func handleMessage(_ message: String) {
|
||||||
@ -363,11 +363,11 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
doPoll()
|
doPoll()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleOpen(openMessage: String) {
|
private func handleOpen(_ openMessage: String) {
|
||||||
let mesData = openMessage.data(using: NSUTF8StringEncoding, allowLossyConversion: false)!
|
let mesData = openMessage.data(using: String.Encoding.utf8, allowLossyConversion: false)!
|
||||||
do {
|
do {
|
||||||
let json = try NSJSONSerialization.jsonObject(with: mesData,
|
let json = try JSONSerialization.jsonObject(with: mesData,
|
||||||
options: NSJSONReadingOptions.allowFragments) as? NSDictionary
|
options: JSONSerialization.ReadingOptions.allowFragments) as? NSDictionary
|
||||||
if let sid = json?["sid"] as? String {
|
if let sid = json?["sid"] as? String {
|
||||||
let upgradeWs: Bool
|
let upgradeWs: Bool
|
||||||
|
|
||||||
@ -395,14 +395,14 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
doPoll()
|
doPoll()
|
||||||
}
|
}
|
||||||
|
|
||||||
client?.engineDidOpen(reason: "Connect")
|
client?.engineDidOpen("Connect")
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
didError(error: "Error parsing open packet")
|
didError("Error parsing open packet")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handlePong(pongMessage: String) {
|
private func handlePong(_ pongMessage: String) {
|
||||||
pongsMissed = 0
|
pongsMissed = 0
|
||||||
|
|
||||||
// We should upgrade
|
// We should upgrade
|
||||||
@ -411,9 +411,10 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseEngineData(_ data: NSData) {
|
public func parseEngineData(_ data: Data) {
|
||||||
DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data)
|
DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data)
|
||||||
client?.parseEngineBinaryData(data.subdata(with: NSMakeRange(1, data.length - 1)))
|
|
||||||
|
client?.parseEngineBinaryData(data.subdata(in: Range<Int>(uncheckedBounds: (1, data.count - 1))))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseEngineMessage(_ message: String, fromPolling: Bool) {
|
public func parseEngineMessage(_ message: String, fromPolling: Bool) {
|
||||||
@ -431,7 +432,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fromPolling && type != .noop && doubleEncodeUTF8 {
|
if fromPolling && type != .noop && doubleEncodeUTF8 {
|
||||||
fixedString = fixDoubleUTF8(string: message)
|
fixedString = fixDoubleUTF8(message)
|
||||||
} else {
|
} else {
|
||||||
fixedString = message
|
fixedString = message
|
||||||
}
|
}
|
||||||
@ -443,12 +444,11 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
case .noop:
|
case .noop:
|
||||||
handleNOOP()
|
handleNOOP()
|
||||||
case .pong:
|
case .pong:
|
||||||
handlePong(pongMessage: fixedString)
|
handlePong(fixedString)
|
||||||
case .open:
|
case .open:
|
||||||
handleOpen(openMessage:
|
handleOpen(fixedString[fixedString.characters.index(after: fixedString.characters.startIndex)..<fixedString.endIndex])
|
||||||
fixedString[fixedString.characters.index(after: fixedString.characters.startIndex)..<fixedString.endIndex])
|
|
||||||
case .close:
|
case .close:
|
||||||
handleClose(reason: fixedString)
|
handleClose(fixedString)
|
||||||
default:
|
default:
|
||||||
DefaultSocketLogger.Logger.log("Got unknown packet type", type: logType)
|
DefaultSocketLogger.Logger.log("Got unknown packet type", type: logType)
|
||||||
}
|
}
|
||||||
@ -462,9 +462,9 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
polling = true
|
polling = true
|
||||||
probing = false
|
probing = false
|
||||||
invalidated = false
|
invalidated = false
|
||||||
session = NSURLSession(configuration: .default(),
|
session = URLSession(configuration: .default(),
|
||||||
delegate: sessionDelegate,
|
delegate: sessionDelegate,
|
||||||
delegateQueue: NSOperationQueue())
|
delegateQueue: OperationQueue())
|
||||||
sid = ""
|
sid = ""
|
||||||
waitingForPoll = false
|
waitingForPoll = false
|
||||||
waitingForPost = false
|
waitingForPost = false
|
||||||
@ -478,7 +478,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
|
|
||||||
//Server is not responding
|
//Server is not responding
|
||||||
if pongsMissed > pongsMissedMax {
|
if pongsMissed > pongsMissedMax {
|
||||||
client?.engineDidClose(reason: "Ping timeout")
|
client?.engineDidClose("Ping timeout")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,8 +486,8 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
pongsMissed += 1
|
pongsMissed += 1
|
||||||
write("", withType: .ping, withData: [])
|
write("", withType: .ping, withData: [])
|
||||||
|
|
||||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(pingInterval * Double(NSEC_PER_SEC)))
|
let time = DispatchTime.now() + Double(Int64(pingInterval * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
|
||||||
dispatch_after(time, dispatch_get_main_queue()) {[weak self] in
|
DispatchQueue.main.after(when: time) {[weak self] in
|
||||||
self?.sendPing()
|
self?.sendPing()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -505,8 +505,8 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write a message, independent of transport.
|
/// Write a message, independent of transport.
|
||||||
public func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [NSData]) {
|
public func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data]) {
|
||||||
dispatch_async(emitQueue) {
|
emitQueue.async {
|
||||||
guard self.connected else { return }
|
guard self.connected else { return }
|
||||||
|
|
||||||
if self.websocket {
|
if self.websocket {
|
||||||
@ -524,7 +524,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delegate methods
|
// Delegate methods
|
||||||
public func websocketDidConnect(socket: WebSocket) {
|
public func websocketDidConnect(_ socket: WebSocket) {
|
||||||
if !forceWebsockets {
|
if !forceWebsockets {
|
||||||
probing = true
|
probing = true
|
||||||
probeWebSocket()
|
probeWebSocket()
|
||||||
@ -535,11 +535,11 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
|
public func websocketDidDisconnect(_ socket: WebSocket, error: NSError?) {
|
||||||
probing = false
|
probing = false
|
||||||
|
|
||||||
if closed {
|
if closed {
|
||||||
client?.engineDidClose(reason: "Disconnect")
|
client?.engineDidClose("Disconnect")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,9 +548,9 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
|
|||||||
websocket = false
|
websocket = false
|
||||||
|
|
||||||
if let reason = error?.localizedDescription {
|
if let reason = error?.localizedDescription {
|
||||||
didError(error: reason)
|
didError(reason)
|
||||||
} else {
|
} else {
|
||||||
client?.engineDidClose(reason: "Socket Disconnected")
|
client?.engineDidClose("Socket Disconnected")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
flushProbeWait()
|
flushProbeWait()
|
||||||
|
|||||||
@ -26,9 +26,9 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@objc public protocol SocketEngineClient {
|
@objc public protocol SocketEngineClient {
|
||||||
func engineDidError(reason: String)
|
func engineDidError(_ reason: String)
|
||||||
func engineDidClose(reason: String)
|
func engineDidClose(_ reason: String)
|
||||||
func engineDidOpen(reason: String)
|
func engineDidOpen(_ reason: String)
|
||||||
func parseEngineMessage(_ msg: String)
|
func parseEngineMessage(_ msg: String)
|
||||||
func parseEngineBinaryData(_ data: NSData)
|
func parseEngineBinaryData(_ data: Data)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ public protocol SocketEnginePollable : SocketEngineSpec {
|
|||||||
/// Holds strings waiting to be sent over polling.
|
/// Holds strings waiting to be sent over polling.
|
||||||
/// You shouldn't need to mess with this.
|
/// You shouldn't need to mess with this.
|
||||||
var postWait: [String] { get set }
|
var postWait: [String] { get set }
|
||||||
var session: NSURLSession? { get }
|
var session: URLSession? { get }
|
||||||
/// Because socket.io doesn't let you send two polling request at the same time
|
/// Because socket.io doesn't let you send two polling request at the same time
|
||||||
/// we have to keep track if there's an outstanding poll
|
/// we have to keep track if there's an outstanding poll
|
||||||
var waitingForPoll: Bool { get set }
|
var waitingForPoll: Bool { get set }
|
||||||
@ -39,7 +39,7 @@ public protocol SocketEnginePollable : SocketEngineSpec {
|
|||||||
var waitingForPost: Bool { get set }
|
var waitingForPost: Bool { get set }
|
||||||
|
|
||||||
func doPoll()
|
func doPoll()
|
||||||
func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [NSData])
|
func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data])
|
||||||
func stopPolling()
|
func stopPolling()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ public protocol SocketEnginePollable : SocketEngineSpec {
|
|||||||
extension SocketEnginePollable {
|
extension SocketEnginePollable {
|
||||||
private func addHeaders(for req: NSMutableURLRequest) {
|
private func addHeaders(for req: NSMutableURLRequest) {
|
||||||
if cookies != nil {
|
if cookies != nil {
|
||||||
let headers = NSHTTPCookie.requestHeaderFields(with: cookies!)
|
let headers = HTTPCookie.requestHeaderFields(with: cookies!)
|
||||||
req.allHTTPHeaderFields = headers
|
req.allHTTPHeaderFields = headers
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ extension SocketEnginePollable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRequestForPostWithPostWait() -> NSURLRequest {
|
func createRequestForPostWithPostWait() -> URLRequest {
|
||||||
var postStr = ""
|
var postStr = ""
|
||||||
|
|
||||||
for packet in postWait {
|
for packet in postWait {
|
||||||
@ -71,20 +71,20 @@ extension SocketEnginePollable {
|
|||||||
|
|
||||||
postWait.removeAll(keepingCapacity: false)
|
postWait.removeAll(keepingCapacity: false)
|
||||||
|
|
||||||
let req = NSMutableURLRequest(url: urlPollingWithSid)
|
let req = NSMutableURLRequest(url: urlPollingWithSid as URL)
|
||||||
|
|
||||||
addHeaders(for: req)
|
addHeaders(for: req)
|
||||||
|
|
||||||
req.httpMethod = "POST"
|
req.httpMethod = "POST"
|
||||||
req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type")
|
req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type")
|
||||||
|
|
||||||
let postData = postStr.data(using: NSUTF8StringEncoding,
|
let postData = postStr.data(using: String.Encoding.utf8,
|
||||||
allowLossyConversion: false)!
|
allowLossyConversion: false)!
|
||||||
|
|
||||||
req.httpBody = postData
|
req.httpBody = postData
|
||||||
req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length")
|
req.setValue(String(postData.count), forHTTPHeaderField: "Content-Length")
|
||||||
|
|
||||||
return req
|
return req as URLRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
public func doPoll() {
|
public func doPoll() {
|
||||||
@ -93,13 +93,13 @@ extension SocketEnginePollable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
waitingForPoll = true
|
waitingForPoll = true
|
||||||
let req = NSMutableURLRequest(url: urlPollingWithSid)
|
let req = NSMutableURLRequest(url: urlPollingWithSid as URL)
|
||||||
|
|
||||||
addHeaders(for: req)
|
addHeaders(for: req)
|
||||||
doLongPoll(for: req)
|
doLongPoll(for: req as URLRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doRequest(for req: NSURLRequest, callbackWith callback: (NSData?, NSURLResponse?, NSError?) -> Void) {
|
func doRequest(for req: URLRequest, callbackWith callback: (Data?, URLResponse?, NSError?) -> Void) {
|
||||||
if !polling || closed || invalidated || fastUpgrade {
|
if !polling || closed || invalidated || fastUpgrade {
|
||||||
DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEnginePolling")
|
DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEnginePolling")
|
||||||
return
|
return
|
||||||
@ -110,7 +110,7 @@ extension SocketEnginePollable {
|
|||||||
session?.dataTask(with: req, completionHandler: callback).resume()
|
session?.dataTask(with: req, completionHandler: callback).resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
func doLongPoll(for req: NSURLRequest) {
|
func doLongPoll(for req: URLRequest) {
|
||||||
doRequest(for: req) {[weak self] data, res, err in
|
doRequest(for: req) {[weak self] data, res, err in
|
||||||
guard let this = self where this.polling else { return }
|
guard let this = self where this.polling else { return }
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ extension SocketEnginePollable {
|
|||||||
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
|
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
|
||||||
|
|
||||||
if this.polling {
|
if this.polling {
|
||||||
this.didError(error: err?.localizedDescription ?? "Error")
|
this.didError(err?.localizedDescription ?? "Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -126,8 +126,8 @@ extension SocketEnginePollable {
|
|||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling")
|
DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling")
|
||||||
|
|
||||||
if let str = String(data: data!, encoding: NSUTF8StringEncoding) {
|
if let str = String(data: data!, encoding: String.Encoding.utf8) {
|
||||||
dispatch_async(this.parseQueue) {
|
this.parseQueue.async {
|
||||||
this.parsePollingMessage(str)
|
this.parsePollingMessage(str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +163,7 @@ extension SocketEnginePollable {
|
|||||||
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
|
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
|
||||||
|
|
||||||
if this.polling {
|
if this.polling {
|
||||||
this.didError(error: err?.localizedDescription ?? "Error")
|
this.didError(err?.localizedDescription ?? "Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -171,7 +171,7 @@ extension SocketEnginePollable {
|
|||||||
|
|
||||||
this.waitingForPost = false
|
this.waitingForPost = false
|
||||||
|
|
||||||
dispatch_async(this.emitQueue) {
|
this.emitQueue.async {
|
||||||
if !this.fastUpgrade {
|
if !this.fastUpgrade {
|
||||||
this.flushWaitingForPost()
|
this.flushWaitingForPost()
|
||||||
this.doPoll()
|
this.doPoll()
|
||||||
@ -187,13 +187,13 @@ extension SocketEnginePollable {
|
|||||||
|
|
||||||
while reader.hasNext {
|
while reader.hasNext {
|
||||||
if let n = Int(reader.readUntilStringOccurence(":")) {
|
if let n = Int(reader.readUntilStringOccurence(":")) {
|
||||||
let str = reader.read(length: n)
|
let str = reader.read(n)
|
||||||
|
|
||||||
dispatch_async(handleQueue) {
|
(handleQueue).async {
|
||||||
self.parseEngineMessage(str, fromPolling: true)
|
self.parseEngineMessage(str, fromPolling: true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dispatch_async(handleQueue) {
|
handleQueue.async {
|
||||||
self.parseEngineMessage(str, fromPolling: true)
|
self.parseEngineMessage(str, fromPolling: true)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -203,12 +203,12 @@ extension SocketEnginePollable {
|
|||||||
|
|
||||||
/// Send polling message.
|
/// Send polling message.
|
||||||
/// Only call on emitQueue
|
/// Only call on emitQueue
|
||||||
public func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) {
|
public func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data]) {
|
||||||
DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEnginePolling", args: message, type.rawValue)
|
DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEnginePolling", args: message, type.rawValue)
|
||||||
let fixedMessage: String
|
let fixedMessage: String
|
||||||
|
|
||||||
if doubleEncodeUTF8 {
|
if doubleEncodeUTF8 {
|
||||||
fixedMessage = doubleEncodeUTF8(string: message)
|
fixedMessage = doubleEncodeUTF8(message)
|
||||||
} else {
|
} else {
|
||||||
fixedMessage = message
|
fixedMessage = message
|
||||||
}
|
}
|
||||||
@ -216,7 +216,7 @@ extension SocketEnginePollable {
|
|||||||
postWait.append(String(type.rawValue) + fixedMessage)
|
postWait.append(String(type.rawValue) + fixedMessage)
|
||||||
|
|
||||||
for data in datas {
|
for data in datas {
|
||||||
if case let .Right(bin) = createBinaryDataForSend(using: data) {
|
if case let .right(bin) = createBinaryDataForSend(using: data) {
|
||||||
postWait.append(bin)
|
postWait.append(bin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,77 +31,77 @@ import Foundation
|
|||||||
var connected: Bool { get }
|
var connected: Bool { get }
|
||||||
var connectParams: [String: AnyObject]? { get set }
|
var connectParams: [String: AnyObject]? { get set }
|
||||||
var doubleEncodeUTF8: Bool { get }
|
var doubleEncodeUTF8: Bool { get }
|
||||||
var cookies: [NSHTTPCookie]? { get }
|
var cookies: [HTTPCookie]? { get }
|
||||||
var extraHeaders: [String: String]? { get }
|
var extraHeaders: [String: String]? { get }
|
||||||
var fastUpgrade: Bool { get }
|
var fastUpgrade: Bool { get }
|
||||||
var forcePolling: Bool { get }
|
var forcePolling: Bool { get }
|
||||||
var forceWebsockets: Bool { get }
|
var forceWebsockets: Bool { get }
|
||||||
var parseQueue: dispatch_queue_t { get }
|
var parseQueue: DispatchQueue { get }
|
||||||
var polling: Bool { get }
|
var polling: Bool { get }
|
||||||
var probing: Bool { get }
|
var probing: Bool { get }
|
||||||
var emitQueue: dispatch_queue_t { get }
|
var emitQueue: DispatchQueue { get }
|
||||||
var handleQueue: dispatch_queue_t { get }
|
var handleQueue: DispatchQueue { get }
|
||||||
var sid: String { get }
|
var sid: String { get }
|
||||||
var socketPath: String { get }
|
var socketPath: String { get }
|
||||||
var urlPolling: NSURL { get }
|
var urlPolling: URL { get }
|
||||||
var urlWebSocket: NSURL { get }
|
var urlWebSocket: URL { get }
|
||||||
var websocket: Bool { get }
|
var websocket: Bool { get }
|
||||||
var ws: WebSocket? { get }
|
var ws: WebSocket? { get }
|
||||||
|
|
||||||
init(client: SocketEngineClient, url: NSURL, options: NSDictionary?)
|
init(client: SocketEngineClient, url: URL, options: NSDictionary?)
|
||||||
|
|
||||||
func connect()
|
func connect()
|
||||||
func didError(error: String)
|
func didError(_ error: String)
|
||||||
func disconnect(reason: String)
|
func disconnect(_ reason: String)
|
||||||
func doFastUpgrade()
|
func doFastUpgrade()
|
||||||
func flushWaitingForPostToWebSocket()
|
func flushWaitingForPostToWebSocket()
|
||||||
func parseEngineData(_ data: NSData)
|
func parseEngineData(_ data: Data)
|
||||||
func parseEngineMessage(_ message: String, fromPolling: Bool)
|
func parseEngineMessage(_ message: String, fromPolling: Bool)
|
||||||
func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [NSData])
|
func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data])
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SocketEngineSpec {
|
extension SocketEngineSpec {
|
||||||
var urlPollingWithSid: NSURL {
|
var urlPollingWithSid: URL {
|
||||||
let com = NSURLComponents(url: urlPolling, resolvingAgainstBaseURL: false)!
|
var com = URLComponents(url: urlPolling, resolvingAgainstBaseURL: false)!
|
||||||
com.percentEncodedQuery = com.percentEncodedQuery! + "&sid=\(sid.urlEncode()!)"
|
com.percentEncodedQuery = com.percentEncodedQuery! + "&sid=\(sid.urlEncode()!)"
|
||||||
|
|
||||||
return com.url!
|
return com.url!
|
||||||
}
|
}
|
||||||
|
|
||||||
var urlWebSocketWithSid: NSURL {
|
var urlWebSocketWithSid: URL {
|
||||||
let com = NSURLComponents(url: urlWebSocket, resolvingAgainstBaseURL: false)!
|
var com = URLComponents(url: urlWebSocket, resolvingAgainstBaseURL: false)!
|
||||||
com.percentEncodedQuery = com.percentEncodedQuery! + (sid == "" ? "" : "&sid=\(sid.urlEncode()!)")
|
com.percentEncodedQuery = com.percentEncodedQuery! + (sid == "" ? "" : "&sid=\(sid.urlEncode()!)")
|
||||||
|
|
||||||
return com.url!
|
return com.url!
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBinaryDataForSend(using data: NSData) -> Either<NSData, String> {
|
func createBinaryDataForSend(using data: Data) -> Either<Data, String> {
|
||||||
if websocket {
|
if websocket {
|
||||||
var byteArray = [UInt8](repeating: 0x4, count: 1)
|
var byteArray = [UInt8](repeating: 0x4, count: 1)
|
||||||
let mutData = NSMutableData(bytes: &byteArray, length: 1)
|
let mutData = NSMutableData(bytes: &byteArray, length: 1)
|
||||||
|
|
||||||
mutData.append(data)
|
mutData.append(data)
|
||||||
|
|
||||||
return .Left(mutData)
|
return .left(mutData as Data)
|
||||||
} else {
|
} else {
|
||||||
let str = "b4" + data.base64EncodedString(NSDataBase64EncodingOptions(rawValue: 0))
|
let str = "b4" + data.base64EncodedString(NSData.Base64EncodingOptions(rawValue: 0))
|
||||||
|
|
||||||
return .Right(str)
|
return .right(str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func doubleEncodeUTF8(string: String) -> String {
|
func doubleEncodeUTF8(_ string: String) -> String {
|
||||||
if let latin1 = string.data(using: NSUTF8StringEncoding),
|
if let latin1 = string.data(using: String.Encoding.utf8),
|
||||||
utf8 = NSString(data: latin1, encoding: NSISOLatin1StringEncoding) {
|
utf8 = NSString(data: latin1, encoding: String.Encoding.isoLatin1.rawValue) {
|
||||||
return utf8 as String
|
return utf8 as String
|
||||||
} else {
|
} else {
|
||||||
return string
|
return string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fixDoubleUTF8(string: String) -> String {
|
func fixDoubleUTF8(_ string: String) -> String {
|
||||||
if let utf8 = string.data(using: NSISOLatin1StringEncoding),
|
if let utf8 = string.data(using: String.Encoding.isoLatin1),
|
||||||
latin1 = NSString(data: utf8, encoding: NSUTF8StringEncoding) {
|
latin1 = NSString(data: utf8, encoding: String.Encoding.utf8.rawValue) {
|
||||||
return latin1 as String
|
return latin1 as String
|
||||||
} else {
|
} else {
|
||||||
return string
|
return string
|
||||||
@ -109,7 +109,7 @@ extension SocketEngineSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Send an engine message (4)
|
/// Send an engine message (4)
|
||||||
func send(_ msg: String, withData datas: [NSData]) {
|
func send(_ msg: String, withData datas: [Data]) {
|
||||||
write(msg, withType: .message, withData: datas)
|
write(msg, withType: .message, withData: datas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import Foundation
|
|||||||
|
|
||||||
/// Protocol that is used to implement socket.io WebSocket support
|
/// Protocol that is used to implement socket.io WebSocket support
|
||||||
public protocol SocketEngineWebsocket : SocketEngineSpec, WebSocketDelegate {
|
public protocol SocketEngineWebsocket : SocketEngineSpec, WebSocketDelegate {
|
||||||
func sendWebSocketMessage(_ str: String, withType type: SocketEnginePacketType, withData datas: [NSData])
|
func sendWebSocketMessage(_ str: String, withType type: SocketEnginePacketType, withData datas: [Data])
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebSocket methods
|
// WebSocket methods
|
||||||
@ -40,23 +40,23 @@ extension SocketEngineWebsocket {
|
|||||||
|
|
||||||
/// Send message on WebSockets
|
/// Send message on WebSockets
|
||||||
/// Only call on emitQueue
|
/// Only call on emitQueue
|
||||||
public func sendWebSocketMessage(_ str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) {
|
public func sendWebSocketMessage(_ str: String, withType type: SocketEnginePacketType, withData datas: [Data]) {
|
||||||
DefaultSocketLogger.Logger.log("Sending ws: %@ as type: %@", type: "SocketEngine", args: str, type.rawValue)
|
DefaultSocketLogger.Logger.log("Sending ws: %@ as type: %@", type: "SocketEngine", args: str, type.rawValue)
|
||||||
|
|
||||||
ws?.writeString(str: "\(type.rawValue)\(str)")
|
ws?.writeString("\(type.rawValue)\(str)")
|
||||||
|
|
||||||
for data in datas {
|
for data in datas {
|
||||||
if case let .Left(bin) = createBinaryDataForSend(using: data) {
|
if case let .left(bin) = createBinaryDataForSend(using: data) {
|
||||||
ws?.writeData(data: bin)
|
ws?.writeData(bin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
|
public func websocketDidReceiveMessage(_ socket: WebSocket, text: String) {
|
||||||
parseEngineMessage(text, fromPolling: false)
|
parseEngineMessage(text, fromPolling: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
|
public func websocketDidReceiveData(_ socket: WebSocket, data: Data) {
|
||||||
parseEngineData(data)
|
parseEngineData(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,10 +26,10 @@ import Foundation
|
|||||||
|
|
||||||
struct SocketEventHandler {
|
struct SocketEventHandler {
|
||||||
let event: String
|
let event: String
|
||||||
let id: NSUUID
|
let id: UUID
|
||||||
let callback: NormalCallback
|
let callback: NormalCallback
|
||||||
|
|
||||||
func executeCallback(items: [AnyObject], withAck ack: Int, withSocket socket: SocketIOClient) {
|
func executeCallback(_ items: [AnyObject], withAck ack: Int, withSocket socket: SocketIOClient) {
|
||||||
callback(items, SocketAckEmitter(socket: socket, ackNum: ack))
|
callback(items, SocketAckEmitter(socket: socket, ackNum: ack))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable {
|
public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable {
|
||||||
public let socketURL: NSURL
|
public let socketURL: URL
|
||||||
|
|
||||||
public private(set) var engine: SocketEngineSpec?
|
public private(set) var engine: SocketEngineSpec?
|
||||||
public private(set) var status = SocketIOClientStatus.notConnected {
|
public private(set) var status = SocketIOClientStatus.notConnected {
|
||||||
@ -49,9 +49,9 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
return nsp + "#" + (engine?.sid ?? "")
|
return nsp + "#" + (engine?.sid ?? "")
|
||||||
}
|
}
|
||||||
|
|
||||||
private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL)!
|
private let emitQueue = DispatchQueue(label: "com.socketio.emitQueue", attributes: DispatchQueueAttributes.serial)
|
||||||
private let logType = "SocketIOClient"
|
private let logType = "SocketIOClient"
|
||||||
private let parseQueue = dispatch_queue_create("com.socketio.parseQueue", DISPATCH_QUEUE_SERIAL)!
|
private let parseQueue = DispatchQueue(label: "com.socketio.parseQueue", attributes: DispatchQueueAttributes.serial)
|
||||||
|
|
||||||
private var anyHandler: ((SocketAnyEvent) -> Void)?
|
private var anyHandler: ((SocketAnyEvent) -> Void)?
|
||||||
private var currentReconnectAttempt = 0
|
private var currentReconnectAttempt = 0
|
||||||
@ -60,18 +60,18 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
private var reconnecting = false
|
private var reconnecting = false
|
||||||
|
|
||||||
private(set) var currentAck = -1
|
private(set) var currentAck = -1
|
||||||
private(set) var handleQueue = dispatch_get_main_queue()!
|
private(set) var handleQueue = DispatchQueue.main
|
||||||
private(set) var reconnectAttempts = -1
|
private(set) var reconnectAttempts = -1
|
||||||
|
|
||||||
var waitingPackets = [SocketPacket]()
|
var waitingPackets = [SocketPacket]()
|
||||||
|
|
||||||
/// Type safe way to create a new SocketIOClient. opts can be omitted
|
/// Type safe way to create a new SocketIOClient. opts can be omitted
|
||||||
public init(socketURL: NSURL, options: Set<SocketIOClientOption> = []) {
|
public init(socketURL: URL, options: Set<SocketIOClientOption> = []) {
|
||||||
self.options = options
|
self.options = options
|
||||||
self.socketURL = socketURL
|
self.socketURL = socketURL
|
||||||
|
|
||||||
if socketURL.absoluteString.hasPrefix("https://") {
|
if ((socketURL.absoluteString?.hasPrefix("https://")) != nil) {
|
||||||
self.options.insertIgnore(element: .secure(true))
|
self.options.insertIgnore(.secure(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
for option in options {
|
for option in options {
|
||||||
@ -97,20 +97,20 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.options.insertIgnore(element: .path("/socket.io/"))
|
self.options.insertIgnore(.path("/socket.io/"))
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
|
/// Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
|
||||||
/// If using Swift it's recommended to use `init(socketURL: NSURL, options: Set<SocketIOClientOption>)`
|
/// If using Swift it's recommended to use `init(socketURL: NSURL, options: Set<SocketIOClientOption>)`
|
||||||
public convenience init(socketURL: NSURL, options: NSDictionary?) {
|
public convenience init(socketURL: URL, options: NSDictionary?) {
|
||||||
self.init(socketURL: socketURL, options: options?.toSocketOptionsSet() ?? [])
|
self.init(socketURL: socketURL, options: options?.toSocketOptionsSet() ?? [])
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
DefaultSocketLogger.Logger.log("Client is being released", type: logType)
|
DefaultSocketLogger.Logger.log("Client is being released", type: logType)
|
||||||
engine?.disconnect(reason: "Client Deinit")
|
engine?.disconnect("Client Deinit")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addEngine() -> SocketEngineSpec {
|
private func addEngine() -> SocketEngineSpec {
|
||||||
@ -123,11 +123,11 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
|
|
||||||
/// Connect to the server.
|
/// Connect to the server.
|
||||||
public func connect() {
|
public func connect() {
|
||||||
connect(timeoutAfter: 0, handleWith: nil)
|
connect(0, handleWith: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connect to the server. If we aren't connected after timeoutAfter, call handler
|
/// Connect to the server. If we aren't connected after timeoutAfter, call handler
|
||||||
public func connect(timeoutAfter: Int, handleWith handler: (() -> Void)?) {
|
public func connect(_ timeoutAfter: Int, handleWith handler: (() -> Void)?) {
|
||||||
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
||||||
|
|
||||||
guard status != .connected else {
|
guard status != .connected else {
|
||||||
@ -145,30 +145,30 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
|
|
||||||
guard timeoutAfter != 0 else { return }
|
guard timeoutAfter != 0 else { return }
|
||||||
|
|
||||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
|
let time = DispatchTime.now() + Double(Int64(timeoutAfter) * Int64(NSEC_PER_SEC)) / Double(NSEC_PER_SEC)
|
||||||
|
|
||||||
dispatch_after(time, handleQueue) {[weak self] in
|
handleQueue.after(when: time) {[weak self] in
|
||||||
if let this = self where this.status != .connected && this.status != .disconnected {
|
if let this = self where this.status != .connected && this.status != .disconnected {
|
||||||
this.status = .disconnected
|
this.status = .disconnected
|
||||||
this.engine?.disconnect(reason: "Connect timeout")
|
this.engine?.disconnect("Connect timeout")
|
||||||
|
|
||||||
handler?()
|
handler?()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createOnAck(items: [AnyObject]) -> OnAckCallback {
|
private func createOnAck(_ items: [AnyObject]) -> OnAckCallback {
|
||||||
currentAck += 1
|
currentAck += 1
|
||||||
|
|
||||||
return {[weak self, ack = currentAck] timeout, callback in
|
return {[weak self, ack = currentAck] timeout, callback in
|
||||||
if let this = self {
|
if let this = self {
|
||||||
this.ackHandlers.addAck(ack, callback: callback)
|
this.ackHandlers.addAck(ack, callback: callback)
|
||||||
this._emit(data: items, ack: ack)
|
this._emit(items, ack: ack)
|
||||||
|
|
||||||
if timeout != 0 {
|
if timeout != 0 {
|
||||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC))
|
let time = DispatchTime.now() + Double(Int64(timeout * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)
|
||||||
|
|
||||||
dispatch_after(time, this.handleQueue) {
|
this.handleQueue.after(when: time) {
|
||||||
this.ackHandlers.timeoutAck(ack)
|
this.ackHandlers.timeoutAck(ack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,7 +185,7 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
handleEvent("connect", data: [], isInternalMessage: false)
|
handleEvent("connect", data: [], isInternalMessage: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func didDisconnect(reason: String) {
|
func didDisconnect(_ reason: String) {
|
||||||
guard status != .disconnected else { return }
|
guard status != .disconnected else { return }
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Disconnected: %@", type: logType, args: reason)
|
DefaultSocketLogger.Logger.log("Disconnected: %@", type: logType, args: reason)
|
||||||
@ -193,7 +193,7 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
status = .disconnected
|
status = .disconnected
|
||||||
|
|
||||||
// Make sure the engine is actually dead.
|
// Make sure the engine is actually dead.
|
||||||
engine?.disconnect(reason: reason)
|
engine?.disconnect(reason)
|
||||||
handleEvent("disconnect", data: [reason as AnyObject], isInternalMessage: true)
|
handleEvent("disconnect", data: [reason as AnyObject], isInternalMessage: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,12 +203,12 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
|
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
|
||||||
|
|
||||||
didDisconnect(reason: "Disconnect")
|
didDisconnect("Disconnect")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a message to the server
|
/// Send a message to the server
|
||||||
public func emit(_ event: String, _ items: SocketData...) {
|
public func emit(_ event: String, _ items: SocketData...) {
|
||||||
emit(event, with: socketDataToAnyObject(data: items))
|
emit(event, with: socketDataToAnyObject(items))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as emit, but meant for Objective-C
|
/// Same as emit, but meant for Objective-C
|
||||||
@ -218,28 +218,28 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_emit(data: [event as AnyObject] + items)
|
_emit([event as AnyObject] + items)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
|
/// Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
|
||||||
/// an ack.
|
/// an ack.
|
||||||
public func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
|
public func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
|
||||||
return emitWithAck(event, with: socketDataToAnyObject(data: items))
|
return emitWithAck(event, with: socketDataToAnyObject(items))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as emitWithAck, but for Objective-C
|
/// Same as emitWithAck, but for Objective-C
|
||||||
public func emitWithAck(_ event: String, with items: [AnyObject]) -> OnAckCallback {
|
public func emitWithAck(_ event: String, with items: [AnyObject]) -> OnAckCallback {
|
||||||
return createOnAck(items: [event as AnyObject] + items)
|
return createOnAck([event as AnyObject] + items)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func _emit(data: [AnyObject], ack: Int? = nil) {
|
private func _emit(_ data: [AnyObject], ack: Int? = nil) {
|
||||||
dispatch_async(emitQueue) {
|
emitQueue.async {
|
||||||
guard self.status == .connected else {
|
guard self.status == .connected else {
|
||||||
self.handleEvent("error", data: ["Tried emitting when not connected"], isInternalMessage: true)
|
self.handleEvent("error", data: ["Tried emitting when not connected"], isInternalMessage: true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let packet = SocketPacket.packetFromEmit(items: data, id: ack ?? -1, nsp: self.nsp, ack: false)
|
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: self.nsp, ack: false)
|
||||||
let str = packet.packetString
|
let str = packet.packetString
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Emitting: %@", type: self.logType, args: str)
|
DefaultSocketLogger.Logger.log("Emitting: %@", type: self.logType, args: str)
|
||||||
@ -250,9 +250,9 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
|
|
||||||
// If the server wants to know that the client received data
|
// If the server wants to know that the client received data
|
||||||
func emitAck(_ ack: Int, with items: [AnyObject]) {
|
func emitAck(_ ack: Int, with items: [AnyObject]) {
|
||||||
dispatch_async(emitQueue) {
|
emitQueue.async {
|
||||||
if self.status == .connected {
|
if self.status == .connected {
|
||||||
let packet = SocketPacket.packetFromEmit(items: items, id: ack ?? -1, nsp: self.nsp, ack: true)
|
let packet = SocketPacket.packetFromEmit(items, id: ack ?? -1, nsp: self.nsp, ack: true)
|
||||||
let str = packet.packetString
|
let str = packet.packetString
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Emitting Ack: %@", type: self.logType, args: str)
|
DefaultSocketLogger.Logger.log("Emitting Ack: %@", type: self.logType, args: str)
|
||||||
@ -262,7 +262,7 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func engineDidClose(reason: String) {
|
public func engineDidClose(_ reason: String) {
|
||||||
waitingPackets.removeAll()
|
waitingPackets.removeAll()
|
||||||
|
|
||||||
if status != .disconnected {
|
if status != .disconnected {
|
||||||
@ -270,21 +270,21 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
}
|
}
|
||||||
|
|
||||||
if status == .disconnected || !reconnects {
|
if status == .disconnected || !reconnects {
|
||||||
didDisconnect(reason: reason)
|
didDisconnect(reason)
|
||||||
} else if !reconnecting {
|
} else if !reconnecting {
|
||||||
reconnecting = true
|
reconnecting = true
|
||||||
tryReconnect(reason: reason)
|
tryReconnect(reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// error
|
/// error
|
||||||
public func engineDidError(reason: String) {
|
public func engineDidError(_ reason: String) {
|
||||||
DefaultSocketLogger.Logger.error("%@", type: logType, args: reason)
|
DefaultSocketLogger.Logger.error("%@", type: logType, args: reason)
|
||||||
|
|
||||||
handleEvent("error", data: [reason as AnyObject], isInternalMessage: true)
|
handleEvent("error", data: [reason as AnyObject], isInternalMessage: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func engineDidOpen(reason: String) {
|
public func engineDidOpen(_ reason: String) {
|
||||||
DefaultSocketLogger.Logger.log(reason, type: "SocketEngineClient")
|
DefaultSocketLogger.Logger.log(reason, type: "SocketEngineClient")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,11 +303,11 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "")
|
DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "")
|
||||||
|
|
||||||
dispatch_async(handleQueue) {
|
handleQueue.async {
|
||||||
self.anyHandler?(SocketAnyEvent(event: event, items: data))
|
self.anyHandler?(SocketAnyEvent(event: event, items: data))
|
||||||
|
|
||||||
for handler in self.handlers where handler.event == event {
|
for handler in self.handlers where handler.event == event {
|
||||||
handler.executeCallback(items: data, withAck: ack, withSocket: self)
|
handler.executeCallback(data, withAck: ack, withSocket: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,7 +338,7 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a handler with the specified UUID gotten from an `on` or `once`
|
/// Removes a handler with the specified UUID gotten from an `on` or `once`
|
||||||
public func off(id: NSUUID) {
|
public func off(id: UUID) {
|
||||||
DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id)
|
DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id)
|
||||||
|
|
||||||
handlers = handlers.filter({ $0.id != id })
|
handlers = handlers.filter({ $0.id != id })
|
||||||
@ -347,22 +347,22 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
/// Adds a handler for an event.
|
/// Adds a handler for an event.
|
||||||
/// Returns: A unique id for the handler
|
/// Returns: A unique id for the handler
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func on(_ event: String, callback: NormalCallback) -> NSUUID {
|
public func on(_ event: String, callback: NormalCallback) -> UUID {
|
||||||
DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event)
|
DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event)
|
||||||
|
|
||||||
let handler = SocketEventHandler(event: event, id: NSUUID(), callback: callback)
|
let handler = SocketEventHandler(event: event, id: UUID(), callback: callback)
|
||||||
handlers.append(handler)
|
handlers.append(handler)
|
||||||
|
|
||||||
return handler.id
|
return handler.id as UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a single-use handler for an event.
|
/// Adds a single-use handler for an event.
|
||||||
/// Returns: A unique id for the handler
|
/// Returns: A unique id for the handler
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func once(event: String, callback: NormalCallback) -> NSUUID {
|
public func once(_ event: String, callback: NormalCallback) -> UUID {
|
||||||
DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: logType, args: event)
|
DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: logType, args: event)
|
||||||
|
|
||||||
let id = NSUUID()
|
let id = UUID()
|
||||||
|
|
||||||
let handler = SocketEventHandler(event: event, id: id) {[weak self] data, ack in
|
let handler = SocketEventHandler(event: event, id: id) {[weak self] data, ack in
|
||||||
guard let this = self else { return }
|
guard let this = self else { return }
|
||||||
@ -372,24 +372,24 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
|
|
||||||
handlers.append(handler)
|
handlers.append(handler)
|
||||||
|
|
||||||
return handler.id
|
return handler.id as UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a handler that will be called on every event.
|
/// Adds a handler that will be called on every event.
|
||||||
public func onAny(handler: (SocketAnyEvent) -> Void) {
|
public func onAny(_ handler: (SocketAnyEvent) -> Void) {
|
||||||
anyHandler = handler
|
anyHandler = handler
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseEngineMessage(_ msg: String) {
|
public func parseEngineMessage(_ msg: String) {
|
||||||
DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg)
|
DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg)
|
||||||
|
|
||||||
dispatch_async(parseQueue) {
|
parseQueue.async {
|
||||||
self.parseSocketMessage(msg)
|
self.parseSocketMessage(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseEngineBinaryData(_ data: NSData) {
|
public func parseEngineBinaryData(_ data: Data) {
|
||||||
dispatch_async(parseQueue) {
|
parseQueue.async {
|
||||||
self.parseBinaryData(data)
|
self.parseBinaryData(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -398,7 +398,7 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
public func reconnect() {
|
public func reconnect() {
|
||||||
guard !reconnecting else { return }
|
guard !reconnecting else { return }
|
||||||
|
|
||||||
engine?.disconnect(reason: "manual reconnect")
|
engine?.disconnect("manual reconnect")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes all handlers.
|
/// Removes all handlers.
|
||||||
@ -407,11 +407,11 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
handlers.removeAll(keepingCapacity: false)
|
handlers.removeAll(keepingCapacity: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func socketDataToAnyObject(data: [SocketData]) -> [AnyObject] {
|
func socketDataToAnyObject(_ data: [SocketData]) -> [AnyObject] {
|
||||||
return data.flatMap({$0 as? AnyObject})
|
return data.flatMap({$0 as? AnyObject})
|
||||||
}
|
}
|
||||||
|
|
||||||
private func tryReconnect(reason: String) {
|
private func tryReconnect(_ reason: String) {
|
||||||
if reconnecting {
|
if reconnecting {
|
||||||
DefaultSocketLogger.Logger.log("Starting reconnect", type: logType)
|
DefaultSocketLogger.Logger.log("Starting reconnect", type: logType)
|
||||||
handleEvent("reconnect", data: [reason as AnyObject], isInternalMessage: true)
|
handleEvent("reconnect", data: [reason as AnyObject], isInternalMessage: true)
|
||||||
@ -426,7 +426,7 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
}
|
}
|
||||||
|
|
||||||
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
|
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
|
||||||
return didDisconnect(reason: "Reconnect Failed")
|
return didDisconnect("Reconnect Failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType)
|
DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType)
|
||||||
@ -436,9 +436,9 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
|
|||||||
currentReconnectAttempt += 1
|
currentReconnectAttempt += 1
|
||||||
connect()
|
connect()
|
||||||
|
|
||||||
let dispatchAfter = dispatch_time(DISPATCH_TIME_NOW, Int64(UInt64(reconnectWait) * NSEC_PER_SEC))
|
let dispatchAfter = DispatchTime.now() + Double(Int64(UInt64(reconnectWait) * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)
|
||||||
|
|
||||||
dispatch_after(dispatchAfter, dispatch_get_main_queue(), _tryReconnect)
|
DispatchQueue.main.after(when: dispatchAfter, execute: _tryReconnect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,11 +452,11 @@ extension SocketIOClient {
|
|||||||
status = .connected
|
status = .connected
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTestEngine(engine: SocketEngineSpec?) {
|
func setTestEngine(_ engine: SocketEngineSpec?) {
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitTest(event: String, _ data: AnyObject...) {
|
func emitTest(_ event: String, _ data: AnyObject...) {
|
||||||
self._emit(data: [event as AnyObject] + data)
|
self._emit([event as AnyObject] + data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,13 +30,13 @@ protocol ClientOption : CustomStringConvertible, Hashable {
|
|||||||
|
|
||||||
public enum SocketIOClientOption : ClientOption {
|
public enum SocketIOClientOption : ClientOption {
|
||||||
case connectParams([String: AnyObject])
|
case connectParams([String: AnyObject])
|
||||||
case cookies([NSHTTPCookie])
|
case cookies([HTTPCookie])
|
||||||
case doubleEncodeUTF8(Bool)
|
case doubleEncodeUTF8(Bool)
|
||||||
case extraHeaders([String: String])
|
case extraHeaders([String: String])
|
||||||
case forceNew(Bool)
|
case forceNew(Bool)
|
||||||
case forcePolling(Bool)
|
case forcePolling(Bool)
|
||||||
case forceWebsockets(Bool)
|
case forceWebsockets(Bool)
|
||||||
case handleQueue(dispatch_queue_t)
|
case handleQueue(DispatchQueue)
|
||||||
case log(Bool)
|
case log(Bool)
|
||||||
case logger(SocketLogger)
|
case logger(SocketLogger)
|
||||||
case nsp(String)
|
case nsp(String)
|
||||||
@ -47,7 +47,7 @@ public enum SocketIOClientOption : ClientOption {
|
|||||||
case secure(Bool)
|
case secure(Bool)
|
||||||
case security(SSLSecurity)
|
case security(SSLSecurity)
|
||||||
case selfSigned(Bool)
|
case selfSigned(Bool)
|
||||||
case sessionDelegate(NSURLSessionDelegate)
|
case sessionDelegate(URLSessionDelegate)
|
||||||
case voipEnabled(Bool)
|
case voipEnabled(Bool)
|
||||||
|
|
||||||
public var description: String {
|
public var description: String {
|
||||||
@ -158,7 +158,7 @@ public func ==(lhs: SocketIOClientOption, rhs: SocketIOClientOption) -> Bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension Set where Element : ClientOption {
|
extension Set where Element : ClientOption {
|
||||||
mutating func insertIgnore(element: Element) {
|
mutating func insertIgnore(_ element: Element) {
|
||||||
if !contains(element) {
|
if !contains(element) {
|
||||||
insert(element)
|
insert(element)
|
||||||
}
|
}
|
||||||
@ -166,11 +166,11 @@ extension Set where Element : ClientOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension NSDictionary {
|
extension NSDictionary {
|
||||||
private static func keyValueToSocketIOClientOption(key: String, value: AnyObject) -> SocketIOClientOption? {
|
private static func keyValueToSocketIOClientOption(_ key: String, value: AnyObject) -> SocketIOClientOption? {
|
||||||
switch (key, value) {
|
switch (key, value) {
|
||||||
case let ("connectParams", params as [String: AnyObject]):
|
case let ("connectParams", params as [String: AnyObject]):
|
||||||
return .connectParams(params)
|
return .connectParams(params)
|
||||||
case let ("cookies", cookies as [NSHTTPCookie]):
|
case let ("cookies", cookies as [HTTPCookie]):
|
||||||
return .cookies(cookies)
|
return .cookies(cookies)
|
||||||
case let ("doubleEncodeUTF8", encode as Bool):
|
case let ("doubleEncodeUTF8", encode as Bool):
|
||||||
return .doubleEncodeUTF8(encode)
|
return .doubleEncodeUTF8(encode)
|
||||||
@ -182,7 +182,7 @@ extension NSDictionary {
|
|||||||
return .forcePolling(force)
|
return .forcePolling(force)
|
||||||
case let ("forceWebsockets", force as Bool):
|
case let ("forceWebsockets", force as Bool):
|
||||||
return .forceWebsockets(force)
|
return .forceWebsockets(force)
|
||||||
case let ("handleQueue", queue as dispatch_queue_t):
|
case let ("handleQueue", queue as DispatchQueue):
|
||||||
return .handleQueue(queue)
|
return .handleQueue(queue)
|
||||||
case let ("log", log as Bool):
|
case let ("log", log as Bool):
|
||||||
return .log(log)
|
return .log(log)
|
||||||
@ -204,7 +204,7 @@ extension NSDictionary {
|
|||||||
return .security(security)
|
return .security(security)
|
||||||
case let ("selfSigned", selfSigned as Bool):
|
case let ("selfSigned", selfSigned as Bool):
|
||||||
return .selfSigned(selfSigned)
|
return .selfSigned(selfSigned)
|
||||||
case let ("sessionDelegate", delegate as NSURLSessionDelegate):
|
case let ("sessionDelegate", delegate as URLSessionDelegate):
|
||||||
return .sessionDelegate(delegate)
|
return .sessionDelegate(delegate)
|
||||||
case let ("voipEnabled", enable as Bool):
|
case let ("voipEnabled", enable as Bool):
|
||||||
return .voipEnabled(enable)
|
return .voipEnabled(enable)
|
||||||
@ -217,8 +217,8 @@ extension NSDictionary {
|
|||||||
var options = Set<SocketIOClientOption>()
|
var options = Set<SocketIOClientOption>()
|
||||||
|
|
||||||
for (rawKey, value) in self {
|
for (rawKey, value) in self {
|
||||||
if let key = rawKey as? String, opt = NSDictionary.keyValueToSocketIOClientOption(key: key, value: value) {
|
if let key = rawKey as? String, opt = NSDictionary.keyValueToSocketIOClientOption(key, value: value) {
|
||||||
options.insertIgnore(element: opt)
|
options.insertIgnore(opt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,15 +27,15 @@ protocol SocketIOClientSpec : class {
|
|||||||
var waitingPackets: [SocketPacket] { get set }
|
var waitingPackets: [SocketPacket] { get set }
|
||||||
|
|
||||||
func didConnect()
|
func didConnect()
|
||||||
func didDisconnect(reason: String)
|
func didDisconnect(_ reason: String)
|
||||||
func didError(reason: String)
|
func didError(_ reason: String)
|
||||||
func handleAck(_ ack: Int, data: [AnyObject])
|
func handleAck(_ ack: Int, data: [AnyObject])
|
||||||
func handleEvent(_ event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int)
|
func handleEvent(_ event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int)
|
||||||
func joinNamespace(_ namespace: String)
|
func joinNamespace(_ namespace: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SocketIOClientSpec {
|
extension SocketIOClientSpec {
|
||||||
func didError(reason: String) {
|
func didError(_ reason: String) {
|
||||||
DefaultSocketLogger.Logger.error("%@", type: "SocketIOClient", args: reason)
|
DefaultSocketLogger.Logger.error("%@", type: "SocketIOClient", args: reason)
|
||||||
|
|
||||||
handleEvent("error", data: [reason as AnyObject], isInternalMessage: true, withAck: -1)
|
handleEvent("error", data: [reason as AnyObject], isInternalMessage: true, withAck: -1)
|
||||||
|
|||||||
@ -35,18 +35,18 @@ struct SocketPacket {
|
|||||||
let type: PacketType
|
let type: PacketType
|
||||||
|
|
||||||
enum PacketType: Int {
|
enum PacketType: Int {
|
||||||
case Connect, Disconnect, Event, Ack, Error, BinaryEvent, BinaryAck
|
case connect, disconnect, event, ack, error, binaryEvent, binaryAck
|
||||||
}
|
}
|
||||||
|
|
||||||
var args: [AnyObject] {
|
var args: [AnyObject] {
|
||||||
if type == .Event || type == .BinaryEvent && data.count != 0 {
|
if type == .event || type == .binaryEvent && data.count != 0 {
|
||||||
return Array(data.dropFirst())
|
return Array(data.dropFirst())
|
||||||
} else {
|
} else {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var binary: [NSData]
|
var binary: [Data]
|
||||||
var data: [AnyObject]
|
var data: [AnyObject]
|
||||||
var description: String {
|
var description: String {
|
||||||
return "SocketPacket {type: \(String(type.rawValue)); data: " +
|
return "SocketPacket {type: \(String(type.rawValue)); data: " +
|
||||||
@ -62,7 +62,7 @@ struct SocketPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(type: PacketType, data: [AnyObject] = [AnyObject](), id: Int = -1,
|
init(type: PacketType, data: [AnyObject] = [AnyObject](), id: Int = -1,
|
||||||
nsp: String, placeholders: Int = 0, binary: [NSData] = [NSData]()) {
|
nsp: String, placeholders: Int = 0, binary: [Data] = [Data]()) {
|
||||||
self.data = data
|
self.data = data
|
||||||
self.id = id
|
self.id = id
|
||||||
self.nsp = nsp
|
self.nsp = nsp
|
||||||
@ -71,7 +71,7 @@ struct SocketPacket {
|
|||||||
self.binary = binary
|
self.binary = binary
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func addData(_ data: NSData) -> Bool {
|
mutating func addData(_ data: Data) -> Bool {
|
||||||
if placeholders == binary.count {
|
if placeholders == binary.count {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -94,9 +94,9 @@ struct SocketPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let jsonSend = try NSJSONSerialization.data(withJSONObject: data as AnyObject,
|
let jsonSend = try JSONSerialization.data(withJSONObject: data as AnyObject,
|
||||||
options: NSJSONWritingOptions(rawValue: 0))
|
options: JSONSerialization.WritingOptions(rawValue: 0))
|
||||||
guard let jsonString = String(data: jsonSend, encoding: NSUTF8StringEncoding) else {
|
guard let jsonString = String(data: jsonSend, encoding: String.Encoding.utf8) else {
|
||||||
return message + "[]"
|
return message + "[]"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ struct SocketPacket {
|
|||||||
let nspString: String
|
let nspString: String
|
||||||
let idString: String
|
let idString: String
|
||||||
|
|
||||||
if type == .BinaryEvent || type == .BinaryAck {
|
if type == .binaryEvent || type == .binaryAck {
|
||||||
binaryCountString = typeString + String(binary.count) + "-"
|
binaryCountString = typeString + String(binary.count) + "-"
|
||||||
} else {
|
} else {
|
||||||
binaryCountString = typeString
|
binaryCountString = typeString
|
||||||
@ -172,19 +172,19 @@ extension SocketPacket {
|
|||||||
private static func findType(_ binCount: Int, ack: Bool) -> PacketType {
|
private static func findType(_ binCount: Int, ack: Bool) -> PacketType {
|
||||||
switch binCount {
|
switch binCount {
|
||||||
case 0 where !ack:
|
case 0 where !ack:
|
||||||
return .Event
|
return .event
|
||||||
case 0 where ack:
|
case 0 where ack:
|
||||||
return .Ack
|
return .ack
|
||||||
case _ where !ack:
|
case _ where !ack:
|
||||||
return .BinaryEvent
|
return .binaryEvent
|
||||||
case _ where ack:
|
case _ where ack:
|
||||||
return .BinaryAck
|
return .binaryAck
|
||||||
default:
|
default:
|
||||||
return .Error
|
return .error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func packetFromEmit(items: [AnyObject], id: Int, nsp: String, ack: Bool) -> SocketPacket {
|
static func packetFromEmit(_ items: [AnyObject], id: Int, nsp: String, ack: Bool) -> SocketPacket {
|
||||||
let (parsedData, binary) = deconstructData(items)
|
let (parsedData, binary) = deconstructData(items)
|
||||||
let packet = SocketPacket(type: findType(binary.count, ack: ack), data: parsedData,
|
let packet = SocketPacket(type: findType(binary.count, ack: ack), data: parsedData,
|
||||||
id: id, nsp: nsp, binary: binary)
|
id: id, nsp: nsp, binary: binary)
|
||||||
@ -195,11 +195,11 @@ extension SocketPacket {
|
|||||||
|
|
||||||
private extension SocketPacket {
|
private extension SocketPacket {
|
||||||
// Recursive function that looks for NSData in collections
|
// Recursive function that looks for NSData in collections
|
||||||
static func shred(_ data: AnyObject, binary: inout [NSData]) -> AnyObject {
|
static func shred(_ data: AnyObject, binary: inout [Data]) -> AnyObject {
|
||||||
let placeholder = ["_placeholder": true, "num": binary.count as AnyObject]
|
let placeholder = ["_placeholder": true, "num": binary.count as AnyObject]
|
||||||
|
|
||||||
switch data {
|
switch data {
|
||||||
case let bin as NSData:
|
case let bin as Data:
|
||||||
binary.append(bin)
|
binary.append(bin)
|
||||||
return placeholder as AnyObject
|
return placeholder as AnyObject
|
||||||
case let arr as [AnyObject]:
|
case let arr as [AnyObject]:
|
||||||
@ -216,8 +216,8 @@ private extension SocketPacket {
|
|||||||
|
|
||||||
// Removes binary data from emit data
|
// Removes binary data from emit data
|
||||||
// Returns a type containing the de-binaryed data and the binary
|
// Returns a type containing the de-binaryed data and the binary
|
||||||
static func deconstructData(_ data: [AnyObject]) -> ([AnyObject], [NSData]) {
|
static func deconstructData(_ data: [AnyObject]) -> ([AnyObject], [Data]) {
|
||||||
var binary = [NSData]()
|
var binary = [Data]()
|
||||||
|
|
||||||
return (data.map({shred($0, binary: &binary)}), binary)
|
return (data.map({shred($0, binary: &binary)}), binary)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol SocketParsable : SocketIOClientSpec {
|
protocol SocketParsable : SocketIOClientSpec {
|
||||||
func parseBinaryData(_ data: NSData)
|
func parseBinaryData(_ data: Data)
|
||||||
func parseSocketMessage(_ message: String)
|
func parseSocketMessage(_ message: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,19 +42,19 @@ extension SocketParsable {
|
|||||||
|
|
||||||
private func handlePacket(_ pack: SocketPacket) {
|
private func handlePacket(_ pack: SocketPacket) {
|
||||||
switch pack.type {
|
switch pack.type {
|
||||||
case .Event where isCorrectNamespace(pack.nsp):
|
case .event where isCorrectNamespace(pack.nsp):
|
||||||
handleEvent(pack.event, data: pack.args, isInternalMessage: false, withAck: pack.id)
|
handleEvent(pack.event, data: pack.args, isInternalMessage: false, withAck: pack.id)
|
||||||
case .Ack where isCorrectNamespace(pack.nsp):
|
case .ack where isCorrectNamespace(pack.nsp):
|
||||||
handleAck(pack.id, data: pack.data)
|
handleAck(pack.id, data: pack.data)
|
||||||
case .BinaryEvent where isCorrectNamespace(pack.nsp):
|
case .binaryEvent where isCorrectNamespace(pack.nsp):
|
||||||
waitingPackets.append(pack)
|
waitingPackets.append(pack)
|
||||||
case .BinaryAck where isCorrectNamespace(pack.nsp):
|
case .binaryAck where isCorrectNamespace(pack.nsp):
|
||||||
waitingPackets.append(pack)
|
waitingPackets.append(pack)
|
||||||
case .Connect:
|
case .connect:
|
||||||
handleConnect(pack)
|
handleConnect(pack)
|
||||||
case .Disconnect:
|
case .disconnect:
|
||||||
didDisconnect(reason: "Got Disconnect")
|
didDisconnect("Got Disconnect")
|
||||||
case .Error:
|
case .error:
|
||||||
handleEvent("error", data: pack.data, isInternalMessage: true, withAck: pack.id)
|
handleEvent("error", data: pack.data, isInternalMessage: true, withAck: pack.id)
|
||||||
default:
|
default:
|
||||||
DefaultSocketLogger.Logger.log("Got invalid packet: %@", type: "SocketParser", args: pack.description)
|
DefaultSocketLogger.Logger.log("Got invalid packet: %@", type: "SocketParser", args: pack.description)
|
||||||
@ -65,22 +65,22 @@ extension SocketParsable {
|
|||||||
func parseString(_ message: String) -> Either<String, SocketPacket> {
|
func parseString(_ message: String) -> Either<String, SocketPacket> {
|
||||||
var parser = SocketStringReader(message: message)
|
var parser = SocketStringReader(message: message)
|
||||||
|
|
||||||
guard let type = SocketPacket.PacketType(rawValue: Int(parser.read(length: 1)) ?? -1) else {
|
guard let type = SocketPacket.PacketType(rawValue: Int(parser.read(1)) ?? -1) else {
|
||||||
return .Left("Invalid packet type")
|
return .left("Invalid packet type")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !parser.hasNext {
|
if !parser.hasNext {
|
||||||
return .Right(SocketPacket(type: type, nsp: "/"))
|
return .right(SocketPacket(type: type, nsp: "/"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var namespace = "/"
|
var namespace = "/"
|
||||||
var placeholders = -1
|
var placeholders = -1
|
||||||
|
|
||||||
if type == .BinaryEvent || type == .BinaryAck {
|
if type == .binaryEvent || type == .binaryAck {
|
||||||
if let holders = Int(parser.readUntilStringOccurence("-")) {
|
if let holders = Int(parser.readUntilStringOccurence("-")) {
|
||||||
placeholders = holders
|
placeholders = holders
|
||||||
} else {
|
} else {
|
||||||
return .Left("Invalid packet")
|
return .left("Invalid packet")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,53 +89,53 @@ extension SocketParsable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !parser.hasNext {
|
if !parser.hasNext {
|
||||||
return .Right(SocketPacket(type: type, nsp: namespace, placeholders: placeholders))
|
return .right(SocketPacket(type: type, nsp: namespace, placeholders: placeholders))
|
||||||
}
|
}
|
||||||
|
|
||||||
var idString = ""
|
var idString = ""
|
||||||
|
|
||||||
if type == .Error {
|
if type == .error {
|
||||||
parser.advance(by: -1)
|
parser.advance(-1)
|
||||||
} else {
|
} else {
|
||||||
while parser.hasNext {
|
while parser.hasNext {
|
||||||
if let int = Int(parser.read(length: 1)) {
|
if let int = Int(parser.read(1)) {
|
||||||
idString += String(int)
|
idString += String(int)
|
||||||
} else {
|
} else {
|
||||||
parser.advance(by: -2)
|
parser.advance(-2)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let d = message[parser.advance(by: 1)..<message.endIndex]
|
let d = message[parser.advance(1)..<message.endIndex]
|
||||||
|
|
||||||
switch parseData(d) {
|
switch parseData(d) {
|
||||||
case let .Left(err):
|
case let .left(err):
|
||||||
// Errors aren't always enclosed in an array
|
// Errors aren't always enclosed in an array
|
||||||
if case let .Right(data) = parseData("\([d as AnyObject])") {
|
if case let .right(data) = parseData("\([d as AnyObject])") {
|
||||||
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
|
return .right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
|
||||||
nsp: namespace, placeholders: placeholders))
|
nsp: namespace, placeholders: placeholders))
|
||||||
} else {
|
} else {
|
||||||
return .Left(err)
|
return .left(err)
|
||||||
}
|
}
|
||||||
case let .Right(data):
|
case let .right(data):
|
||||||
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
|
return .right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
|
||||||
nsp: namespace, placeholders: placeholders))
|
nsp: namespace, placeholders: placeholders))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses data for events
|
// Parses data for events
|
||||||
private func parseData(_ data: String) -> Either<String, [AnyObject]> {
|
private func parseData(_ data: String) -> Either<String, [AnyObject]> {
|
||||||
let stringData = data.data(using: NSUTF8StringEncoding, allowLossyConversion: false)
|
let stringData = data.data(using: String.Encoding.utf8, allowLossyConversion: false)
|
||||||
do {
|
do {
|
||||||
if let arr = try NSJSONSerialization.jsonObject(with: stringData!,
|
if let arr = try JSONSerialization.jsonObject(with: stringData!,
|
||||||
options: NSJSONReadingOptions.mutableContainers) as? [AnyObject] {
|
options: JSONSerialization.ReadingOptions.mutableContainers) as? [AnyObject] {
|
||||||
return .Right(arr)
|
return .right(arr)
|
||||||
} else {
|
} else {
|
||||||
return .Left("Expected data array")
|
return .left("Expected data array")
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
return .Left("Error parsing data for packet")
|
return .left("Error parsing data for packet")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,15 +146,15 @@ extension SocketParsable {
|
|||||||
DefaultSocketLogger.Logger.log("Parsing %@", type: "SocketParser", args: message)
|
DefaultSocketLogger.Logger.log("Parsing %@", type: "SocketParser", args: message)
|
||||||
|
|
||||||
switch parseString(message) {
|
switch parseString(message) {
|
||||||
case let .Left(err):
|
case let .left(err):
|
||||||
DefaultSocketLogger.Logger.error("\(err): %@", type: "SocketParser", args: message)
|
DefaultSocketLogger.Logger.error("\(err): %@", type: "SocketParser", args: message)
|
||||||
case let .Right(pack):
|
case let .right(pack):
|
||||||
DefaultSocketLogger.Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description)
|
DefaultSocketLogger.Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description)
|
||||||
handlePacket(pack)
|
handlePacket(pack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseBinaryData(_ data: NSData) {
|
func parseBinaryData(_ data: Data) {
|
||||||
guard !waitingPackets.isEmpty else {
|
guard !waitingPackets.isEmpty else {
|
||||||
DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser")
|
DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser")
|
||||||
return
|
return
|
||||||
@ -165,7 +165,7 @@ extension SocketParsable {
|
|||||||
|
|
||||||
let packet = waitingPackets.removeLast()
|
let packet = waitingPackets.removeLast()
|
||||||
|
|
||||||
if packet.type != .BinaryAck {
|
if packet.type != .binaryAck {
|
||||||
handleEvent(packet.event, data: packet.args ?? [],
|
handleEvent(packet.event, data: packet.args ?? [],
|
||||||
isInternalMessage: false, withAck: packet.id)
|
isInternalMessage: false, withAck: packet.id)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -39,15 +39,15 @@ struct SocketStringReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
mutating func advance(by: Int) -> String.Index {
|
mutating func advance(_ by: Int) -> String.Index {
|
||||||
currentIndex = message.characters.index(currentIndex, offsetBy: by)
|
currentIndex = message.characters.index(currentIndex, offsetBy: by)
|
||||||
|
|
||||||
return currentIndex
|
return currentIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func read(length: Int) -> String {
|
mutating func read(_ length: Int) -> String {
|
||||||
let readString = message[currentIndex..<message.characters.index(currentIndex, offsetBy: length)]
|
let readString = message[currentIndex..<message.characters.index(currentIndex, offsetBy: length)]
|
||||||
advance(by: length)
|
advance(length)
|
||||||
|
|
||||||
return readString
|
return readString
|
||||||
}
|
}
|
||||||
@ -60,12 +60,12 @@ struct SocketStringReader {
|
|||||||
return substring
|
return substring
|
||||||
}
|
}
|
||||||
|
|
||||||
advance(by: message.characters.distance(from: message.characters.startIndex, to: foundRange.lowerBound) + 1)
|
advance(message.characters.distance(from: message.characters.startIndex, to: foundRange.lowerBound) + 1)
|
||||||
|
|
||||||
return substring.substring(to: foundRange.lowerBound)
|
return substring.substring(to: foundRange.lowerBound)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func readUntilEnd() -> String {
|
mutating func readUntilEnd() -> String {
|
||||||
return read(length: message.characters.distance(from: currentIndex, to: message.endIndex))
|
return read(message.characters.distance(from: currentIndex, to: message.endIndex))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ extension Dictionary : SocketData {}
|
|||||||
extension Double : SocketData {}
|
extension Double : SocketData {}
|
||||||
extension Int : SocketData {}
|
extension Int : SocketData {}
|
||||||
extension NSArray : SocketData {}
|
extension NSArray : SocketData {}
|
||||||
extension NSData : SocketData {}
|
extension Data : SocketData {}
|
||||||
extension NSDictionary : SocketData {}
|
extension NSDictionary : SocketData {}
|
||||||
extension NSString : SocketData {}
|
extension NSString : SocketData {}
|
||||||
extension NSNull : SocketData {}
|
extension NSNull : SocketData {}
|
||||||
@ -42,10 +42,10 @@ public typealias AckCallback = ([AnyObject]) -> Void
|
|||||||
public typealias NormalCallback = ([AnyObject], SocketAckEmitter) -> Void
|
public typealias NormalCallback = ([AnyObject], SocketAckEmitter) -> Void
|
||||||
public typealias OnAckCallback = (timeoutAfter: UInt64, callback: AckCallback) -> Void
|
public typealias OnAckCallback = (timeoutAfter: UInt64, callback: AckCallback) -> Void
|
||||||
|
|
||||||
typealias Probe = (msg: String, type: SocketEnginePacketType, data: [NSData])
|
typealias Probe = (msg: String, type: SocketEnginePacketType, data: [Data])
|
||||||
typealias ProbeWaitQueue = [Probe]
|
typealias ProbeWaitQueue = [Probe]
|
||||||
|
|
||||||
enum Either<E, V> {
|
enum Either<E, V> {
|
||||||
case Left(E)
|
case left(E)
|
||||||
case Right(V)
|
case right(V)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import Foundation
|
|||||||
import Security
|
import Security
|
||||||
|
|
||||||
public class SSLCert : NSObject {
|
public class SSLCert : NSObject {
|
||||||
var certData: NSData?
|
var certData: Data?
|
||||||
var key: SecKey?
|
var key: SecKey?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +34,7 @@ public class SSLCert : NSObject {
|
|||||||
|
|
||||||
- returns: a representation security object to be used with
|
- returns: a representation security object to be used with
|
||||||
*/
|
*/
|
||||||
public init(data: NSData) {
|
public init(data: Data) {
|
||||||
self.certData = data
|
self.certData = data
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ public class SSLSecurity : NSObject {
|
|||||||
public var validatedDN = true //should the domain name be validated?
|
public var validatedDN = true //should the domain name be validated?
|
||||||
|
|
||||||
var isReady = false //is the key processing done?
|
var isReady = false //is the key processing done?
|
||||||
var certificates: [NSData]? //the certificates
|
var certificates: [Data]? //the certificates
|
||||||
var pubKeys: [SecKey]? //the public keys
|
var pubKeys: [SecKey]? //the public keys
|
||||||
var usePublicKeys = false //use public keys or certificate validation?
|
var usePublicKeys = false //use public keys or certificate validation?
|
||||||
|
|
||||||
@ -66,12 +66,12 @@ public class SSLSecurity : NSObject {
|
|||||||
- returns: a representation security object to be used with
|
- returns: a representation security object to be used with
|
||||||
*/
|
*/
|
||||||
public convenience init(usePublicKeys: Bool = false) {
|
public convenience init(usePublicKeys: Bool = false) {
|
||||||
let paths = NSBundle.main().pathsForResources(ofType: "cer", inDirectory: ".")
|
let paths = Bundle.main().pathsForResources(ofType: "cer", inDirectory: ".")
|
||||||
|
|
||||||
let certs = paths.reduce([SSLCert]()) { (certs: [SSLCert], path: String) -> [SSLCert] in
|
let certs = paths.reduce([SSLCert]()) { (certs: [SSLCert], path: String) -> [SSLCert] in
|
||||||
var certs = certs
|
var certs = certs
|
||||||
if let data = NSData(contentsOfFile: path) {
|
if let data = NSData(contentsOfFile: path) {
|
||||||
certs.append(SSLCert(data: data))
|
certs.append(SSLCert(data: data as Data))
|
||||||
}
|
}
|
||||||
return certs
|
return certs
|
||||||
}
|
}
|
||||||
@ -93,11 +93,11 @@ public class SSLSecurity : NSObject {
|
|||||||
self.usePublicKeys = usePublicKeys
|
self.usePublicKeys = usePublicKeys
|
||||||
|
|
||||||
if self.usePublicKeys {
|
if self.usePublicKeys {
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)) {
|
DispatchQueue.global(attributes: DispatchQueue.GlobalAttributes.qosDefault).async {
|
||||||
let pubKeys = certs.reduce([SecKey]()) { (pubKeys: [SecKey], cert: SSLCert) -> [SecKey] in
|
let pubKeys = certs.reduce([SecKey]()) { (pubKeys: [SecKey], cert: SSLCert) -> [SecKey] in
|
||||||
var pubKeys = pubKeys
|
var pubKeys = pubKeys
|
||||||
if let data = cert.certData where cert.key == nil {
|
if let data = cert.certData where cert.key == nil {
|
||||||
cert.key = self.extractPublicKey(data: data)
|
cert.key = self.extractPublicKey(data)
|
||||||
}
|
}
|
||||||
if let key = cert.key {
|
if let key = cert.key {
|
||||||
pubKeys.append(key)
|
pubKeys.append(key)
|
||||||
@ -109,7 +109,7 @@ public class SSLSecurity : NSObject {
|
|||||||
self.isReady = true
|
self.isReady = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let certificates = certs.reduce([NSData]()) { (certificates: [NSData], cert: SSLCert) -> [NSData] in
|
let certificates = certs.reduce([Data]()) { (certificates: [Data], cert: SSLCert) -> [Data] in
|
||||||
var certificates = certificates
|
var certificates = certificates
|
||||||
if let data = cert.certData {
|
if let data = cert.certData {
|
||||||
certificates.append(data)
|
certificates.append(data)
|
||||||
@ -129,7 +129,7 @@ public class SSLSecurity : NSObject {
|
|||||||
|
|
||||||
- returns: if the key was successfully validated
|
- returns: if the key was successfully validated
|
||||||
*/
|
*/
|
||||||
public func isValid(trust: SecTrust, domain: String?) -> Bool {
|
public func isValid(_ trust: SecTrust, domain: String?) -> Bool {
|
||||||
|
|
||||||
var tries = 0
|
var tries = 0
|
||||||
while(!self.isReady) {
|
while(!self.isReady) {
|
||||||
@ -141,14 +141,14 @@ public class SSLSecurity : NSObject {
|
|||||||
}
|
}
|
||||||
var policy: SecPolicy
|
var policy: SecPolicy
|
||||||
if self.validatedDN {
|
if self.validatedDN {
|
||||||
policy = SecPolicyCreateSSL(true, domain)
|
policy = SecPolicyCreateSSL(true, domain)!
|
||||||
} else {
|
} else {
|
||||||
policy = SecPolicyCreateBasicX509()
|
policy = SecPolicyCreateBasicX509()!
|
||||||
}
|
}
|
||||||
SecTrustSetPolicies(trust,policy)
|
SecTrustSetPolicies(trust,policy)
|
||||||
if self.usePublicKeys {
|
if self.usePublicKeys {
|
||||||
if let keys = self.pubKeys {
|
if let keys = self.pubKeys {
|
||||||
let serverPubKeys = publicKeyChainForTrust(trust: trust)
|
let serverPubKeys = publicKeyChainForTrust(trust)
|
||||||
for serverKey in serverPubKeys as [AnyObject] {
|
for serverKey in serverPubKeys as [AnyObject] {
|
||||||
for key in keys as [AnyObject] {
|
for key in keys as [AnyObject] {
|
||||||
if serverKey.isEqual(key) {
|
if serverKey.isEqual(key) {
|
||||||
@ -158,16 +158,16 @@ public class SSLSecurity : NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let certs = self.certificates {
|
} else if let certs = self.certificates {
|
||||||
let serverCerts = certificateChainForTrust(trust: trust)
|
let serverCerts = certificateChainForTrust(trust)
|
||||||
var collect = [SecCertificate]()
|
var collect = [SecCertificate]()
|
||||||
for cert in certs {
|
for cert in certs {
|
||||||
collect.append(SecCertificateCreateWithData(nil,cert)!)
|
collect.append(SecCertificateCreateWithData(nil,cert)!)
|
||||||
}
|
}
|
||||||
SecTrustSetAnchorCertificates(trust,collect)
|
SecTrustSetAnchorCertificates(trust,collect)
|
||||||
var result: SecTrustResultType = 0
|
var result = SecTrustResultType(rawValue: 0)!
|
||||||
SecTrustEvaluate(trust,&result)
|
SecTrustEvaluate(trust,&result)
|
||||||
let r = Int(result)
|
let r = Int(result.rawValue)
|
||||||
if r == kSecTrustResultUnspecified || r == kSecTrustResultProceed {
|
if r == Int(SecTrustResultType.unspecified.rawValue) || r == Int(SecTrustResultType.proceed.rawValue) {
|
||||||
var trustedCount = 0
|
var trustedCount = 0
|
||||||
for serverCert in serverCerts {
|
for serverCert in serverCerts {
|
||||||
for cert in certs {
|
for cert in certs {
|
||||||
@ -192,10 +192,10 @@ public class SSLSecurity : NSObject {
|
|||||||
|
|
||||||
- returns: a public key
|
- returns: a public key
|
||||||
*/
|
*/
|
||||||
func extractPublicKey(data: NSData) -> SecKey? {
|
func extractPublicKey(_ data: Data) -> SecKey? {
|
||||||
guard let cert = SecCertificateCreateWithData(nil, data) else { return nil }
|
guard let cert = SecCertificateCreateWithData(nil, data) else { return nil }
|
||||||
|
|
||||||
return extractPublicKeyFromCert(cert: cert, policy: SecPolicyCreateBasicX509())
|
return extractPublicKeyFromCert(cert, policy: SecPolicyCreateBasicX509()!)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -205,13 +205,13 @@ public class SSLSecurity : NSObject {
|
|||||||
|
|
||||||
- returns: a public key
|
- returns: a public key
|
||||||
*/
|
*/
|
||||||
func extractPublicKeyFromCert(cert: SecCertificate, policy: SecPolicy) -> SecKey? {
|
func extractPublicKeyFromCert(_ cert: SecCertificate, policy: SecPolicy) -> SecKey? {
|
||||||
var possibleTrust: SecTrust?
|
var possibleTrust: SecTrust?
|
||||||
SecTrustCreateWithCertificates(cert, policy, &possibleTrust)
|
SecTrustCreateWithCertificates(cert, policy, &possibleTrust)
|
||||||
|
|
||||||
guard let trust = possibleTrust else { return nil }
|
guard let trust = possibleTrust else { return nil }
|
||||||
|
|
||||||
var result: SecTrustResultType = 0
|
var result = SecTrustResultType(rawValue: 0)!
|
||||||
SecTrustEvaluate(trust, &result)
|
SecTrustEvaluate(trust, &result)
|
||||||
return SecTrustCopyPublicKey(trust)
|
return SecTrustCopyPublicKey(trust)
|
||||||
}
|
}
|
||||||
@ -223,11 +223,11 @@ public class SSLSecurity : NSObject {
|
|||||||
|
|
||||||
- returns: the certificate chain for the trust
|
- returns: the certificate chain for the trust
|
||||||
*/
|
*/
|
||||||
func certificateChainForTrust(trust: SecTrust) -> [NSData] {
|
func certificateChainForTrust(_ trust: SecTrust) -> [Data] {
|
||||||
let certificates = (0..<SecTrustGetCertificateCount(trust)).reduce([NSData]()) { (certificates: [NSData], index: Int) -> [NSData] in
|
let certificates = (0..<SecTrustGetCertificateCount(trust)).reduce([Data]()) { (certificates: [Data], index: Int) -> [Data] in
|
||||||
var certificates = certificates
|
var certificates = certificates
|
||||||
let cert = SecTrustGetCertificateAtIndex(trust, index)
|
let cert = SecTrustGetCertificateAtIndex(trust, index)
|
||||||
certificates.append(SecCertificateCopyData(cert!))
|
certificates.append(SecCertificateCopyData(cert!) as Data)
|
||||||
return certificates
|
return certificates
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,12 +241,12 @@ public class SSLSecurity : NSObject {
|
|||||||
|
|
||||||
- returns: the public keys from the certifcate chain for the trust
|
- returns: the public keys from the certifcate chain for the trust
|
||||||
*/
|
*/
|
||||||
func publicKeyChainForTrust(trust: SecTrust) -> [SecKey] {
|
func publicKeyChainForTrust(_ trust: SecTrust) -> [SecKey] {
|
||||||
let policy = SecPolicyCreateBasicX509()
|
let policy = SecPolicyCreateBasicX509()
|
||||||
let keys = (0..<SecTrustGetCertificateCount(trust)).reduce([SecKey]()) { (keys: [SecKey], index: Int) -> [SecKey] in
|
let keys = (0..<SecTrustGetCertificateCount(trust)).reduce([SecKey]()) { (keys: [SecKey], index: Int) -> [SecKey] in
|
||||||
var keys = keys
|
var keys = keys
|
||||||
let cert = SecTrustGetCertificateAtIndex(trust, index)
|
let cert = SecTrustGetCertificateAtIndex(trust, index)
|
||||||
if let key = extractPublicKeyFromCert(cert: cert!, policy: policy) {
|
if let key = extractPublicKeyFromCert(cert!, policy: policy!) {
|
||||||
keys.append(key)
|
keys.append(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,40 +28,40 @@ public let WebsocketDidDisconnectNotification = "WebsocketDidDisconnectNotificat
|
|||||||
public let WebsocketDisconnectionErrorKeyName = "WebsocketDisconnectionErrorKeyName"
|
public let WebsocketDisconnectionErrorKeyName = "WebsocketDisconnectionErrorKeyName"
|
||||||
|
|
||||||
public protocol WebSocketDelegate: class {
|
public protocol WebSocketDelegate: class {
|
||||||
func websocketDidConnect(socket: WebSocket)
|
func websocketDidConnect(_ socket: WebSocket)
|
||||||
func websocketDidDisconnect(socket: WebSocket, error: NSError?)
|
func websocketDidDisconnect(_ socket: WebSocket, error: NSError?)
|
||||||
func websocketDidReceiveMessage(socket: WebSocket, text: String)
|
func websocketDidReceiveMessage(_ socket: WebSocket, text: String)
|
||||||
func websocketDidReceiveData(socket: WebSocket, data: NSData)
|
func websocketDidReceiveData(_ socket: WebSocket, data: Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol WebSocketPongDelegate: class {
|
public protocol WebSocketPongDelegate: class {
|
||||||
func websocketDidReceivePong(socket: WebSocket)
|
func websocketDidReceivePong(_ socket: WebSocket)
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WebSocket : NSObject, NSStreamDelegate {
|
public class WebSocket : NSObject, StreamDelegate {
|
||||||
|
|
||||||
enum OpCode : UInt8 {
|
enum OpCode : UInt8 {
|
||||||
case ContinueFrame = 0x0
|
case continueFrame = 0x0
|
||||||
case TextFrame = 0x1
|
case textFrame = 0x1
|
||||||
case BinaryFrame = 0x2
|
case binaryFrame = 0x2
|
||||||
//3-7 are reserved.
|
//3-7 are reserved.
|
||||||
case ConnectionClose = 0x8
|
case connectionClose = 0x8
|
||||||
case Ping = 0x9
|
case ping = 0x9
|
||||||
case Pong = 0xA
|
case pong = 0xA
|
||||||
//B-F reserved.
|
//B-F reserved.
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CloseCode : UInt16 {
|
public enum CloseCode : UInt16 {
|
||||||
case Normal = 1000
|
case normal = 1000
|
||||||
case GoingAway = 1001
|
case goingAway = 1001
|
||||||
case ProtocolError = 1002
|
case protocolError = 1002
|
||||||
case ProtocolUnhandledType = 1003
|
case protocolUnhandledType = 1003
|
||||||
// 1004 reserved.
|
// 1004 reserved.
|
||||||
case NoStatusReceived = 1005
|
case noStatusReceived = 1005
|
||||||
//1006 reserved.
|
//1006 reserved.
|
||||||
case Encoding = 1007
|
case encoding = 1007
|
||||||
case PolicyViolated = 1008
|
case policyViolated = 1008
|
||||||
case MessageTooBig = 1009
|
case messageTooBig = 1009
|
||||||
}
|
}
|
||||||
|
|
||||||
#if swift(>=3)
|
#if swift(>=3)
|
||||||
@ -71,11 +71,11 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
|
|
||||||
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 = DispatchQueue.main
|
||||||
|
|
||||||
var optionalProtocols : [String]?
|
var optionalProtocols : [String]?
|
||||||
//Constant Values.
|
//Constant Values.
|
||||||
@ -100,7 +100,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
|
|
||||||
class WSResponse {
|
class WSResponse {
|
||||||
var isFin = false
|
var isFin = false
|
||||||
var code: OpCode = .ContinueFrame
|
var code: OpCode = .continueFrame
|
||||||
var bytesLeft = 0
|
var bytesLeft = 0
|
||||||
var frameCount = 0
|
var frameCount = 0
|
||||||
var buffer: NSMutableData?
|
var buffer: NSMutableData?
|
||||||
@ -111,7 +111,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
public var onConnect: ((Void) -> Void)?
|
public var onConnect: ((Void) -> Void)?
|
||||||
public var onDisconnect: ((NSError?) -> Void)?
|
public var onDisconnect: ((NSError?) -> Void)?
|
||||||
public var onText: ((String) -> Void)?
|
public var onText: ((String) -> Void)?
|
||||||
public var onData: ((NSData) -> Void)?
|
public var onData: ((Data) -> Void)?
|
||||||
public var onPong: ((Void) -> Void)?
|
public var onPong: ((Void) -> Void)?
|
||||||
public var headers = [String: String]()
|
public var headers = [String: String]()
|
||||||
public var voipEnabled = false
|
public var voipEnabled = false
|
||||||
@ -123,21 +123,21 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
public var isConnected :Bool {
|
public var isConnected :Bool {
|
||||||
return connected
|
return connected
|
||||||
}
|
}
|
||||||
public var currentURL: NSURL {return url}
|
public var currentURL: URL {return url}
|
||||||
private var url: NSURL
|
private var url: URL
|
||||||
private var inputStream: NSInputStream?
|
private var inputStream: InputStream?
|
||||||
private var outputStream: NSOutputStream?
|
private var outputStream: NSOutputStream?
|
||||||
private var connected = false
|
private var connected = false
|
||||||
private var isCreated = false
|
private var isCreated = false
|
||||||
private var writeQueue = NSOperationQueue()
|
private var writeQueue = OperationQueue()
|
||||||
private var readStack = [WSResponse]()
|
private var readStack = [WSResponse]()
|
||||||
private var inputQueue = [NSData]()
|
private var inputQueue = [Data]()
|
||||||
private var fragBuffer: NSData?
|
private var fragBuffer: Data?
|
||||||
private var certValidated = false
|
private var certValidated = false
|
||||||
private var didDisconnect = false
|
private var didDisconnect = false
|
||||||
private var readyToWrite = false
|
private var readyToWrite = false
|
||||||
private let mutex = NSLock()
|
private let mutex = Lock()
|
||||||
private let notificationCenter = NSNotificationCenter.default()
|
private let notificationCenter = NotificationCenter.default()
|
||||||
private var canDispatch: Bool {
|
private var canDispatch: Bool {
|
||||||
mutex.lock()
|
mutex.lock()
|
||||||
let canWork = readyToWrite
|
let canWork = readyToWrite
|
||||||
@ -145,10 +145,10 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
return canWork
|
return canWork
|
||||||
}
|
}
|
||||||
//the shared processing queue used for all websocket
|
//the shared processing queue used for all websocket
|
||||||
private static let sharedWorkQueue = dispatch_queue_create("com.vluxe.starscream.websocket", DISPATCH_QUEUE_SERIAL)
|
private static let sharedWorkQueue = DispatchQueue(label: "com.vluxe.starscream.websocket", attributes: DispatchQueueAttributes.serial)
|
||||||
|
|
||||||
//used for setting protocols.
|
//used for setting protocols.
|
||||||
public init(url: NSURL, protocols: [String]? = nil) {
|
public init(url: URL, protocols: [String]? = nil) {
|
||||||
self.url = url
|
self.url = url
|
||||||
self.origin = url.absoluteString
|
self.origin = url.absoluteString
|
||||||
writeQueue.maxConcurrentOperationCount = 1
|
writeQueue.maxConcurrentOperationCount = 1
|
||||||
@ -173,18 +173,18 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
|
|
||||||
- Parameter forceTimeout: Maximum time to wait for the server to close the socket.
|
- Parameter forceTimeout: Maximum time to wait for the server to close the socket.
|
||||||
*/
|
*/
|
||||||
public func disconnect(forceTimeout: NSTimeInterval? = nil) {
|
public func disconnect(_ forceTimeout: TimeInterval? = nil) {
|
||||||
switch forceTimeout {
|
switch forceTimeout {
|
||||||
case .some(let seconds) where seconds > 0:
|
case .some(let seconds) where seconds > 0:
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC))), queue!) { [weak self] in
|
queue.after(when: DispatchTime.now() + Double(Int64(seconds * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { [weak self] in
|
||||||
self?.disconnectStream(error: nil)
|
self?.disconnectStream(nil)
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case .none:
|
case .none:
|
||||||
writeError(code: CloseCode.Normal.rawValue)
|
writeError(CloseCode.normal.rawValue)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
self.disconnectStream(error: nil)
|
self.disconnectStream(nil)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,9 +197,9 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
- parameter str: The string to write.
|
- parameter str: The string to write.
|
||||||
- parameter completion: The (optional) completion handler.
|
- parameter completion: The (optional) completion handler.
|
||||||
*/
|
*/
|
||||||
public func writeString(str: String, completion: (() -> ())? = nil) {
|
public func writeString(_ str: String, completion: (() -> ())? = nil) {
|
||||||
guard isConnected else { return }
|
guard isConnected else { return }
|
||||||
dequeueWrite(data: str.data(using: NSUTF8StringEncoding)!, code: .TextFrame, writeCompletion: completion)
|
dequeueWrite(str.data(using: String.Encoding.utf8)!, code: .textFrame, writeCompletion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,16 +210,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
- parameter data: The data to write.
|
- parameter data: The data to write.
|
||||||
- parameter completion: The (optional) completion handler.
|
- parameter completion: The (optional) completion handler.
|
||||||
*/
|
*/
|
||||||
public func writeData(data: NSData, completion: (() -> ())? = nil) {
|
public func writeData(_ data: Data, completion: (() -> ())? = nil) {
|
||||||
guard isConnected else { return }
|
guard isConnected else { return }
|
||||||
dequeueWrite(data: data, code: .BinaryFrame, writeCompletion: completion)
|
dequeueWrite(data, code: .binaryFrame, writeCompletion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
//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, completion: (() -> ())? = nil) {
|
public func writePing(_ data: Data, completion: (() -> ())? = nil) {
|
||||||
guard isConnected else { return }
|
guard isConnected else { return }
|
||||||
dequeueWrite(data: data, code: .Ping, writeCompletion: completion)
|
dequeueWrite(data, code: .ping, writeCompletion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
//private method that starts the connection
|
//private method that starts the connection
|
||||||
@ -230,34 +230,34 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
|
|
||||||
var port = url.port
|
var port = url.port
|
||||||
if port == nil {
|
if port == nil {
|
||||||
if ["wss", "https"].contains(url.scheme) {
|
if ["wss", "https"].contains(url.scheme!) {
|
||||||
port = 443
|
port = 443
|
||||||
} else {
|
} else {
|
||||||
port = 80
|
port = 80
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addHeader(urlRequest: urlRequest, key: headerWSUpgradeName as NSString, val: headerWSUpgradeValue as NSString)
|
addHeader(urlRequest, key: headerWSUpgradeName as NSString, val: headerWSUpgradeValue as NSString)
|
||||||
addHeader(urlRequest: urlRequest, key: headerWSConnectionName as NSString, val: headerWSConnectionValue as NSString)
|
addHeader(urlRequest, key: headerWSConnectionName as NSString, val: headerWSConnectionValue as NSString)
|
||||||
if let protocols = optionalProtocols {
|
if let protocols = optionalProtocols {
|
||||||
addHeader(urlRequest: urlRequest, key: headerWSProtocolName as NSString, val: protocols.joined(separator: ",") as NSString)
|
addHeader(urlRequest, key: headerWSProtocolName as NSString, val: protocols.joined(separator: ",") as NSString)
|
||||||
}
|
}
|
||||||
addHeader(urlRequest: urlRequest, key: headerWSVersionName as NSString, val: headerWSVersionValue as NSString)
|
addHeader(urlRequest, key: headerWSVersionName as NSString, val: headerWSVersionValue as NSString)
|
||||||
addHeader(urlRequest: urlRequest, key: headerWSKeyName as NSString, val: generateWebSocketKey() as NSString)
|
addHeader(urlRequest, key: headerWSKeyName as NSString, val: generateWebSocketKey() as NSString)
|
||||||
if let origin = origin {
|
if let origin = origin {
|
||||||
addHeader(urlRequest: urlRequest, key: headerOriginName as NSString, val: origin as NSString)
|
addHeader(urlRequest, key: headerOriginName as NSString, val: origin as NSString)
|
||||||
}
|
}
|
||||||
addHeader(urlRequest: urlRequest, key: headerWSHostName as NSString, val: "\(url.host!):\(port!)" as NSString)
|
addHeader(urlRequest, key: headerWSHostName as NSString, val: "\(url.host!):\(port!)" as NSString)
|
||||||
for (key,value) in headers {
|
for (key,value) in headers {
|
||||||
addHeader(urlRequest: urlRequest, key: key as NSString, val: value as NSString)
|
addHeader(urlRequest, key: key as NSString, val: value as NSString)
|
||||||
}
|
}
|
||||||
if let cfHTTPMessage = CFHTTPMessageCopySerializedMessage(urlRequest) {
|
if let cfHTTPMessage = CFHTTPMessageCopySerializedMessage(urlRequest) {
|
||||||
let serializedRequest = cfHTTPMessage.takeRetainedValue()
|
let serializedRequest = cfHTTPMessage.takeRetainedValue()
|
||||||
initStreamsWithData(data: serializedRequest, Int(port!))
|
initStreamsWithData(serializedRequest as Data, Int(port!))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add a header to the CFHTTPMessage by using the NSString bridges to CFString
|
//Add a header to the CFHTTPMessage by using the NSString bridges to CFString
|
||||||
private func addHeader(urlRequest: CFHTTPMessage, key: NSString, val: NSString) {
|
private func addHeader(_ urlRequest: CFHTTPMessage, key: NSString, val: NSString) {
|
||||||
CFHTTPMessageSetHeaderFieldValue(urlRequest, key, val)
|
CFHTTPMessageSetHeaderFieldValue(urlRequest, key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,13 +269,13 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
let uni = UnicodeScalar(UInt32(97 + arc4random_uniform(25)))
|
let uni = UnicodeScalar(UInt32(97 + arc4random_uniform(25)))
|
||||||
key += "\(Character(uni))"
|
key += "\(Character(uni))"
|
||||||
}
|
}
|
||||||
let data = key.data(using: NSUTF8StringEncoding)
|
let data = key.data(using: String.Encoding.utf8)
|
||||||
let baseKey = data?.base64EncodedString(NSDataBase64EncodingOptions(rawValue: 0))
|
let baseKey = data?.base64EncodedString(NSData.Base64EncodingOptions(rawValue: 0))
|
||||||
return baseKey!
|
return baseKey!
|
||||||
}
|
}
|
||||||
|
|
||||||
//Start the stream connection and write the data to the output stream
|
//Start the stream connection and write the data to the output stream
|
||||||
private func initStreamsWithData(data: NSData, _ port: Int) {
|
private func initStreamsWithData(_ data: Data, _ 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)
|
||||||
|
|
||||||
@ -288,15 +288,15 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
guard let inStream = inputStream, let outStream = outputStream else { return }
|
guard let inStream = inputStream, let outStream = outputStream else { return }
|
||||||
inStream.delegate = self
|
inStream.delegate = self
|
||||||
outStream.delegate = self
|
outStream.delegate = self
|
||||||
if ["wss", "https"].contains(url.scheme) {
|
if ["wss", "https"].contains(url.scheme!) {
|
||||||
inStream.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL as NSString, forKey: NSStreamSocketSecurityLevelKey)
|
inStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as NSString, forKey: Stream.PropertyKey.socketSecurityLevelKey.rawValue)
|
||||||
outStream.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL as NSString, forKey: NSStreamSocketSecurityLevelKey)
|
outStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as NSString, forKey: Stream.PropertyKey.socketSecurityLevelKey.rawValue)
|
||||||
} else {
|
} else {
|
||||||
certValidated = true //not a https session, so no need to check SSL pinning
|
certValidated = true //not a https session, so no need to check SSL pinning
|
||||||
}
|
}
|
||||||
if voipEnabled {
|
if voipEnabled {
|
||||||
inStream.setProperty(NSStreamNetworkServiceTypeVoIP as NSString, forKey: NSStreamNetworkServiceType)
|
inStream.setProperty(StreamNetworkServiceTypeValue.voip as NSString, forKey: Stream.PropertyKey.networkServiceType.rawValue)
|
||||||
outStream.setProperty(NSStreamNetworkServiceTypeVoIP as NSString, forKey: NSStreamNetworkServiceType)
|
outStream.setProperty(StreamNetworkServiceTypeValue.voip as NSString, forKey: Stream.PropertyKey.networkServiceType.rawValue)
|
||||||
}
|
}
|
||||||
if selfSignedSSL {
|
if selfSignedSSL {
|
||||||
let settings: [NSObject: NSObject] = [kCFStreamSSLValidatesCertificateChain: NSNumber(value: false), kCFStreamSSLPeerName: kCFNull]
|
let settings: [NSObject: NSObject] = [kCFStreamSSLValidatesCertificateChain: NSNumber(value: false), kCFStreamSSLPeerName: kCFNull]
|
||||||
@ -304,18 +304,18 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
outStream.setProperty(settings as AnyObject?, forKey: kCFStreamPropertySSLSettings as String)
|
outStream.setProperty(settings as AnyObject?, forKey: kCFStreamPropertySSLSettings as String)
|
||||||
}
|
}
|
||||||
if let cipherSuites = self.enabledSSLCipherSuites {
|
if let cipherSuites = self.enabledSSLCipherSuites {
|
||||||
if let sslContextIn = CFReadStreamCopyProperty(inputStream, kCFStreamPropertySSLContext) as! SSLContext?,
|
if let sslContextIn = CFReadStreamCopyProperty(inputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext?,
|
||||||
sslContextOut = CFWriteStreamCopyProperty(outputStream, kCFStreamPropertySSLContext) as! SSLContext? {
|
sslContextOut = CFWriteStreamCopyProperty(outputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext? {
|
||||||
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
|
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
|
||||||
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
|
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
|
||||||
if resIn != errSecSuccess {
|
if resIn != errSecSuccess {
|
||||||
let error = self.errorWithDetail(detail: "Error setting ingoing cypher suites", code: UInt16(resIn))
|
let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn))
|
||||||
disconnectStream(error: error)
|
disconnectStream(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if resOut != errSecSuccess {
|
if resOut != errSecSuccess {
|
||||||
let error = self.errorWithDetail(detail: "Error setting outgoing cypher suites", code: UInt16(resOut))
|
let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut))
|
||||||
disconnectStream(error: error)
|
disconnectStream(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,7 +329,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
self.readyToWrite = true
|
self.readyToWrite = true
|
||||||
self.mutex.unlock()
|
self.mutex.unlock()
|
||||||
|
|
||||||
let bytes = UnsafePointer<UInt8>(data.bytes)
|
let bytes = UnsafePointer<UInt8>((data as NSData).bytes)
|
||||||
var out = timeout * 1000000 //wait 5 seconds before giving up
|
var out = timeout * 1000000 //wait 5 seconds before giving up
|
||||||
writeQueue.addOperation { [weak self] in
|
writeQueue.addOperation { [weak self] in
|
||||||
while !outStream.hasSpaceAvailable {
|
while !outStream.hasSpaceAvailable {
|
||||||
@ -337,27 +337,27 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
out -= 100
|
out -= 100
|
||||||
if out < 0 {
|
if out < 0 {
|
||||||
self?.cleanupStream()
|
self?.cleanupStream()
|
||||||
self?.doDisconnect(error: self?.errorWithDetail(detail: "write wait timed out", code: 2))
|
self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: 2))
|
||||||
return
|
return
|
||||||
} else if outStream.streamError != nil {
|
} else if outStream.streamError != nil {
|
||||||
return //disconnectStream will be called.
|
return //disconnectStream will be called.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outStream.write(bytes, maxLength: data.length)
|
outStream.write(bytes, maxLength: data.count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//delegate for the stream methods. Processes incoming bytes
|
//delegate for the stream methods. Processes incoming bytes
|
||||||
public func stream(aStream: NSStream, handle eventCode: NSStreamEvent) {
|
public func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
|
||||||
if let sec = security where !certValidated && [.hasBytesAvailable, .hasSpaceAvailable].contains(eventCode) {
|
if let sec = security where !certValidated && [.hasBytesAvailable, .hasSpaceAvailable].contains(eventCode) {
|
||||||
let possibleTrust: AnyObject? = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as String)
|
let possibleTrust: AnyObject? = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as String)
|
||||||
if let trust: AnyObject = possibleTrust {
|
if let trust: AnyObject = possibleTrust {
|
||||||
let domain: AnyObject? = aStream.property(forKey: kCFStreamSSLPeerName as String)
|
let domain: AnyObject? = aStream.property(forKey: kCFStreamSSLPeerName as String)
|
||||||
if sec.isValid(trust: trust as! SecTrust, domain: domain as! String?) {
|
if sec.isValid(trust as! SecTrust, domain: domain as! String?) {
|
||||||
certValidated = true
|
certValidated = true
|
||||||
} else {
|
} else {
|
||||||
let error = errorWithDetail(detail: "Invalid SSL certificate", code: 1)
|
let error = errorWithDetail("Invalid SSL certificate", code: 1)
|
||||||
disconnectStream(error: error)
|
disconnectStream(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,20 +367,20 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
processInputStream()
|
processInputStream()
|
||||||
}
|
}
|
||||||
} else if eventCode == .errorOccurred {
|
} else if eventCode == .errorOccurred {
|
||||||
disconnectStream(error: aStream.streamError)
|
disconnectStream(aStream.streamError)
|
||||||
} else if eventCode == .endEncountered {
|
} else if eventCode == .endEncountered {
|
||||||
disconnectStream(error: nil)
|
disconnectStream(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//disconnect the stream object
|
//disconnect the stream object
|
||||||
private func disconnectStream(error: NSError?) {
|
private func disconnectStream(_ error: NSError?) {
|
||||||
if error == nil {
|
if error == nil {
|
||||||
writeQueue.waitUntilAllOperationsAreFinished()
|
writeQueue.waitUntilAllOperationsAreFinished()
|
||||||
} else {
|
} else {
|
||||||
writeQueue.cancelAllOperations()
|
writeQueue.cancelAllOperations()
|
||||||
}
|
}
|
||||||
cleanupStream()
|
cleanupStream()
|
||||||
doDisconnect(error: error)
|
doDisconnect(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func cleanupStream() {
|
private func cleanupStream() {
|
||||||
@ -409,7 +409,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
if inputQueue.count == 0 {
|
if inputQueue.count == 0 {
|
||||||
process = true
|
process = true
|
||||||
}
|
}
|
||||||
inputQueue.append(NSData(bytes: buffer, length: length))
|
inputQueue.append(Data(bytes: UnsafePointer<UInt8>(buffer), count: length))
|
||||||
if process {
|
if process {
|
||||||
dequeueInput()
|
dequeueInput()
|
||||||
}
|
}
|
||||||
@ -420,44 +420,44 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
let data = inputQueue[0]
|
let data = inputQueue[0]
|
||||||
var work = data
|
var work = data
|
||||||
if let fragBuffer = fragBuffer {
|
if let fragBuffer = fragBuffer {
|
||||||
let combine = NSMutableData(data: fragBuffer)
|
var combine = NSData(data: fragBuffer) as Data
|
||||||
combine.append(data)
|
combine.append(data)
|
||||||
work = combine
|
work = combine
|
||||||
self.fragBuffer = nil
|
self.fragBuffer = nil
|
||||||
}
|
}
|
||||||
let buffer = UnsafePointer<UInt8>(work.bytes)
|
let buffer = UnsafePointer<UInt8>((work as NSData).bytes)
|
||||||
let length = work.length
|
let length = work.count
|
||||||
if !connected {
|
if !connected {
|
||||||
processTCPHandshake(buffer: buffer, bufferLen: length)
|
processTCPHandshake(buffer, bufferLen: length)
|
||||||
} else {
|
} else {
|
||||||
processRawMessagesInBuffer(pointer: buffer, bufferLen: length)
|
processRawMessagesInBuffer(buffer, bufferLen: length)
|
||||||
}
|
}
|
||||||
inputQueue = inputQueue.filter{$0 != data}
|
inputQueue = inputQueue.filter{$0 != data}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//handle checking the inital connection status
|
//handle checking the inital connection status
|
||||||
private func processTCPHandshake(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
|
private func processTCPHandshake(_ buffer: UnsafePointer<UInt8>, bufferLen: Int) {
|
||||||
let code = processHTTP(buffer: buffer, bufferLen: bufferLen)
|
let code = processHTTP(buffer, bufferLen: bufferLen)
|
||||||
switch code {
|
switch code {
|
||||||
case 0:
|
case 0:
|
||||||
connected = true
|
connected = true
|
||||||
guard canDispatch else {return}
|
guard canDispatch else {return}
|
||||||
dispatch_async(queue!) { [weak self] in
|
queue.async { [weak self] in
|
||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
s.onConnect?()
|
s.onConnect?()
|
||||||
s.delegate?.websocketDidConnect(socket: s)
|
s.delegate?.websocketDidConnect(s)
|
||||||
s.notificationCenter.post(name: WebsocketDidConnectNotification, object: self)
|
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidConnectNotification), object: self)
|
||||||
}
|
}
|
||||||
case -1:
|
case -1:
|
||||||
fragBuffer = NSData(bytes: buffer, length: bufferLen)
|
fragBuffer = Data(bytes: UnsafePointer<UInt8>(buffer), count: bufferLen)
|
||||||
break //do nothing, we are going to collect more data
|
break //do nothing, we are going to collect more data
|
||||||
default:
|
default:
|
||||||
doDisconnect(error: errorWithDetail(detail: "Invalid HTTP upgrade", code: UInt16(code)))
|
doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///Finds the HTTP Packet in the TCP stream, by looking for the CRLF.
|
///Finds the HTTP Packet in the TCP stream, by looking for the CRLF.
|
||||||
private func processHTTP(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Int {
|
private func processHTTP(_ buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Int {
|
||||||
let CRLFBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")]
|
let CRLFBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")]
|
||||||
var k = 0
|
var k = 0
|
||||||
var totalSize = 0
|
var totalSize = 0
|
||||||
@ -473,14 +473,14 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if totalSize > 0 {
|
if totalSize > 0 {
|
||||||
let code = validateResponse(buffer: buffer, bufferLen: totalSize)
|
let code = validateResponse(buffer, bufferLen: totalSize)
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
totalSize += 1 //skip the last \n
|
totalSize += 1 //skip the last \n
|
||||||
let restSize = bufferLen - totalSize
|
let restSize = bufferLen - totalSize
|
||||||
if restSize > 0 {
|
if restSize > 0 {
|
||||||
processRawMessagesInBuffer(pointer: buffer + totalSize, bufferLen: restSize)
|
processRawMessagesInBuffer(buffer + totalSize, bufferLen: restSize)
|
||||||
}
|
}
|
||||||
return 0 //success
|
return 0 //success
|
||||||
}
|
}
|
||||||
@ -488,7 +488,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///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) -> Int {
|
private func validateResponse(_ buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Int {
|
||||||
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
|
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
|
||||||
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
|
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
|
||||||
let code = CFHTTPMessageGetResponseStatusCode(response)
|
let code = CFHTTPMessageGetResponseStatusCode(response)
|
||||||
@ -507,12 +507,12 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///read a 16 bit big endian value from a buffer
|
///read a 16 bit big endian value from a buffer
|
||||||
private static func readUint16(buffer: UnsafePointer<UInt8>, offset: Int) -> UInt16 {
|
private static func readUint16(_ buffer: UnsafePointer<UInt8>, offset: Int) -> UInt16 {
|
||||||
return (UInt16(buffer[offset + 0]) << 8) | UInt16(buffer[offset + 1])
|
return (UInt16(buffer[offset + 0]) << 8) | UInt16(buffer[offset + 1])
|
||||||
}
|
}
|
||||||
|
|
||||||
///read a 64 bit big endian value from a buffer
|
///read a 64 bit big endian value from a buffer
|
||||||
private static func readUint64(buffer: UnsafePointer<UInt8>, offset: Int) -> UInt64 {
|
private static func readUint64(_ buffer: UnsafePointer<UInt8>, offset: Int) -> UInt64 {
|
||||||
var value = UInt64(0)
|
var value = UInt64(0)
|
||||||
for i in 0...7 {
|
for i in 0...7 {
|
||||||
value = (value << 8) | UInt64(buffer[offset + i])
|
value = (value << 8) | UInt64(buffer[offset + i])
|
||||||
@ -521,13 +521,13 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///write a 16 bit big endian value to a buffer
|
///write a 16 bit big endian value to a buffer
|
||||||
private static func writeUint16(buffer: UnsafeMutablePointer<UInt8>, offset: Int, value: UInt16) {
|
private static func writeUint16(_ buffer: UnsafeMutablePointer<UInt8>, offset: Int, value: UInt16) {
|
||||||
buffer[offset + 0] = UInt8(value >> 8)
|
buffer[offset + 0] = UInt8(value >> 8)
|
||||||
buffer[offset + 1] = UInt8(value & 0xff)
|
buffer[offset + 1] = UInt8(value & 0xff)
|
||||||
}
|
}
|
||||||
|
|
||||||
///write a 64 bit big endian value to a buffer
|
///write a 64 bit big endian value to a buffer
|
||||||
private static func writeUint64(buffer: UnsafeMutablePointer<UInt8>, offset: Int, value: UInt64) {
|
private static func writeUint64(_ buffer: UnsafeMutablePointer<UInt8>, offset: Int, value: UInt64) {
|
||||||
for i in 0...7 {
|
for i in 0...7 {
|
||||||
buffer[offset + i] = UInt8((value >> (8*UInt64(7 - i))) & 0xff)
|
buffer[offset + i] = UInt8((value >> (8*UInt64(7 - i))) & 0xff)
|
||||||
}
|
}
|
||||||
@ -540,7 +540,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
guard let baseAddress = buffer.baseAddress else { fatalError("") }
|
guard let baseAddress = buffer.baseAddress else { fatalError("") }
|
||||||
let bufferLen = buffer.count
|
let bufferLen = buffer.count
|
||||||
if response != nil && bufferLen < 2 {
|
if response != nil && bufferLen < 2 {
|
||||||
fragBuffer = NSData(buffer: buffer)
|
fragBuffer = Data(buffer: buffer)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
if let response = response where response.bytesLeft > 0 {
|
if let response = response where response.bytesLeft > 0 {
|
||||||
@ -551,43 +551,43 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
extra = 0
|
extra = 0
|
||||||
}
|
}
|
||||||
response.bytesLeft -= len
|
response.bytesLeft -= len
|
||||||
response.buffer?.append(NSData(bytes: baseAddress, length: len))
|
response.buffer?.append(Data(bytes: baseAddress, count: len))
|
||||||
processResponse(response: response)
|
processResponse(response)
|
||||||
return buffer.fromOffset(offset: bufferLen - extra)
|
return buffer.fromOffset(bufferLen - extra)
|
||||||
} else {
|
} else {
|
||||||
let isFin = (FinMask & baseAddress[0])
|
let isFin = (FinMask & baseAddress[0])
|
||||||
let receivedOpcode = OpCode(rawValue: (OpCodeMask & baseAddress[0]))
|
let receivedOpcode = OpCode(rawValue: (OpCodeMask & baseAddress[0]))
|
||||||
let isMasked = (MaskMask & baseAddress[1])
|
let isMasked = (MaskMask & baseAddress[1])
|
||||||
let payloadLen = (PayloadLenMask & baseAddress[1])
|
let payloadLen = (PayloadLenMask & baseAddress[1])
|
||||||
var offset = 2
|
var offset = 2
|
||||||
if (isMasked > 0 || (RSVMask & baseAddress[0]) > 0) && receivedOpcode != .Pong {
|
if (isMasked > 0 || (RSVMask & baseAddress[0]) > 0) && receivedOpcode != .pong {
|
||||||
let errCode = CloseCode.ProtocolError.rawValue
|
let errCode = CloseCode.protocolError.rawValue
|
||||||
doDisconnect(error: errorWithDetail(detail: "masked and rsv data is not currently supported", code: errCode))
|
doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode))
|
||||||
writeError(code: errCode)
|
writeError(errCode)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
let isControlFrame = (receivedOpcode == .ConnectionClose || receivedOpcode == .Ping)
|
let isControlFrame = (receivedOpcode == .connectionClose || receivedOpcode == .ping)
|
||||||
if !isControlFrame && (receivedOpcode != .BinaryFrame && receivedOpcode != .ContinueFrame &&
|
if !isControlFrame && (receivedOpcode != .binaryFrame && receivedOpcode != .continueFrame &&
|
||||||
receivedOpcode != .TextFrame && receivedOpcode != .Pong) {
|
receivedOpcode != .textFrame && receivedOpcode != .pong) {
|
||||||
let errCode = CloseCode.ProtocolError.rawValue
|
let errCode = CloseCode.protocolError.rawValue
|
||||||
doDisconnect(error: errorWithDetail(detail: "unknown opcode: \(receivedOpcode)", code: errCode))
|
doDisconnect(errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode))
|
||||||
writeError(code: errCode)
|
writeError(errCode)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
if isControlFrame && isFin == 0 {
|
if isControlFrame && isFin == 0 {
|
||||||
let errCode = CloseCode.ProtocolError.rawValue
|
let errCode = CloseCode.protocolError.rawValue
|
||||||
doDisconnect(error: errorWithDetail(detail: "control frames can't be fragmented", code: errCode))
|
doDisconnect(errorWithDetail("control frames can't be fragmented", code: errCode))
|
||||||
writeError(code: errCode)
|
writeError(errCode)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
if receivedOpcode == .ConnectionClose {
|
if receivedOpcode == .connectionClose {
|
||||||
var code = CloseCode.Normal.rawValue
|
var code = CloseCode.normal.rawValue
|
||||||
if payloadLen == 1 {
|
if payloadLen == 1 {
|
||||||
code = CloseCode.ProtocolError.rawValue
|
code = CloseCode.protocolError.rawValue
|
||||||
} else if payloadLen > 1 {
|
} else if payloadLen > 1 {
|
||||||
code = WebSocket.readUint16(buffer: baseAddress, offset: offset)
|
code = WebSocket.readUint16(baseAddress, offset: offset)
|
||||||
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
|
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
|
||||||
code = CloseCode.ProtocolError.rawValue
|
code = CloseCode.protocolError.rawValue
|
||||||
}
|
}
|
||||||
offset += 2
|
offset += 2
|
||||||
}
|
}
|
||||||
@ -595,70 +595,70 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
let len = Int(payloadLen-2)
|
let len = Int(payloadLen-2)
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
let bytes = baseAddress + offset
|
let bytes = baseAddress + offset
|
||||||
let str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding)
|
let str: NSString? = NSString(data: Data(bytes: bytes, count: len), encoding: String.Encoding.utf8.rawValue)
|
||||||
if str == nil {
|
if str == nil {
|
||||||
code = CloseCode.ProtocolError.rawValue
|
code = CloseCode.protocolError.rawValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
doDisconnect(error: errorWithDetail(detail: "connection closed by server", code: code))
|
doDisconnect(errorWithDetail("connection closed by server", code: code))
|
||||||
writeError(code: code)
|
writeError(code)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
if isControlFrame && payloadLen > 125 {
|
if isControlFrame && payloadLen > 125 {
|
||||||
writeError(code: CloseCode.ProtocolError.rawValue)
|
writeError(CloseCode.protocolError.rawValue)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
var dataLength = UInt64(payloadLen)
|
var dataLength = UInt64(payloadLen)
|
||||||
if dataLength == 127 {
|
if dataLength == 127 {
|
||||||
dataLength = WebSocket.readUint64(buffer: baseAddress, offset: offset)
|
dataLength = WebSocket.readUint64(baseAddress, offset: offset)
|
||||||
offset += sizeof(UInt64)
|
offset += sizeof(UInt64)
|
||||||
} else if dataLength == 126 {
|
} else if dataLength == 126 {
|
||||||
dataLength = UInt64(WebSocket.readUint16(buffer: baseAddress, offset: offset))
|
dataLength = UInt64(WebSocket.readUint16(baseAddress, offset: offset))
|
||||||
offset += sizeof(UInt16)
|
offset += sizeof(UInt16)
|
||||||
}
|
}
|
||||||
if bufferLen < offset || UInt64(bufferLen - offset) < dataLength {
|
if bufferLen < offset || UInt64(bufferLen - offset) < dataLength {
|
||||||
fragBuffer = NSData(bytes: baseAddress, length: bufferLen)
|
fragBuffer = Data(bytes: baseAddress, count: bufferLen)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
var len = dataLength
|
var len = dataLength
|
||||||
if dataLength > UInt64(bufferLen) {
|
if dataLength > UInt64(bufferLen) {
|
||||||
len = UInt64(bufferLen-offset)
|
len = UInt64(bufferLen-offset)
|
||||||
}
|
}
|
||||||
let data: NSData
|
let data: Data
|
||||||
if len < 0 {
|
if len < 0 {
|
||||||
len = 0
|
len = 0
|
||||||
data = NSData()
|
data = Data()
|
||||||
} else {
|
} else {
|
||||||
data = NSData(bytes: baseAddress+offset, length: Int(len))
|
data = Data(bytes: baseAddress+offset, count: Int(len))
|
||||||
}
|
}
|
||||||
if receivedOpcode == .Pong {
|
if receivedOpcode == .pong {
|
||||||
if canDispatch {
|
if canDispatch {
|
||||||
dispatch_async(queue!) { [weak self] in
|
queue.async { [weak self] in
|
||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
s.onPong?()
|
s.onPong?()
|
||||||
s.pongDelegate?.websocketDidReceivePong(socket: s)
|
s.pongDelegate?.websocketDidReceivePong(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buffer.fromOffset(offset: offset + Int(len))
|
return buffer.fromOffset(offset + Int(len))
|
||||||
}
|
}
|
||||||
var response = readStack.last
|
var response = readStack.last
|
||||||
if isControlFrame {
|
if isControlFrame {
|
||||||
response = nil //don't append pings
|
response = nil //don't append pings
|
||||||
}
|
}
|
||||||
if isFin == 0 && receivedOpcode == .ContinueFrame && response == nil {
|
if isFin == 0 && receivedOpcode == .continueFrame && response == nil {
|
||||||
let errCode = CloseCode.ProtocolError.rawValue
|
let errCode = CloseCode.protocolError.rawValue
|
||||||
doDisconnect(error: errorWithDetail(detail: "continue frame before a binary or text frame", code: errCode))
|
doDisconnect(errorWithDetail("continue frame before a binary or text frame", code: errCode))
|
||||||
writeError(code: errCode)
|
writeError(errCode)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
var isNew = false
|
var isNew = false
|
||||||
if response == nil {
|
if response == nil {
|
||||||
if receivedOpcode == .ContinueFrame {
|
if receivedOpcode == .continueFrame {
|
||||||
let errCode = CloseCode.ProtocolError.rawValue
|
let errCode = CloseCode.protocolError.rawValue
|
||||||
doDisconnect(error: errorWithDetail(detail: "first frame can't be a continue frame",
|
doDisconnect(errorWithDetail("first frame can't be a continue frame",
|
||||||
code: errCode))
|
code: errCode))
|
||||||
writeError(code: errCode)
|
writeError(errCode)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
isNew = true
|
isNew = true
|
||||||
@ -667,13 +667,13 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
response!.bytesLeft = Int(dataLength)
|
response!.bytesLeft = Int(dataLength)
|
||||||
response!.buffer = NSMutableData(data: data)
|
response!.buffer = NSMutableData(data: data)
|
||||||
} else {
|
} else {
|
||||||
if receivedOpcode == .ContinueFrame {
|
if receivedOpcode == .continueFrame {
|
||||||
response!.bytesLeft = Int(dataLength)
|
response!.bytesLeft = Int(dataLength)
|
||||||
} else {
|
} else {
|
||||||
let errCode = CloseCode.ProtocolError.rawValue
|
let errCode = CloseCode.protocolError.rawValue
|
||||||
doDisconnect(error: errorWithDetail(detail: "second and beyond of fragment message must be a continue frame",
|
doDisconnect(errorWithDetail("second and beyond of fragment message must be a continue frame",
|
||||||
code: errCode))
|
code: errCode))
|
||||||
writeError(code: errCode)
|
writeError(errCode)
|
||||||
return emptyBuffer
|
return emptyBuffer
|
||||||
}
|
}
|
||||||
response!.buffer!.append(data)
|
response!.buffer!.append(data)
|
||||||
@ -685,51 +685,52 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
if isNew {
|
if isNew {
|
||||||
readStack.append(response)
|
readStack.append(response)
|
||||||
}
|
}
|
||||||
processResponse(response: response)
|
processResponse(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
let step = Int(offset+numericCast(len))
|
let step = Int(offset+numericCast(len))
|
||||||
return buffer.fromOffset(offset: step)
|
return buffer.fromOffset(step)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process all messages in the buffer if possible.
|
/// Process all messages in the buffer if possible.
|
||||||
private func processRawMessagesInBuffer(pointer: UnsafePointer<UInt8>, bufferLen: Int) {
|
private func processRawMessagesInBuffer(_ pointer: UnsafePointer<UInt8>, bufferLen: Int) {
|
||||||
var buffer = UnsafeBufferPointer(start: pointer, count: bufferLen)
|
var buffer = UnsafeBufferPointer(start: pointer, count: bufferLen)
|
||||||
repeat {
|
repeat {
|
||||||
buffer = processOneRawMessage(inBuffer: buffer)
|
buffer = processOneRawMessage(inBuffer: buffer)
|
||||||
} while buffer.count >= 2
|
} while buffer.count >= 2
|
||||||
if buffer.count > 0 {
|
if buffer.count > 0 {
|
||||||
fragBuffer = NSData(buffer: buffer)
|
fragBuffer = Data(buffer: buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///process the finished response of a buffer
|
///process the finished response of a buffer
|
||||||
private func processResponse(response: WSResponse) -> Bool {
|
@discardableResult
|
||||||
|
private func processResponse(_ response: WSResponse) -> Bool {
|
||||||
if response.isFin && response.bytesLeft <= 0 {
|
if response.isFin && response.bytesLeft <= 0 {
|
||||||
if response.code == .Ping {
|
if response.code == .ping {
|
||||||
let data = response.buffer! //local copy so it is perverse for writing
|
let data = response.buffer! //local copy so it is perverse for writing
|
||||||
dequeueWrite(data: data, code: OpCode.Pong)
|
dequeueWrite(data as Data, code: .pong)
|
||||||
} else if response.code == .TextFrame {
|
} else if response.code == .textFrame {
|
||||||
let str: NSString? = NSString(data: response.buffer!, encoding: NSUTF8StringEncoding)
|
let str: NSString? = NSString(data: response.buffer! as Data, encoding: String.Encoding.utf8.rawValue)
|
||||||
if str == nil {
|
if str == nil {
|
||||||
writeError(code: CloseCode.Encoding.rawValue)
|
writeError(CloseCode.encoding.rawValue)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if canDispatch {
|
if canDispatch {
|
||||||
dispatch_async(queue!) { [weak self] in
|
queue.async { [weak self] in
|
||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
s.onText?(str! as String)
|
s.onText?(str! as String)
|
||||||
s.delegate?.websocketDidReceiveMessage(socket: s, text: str! as String)
|
s.delegate?.websocketDidReceiveMessage(s, text: str! as String)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if response.code == .BinaryFrame {
|
} else if response.code == .binaryFrame {
|
||||||
if canDispatch {
|
if canDispatch {
|
||||||
let data = response.buffer! //local copy so it is perverse for writing
|
let data = response.buffer! //local copy so it is perverse for writing
|
||||||
dispatch_async(queue!) { [weak self] in
|
queue.async { [weak self] in
|
||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
s.onData?(data)
|
s.onData?(data as Data)
|
||||||
s.delegate?.websocketDidReceiveData(socket: s, data: data)
|
s.delegate?.websocketDidReceiveData(s, data: data as Data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -740,7 +741,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///Create an error
|
///Create an error
|
||||||
private func errorWithDetail(detail: String, code: UInt16) -> NSError {
|
private func errorWithDetail(_ detail: String, code: UInt16) -> NSError {
|
||||||
var details = [String: String]()
|
var details = [String: String]()
|
||||||
details[NSLocalizedDescriptionKey] = detail
|
details[NSLocalizedDescriptionKey] = detail
|
||||||
|
|
||||||
@ -752,20 +753,20 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///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))
|
||||||
let buffer = UnsafeMutablePointer<UInt8>(buf!.bytes)
|
let buffer = UnsafeMutablePointer<UInt8>(buf!.bytes)
|
||||||
WebSocket.writeUint16(buffer: buffer, offset: 0, value: code)
|
WebSocket.writeUint16(buffer, offset: 0, value: code)
|
||||||
dequeueWrite(data: NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose)
|
dequeueWrite(Data(bytes: buffer, count: sizeof(UInt16)), code: .connectionClose)
|
||||||
}
|
}
|
||||||
///used to write things to the stream
|
///used to write things to the stream
|
||||||
private func dequeueWrite(data: NSData, code: OpCode, writeCompletion: (() -> ())? = nil) {
|
private func dequeueWrite(_ data: Data, code: OpCode, writeCompletion: (() -> ())? = nil) {
|
||||||
writeQueue.addOperation { [weak self] in
|
writeQueue.addOperation { [weak self] in
|
||||||
//stream isn't ready, let's wait
|
//stream isn't ready, let's wait
|
||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
var offset = 2
|
var offset = 2
|
||||||
let bytes = UnsafeMutablePointer<UInt8>(data.bytes)
|
let bytes = UnsafeMutablePointer<UInt8>((data as NSData).bytes)
|
||||||
let dataLength = data.length
|
let dataLength = data.count
|
||||||
let frame = NSMutableData(capacity: dataLength + s.MaxFrameSize)
|
let frame = NSMutableData(capacity: dataLength + s.MaxFrameSize)
|
||||||
let buffer = UnsafeMutablePointer<UInt8>(frame!.mutableBytes)
|
let buffer = UnsafeMutablePointer<UInt8>(frame!.mutableBytes)
|
||||||
buffer[0] = s.FinMask | code.rawValue
|
buffer[0] = s.FinMask | code.rawValue
|
||||||
@ -773,11 +774,11 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
buffer[1] = CUnsignedChar(dataLength)
|
buffer[1] = CUnsignedChar(dataLength)
|
||||||
} else if dataLength <= Int(UInt16.max) {
|
} else if dataLength <= Int(UInt16.max) {
|
||||||
buffer[1] = 126
|
buffer[1] = 126
|
||||||
WebSocket.writeUint16(buffer: buffer, offset: offset, value: UInt16(dataLength))
|
WebSocket.writeUint16(buffer, offset: offset, value: UInt16(dataLength))
|
||||||
offset += sizeof(UInt16)
|
offset += sizeof(UInt16)
|
||||||
} else {
|
} else {
|
||||||
buffer[1] = 127
|
buffer[1] = 127
|
||||||
WebSocket.writeUint64(buffer: buffer, offset: offset, value: UInt64(dataLength))
|
WebSocket.writeUint64(buffer, offset: offset, value: UInt64(dataLength))
|
||||||
offset += sizeof(UInt64)
|
offset += sizeof(UInt64)
|
||||||
}
|
}
|
||||||
buffer[1] |= s.MaskMask
|
buffer[1] |= s.MaskMask
|
||||||
@ -799,17 +800,17 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
if let streamError = outStream.streamError {
|
if let streamError = outStream.streamError {
|
||||||
error = streamError
|
error = streamError
|
||||||
} else {
|
} else {
|
||||||
let errCode = InternalErrorCode.OutputStreamWriteError.rawValue
|
let errCode = InternalErrorCode.outputStreamWriteError.rawValue
|
||||||
error = s.errorWithDetail(detail: "output stream error during write", code: errCode)
|
error = s.errorWithDetail("output stream error during write", code: errCode)
|
||||||
}
|
}
|
||||||
s.doDisconnect(error: error)
|
s.doDisconnect(error)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
total += len
|
total += len
|
||||||
}
|
}
|
||||||
if total >= offset {
|
if total >= offset {
|
||||||
if let queue = self?.queue, callback = writeCompletion {
|
if let queue = self?.queue, callback = writeCompletion {
|
||||||
dispatch_async(queue) {
|
queue.asynchronously() {
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -822,17 +823,17 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///used to preform the disconnect delegate
|
///used to preform the disconnect delegate
|
||||||
private func doDisconnect(error: NSError?) {
|
private func doDisconnect(_ error: NSError?) {
|
||||||
guard !didDisconnect else { return }
|
guard !didDisconnect else { return }
|
||||||
didDisconnect = true
|
didDisconnect = true
|
||||||
connected = false
|
connected = false
|
||||||
guard canDispatch else {return}
|
guard canDispatch else {return}
|
||||||
dispatch_async(queue!) { [weak self] in
|
queue.async { [weak self] in
|
||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
s.onDisconnect?(error)
|
s.onDisconnect?(error)
|
||||||
s.delegate?.websocketDidDisconnect(socket: s, error: error)
|
s.delegate?.websocketDidDisconnect(s, error: error)
|
||||||
let userInfo = error.map({ [WebsocketDisconnectionErrorKeyName: $0] })
|
let userInfo = error.map({ [WebsocketDisconnectionErrorKeyName: $0] })
|
||||||
s.notificationCenter.post(name: WebsocketDidDisconnectNotification, object: self, userInfo: userInfo)
|
s.notificationCenter.post(name: NSNotification.Name(rawValue: WebsocketDidDisconnectNotification), object: self, userInfo: userInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -855,7 +856,7 @@ private extension NSData {
|
|||||||
|
|
||||||
private extension UnsafeBufferPointer {
|
private extension UnsafeBufferPointer {
|
||||||
|
|
||||||
func fromOffset(offset: Int) -> UnsafeBufferPointer<Element> {
|
func fromOffset(_ offset: Int) -> UnsafeBufferPointer<Element> {
|
||||||
return UnsafeBufferPointer<Element>(start: baseAddress!.advanced(by: offset), count: count - offset)
|
return UnsafeBufferPointer<Element>(start: baseAddress!.advanced(by: offset), count: count - offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user