Merge branch 'development'

* development:
  Fix #882. Don't automatically remove sockets from nsps since they might be used again
  bump version
  Enable bitcode in debug
  Enable bitcode for select sdks
  simplify ranges
  update changelog
  Just use one boolean to determine polling/ws
  use addHeaders
  update changelog
  Implement #684
  Fix some documentation marks
This commit is contained in:
Erik Little 2017-11-30 06:38:56 -05:00
commit 313032aa41
No known key found for this signature in database
GPG Key ID: 62F837E56F4E9320
20 changed files with 148 additions and 65 deletions

View File

@ -1,3 +1,12 @@
# v13.1.0
- Allow setting `SocketEngineSpec.extraHeaders` after init.
- Deprecate `SocketEngineSpec.websocket` in favor of just using the `SocketEngineSpec.polling` property.
- Enable bitcode for most platforms.
- Fix [#882](https://github.com/socketio/socket.io-client-swift/issues/882). This adds a new method
`SocketManger.removeSocket(_:)` that should be called if when you no longer wish to use a socket again.
This will cause the engine to no longer keep a strong reference to the socket and no longer track it.
# v13.0.1 # v13.0.1
- Fix not setting handleQueue on `SocketManager` - Fix not setting handleQueue on `SocketManager`

View File

@ -86,7 +86,7 @@ let package = Package(
.executable(name: "socket.io-test", targets: ["YourTargetName"]) .executable(name: "socket.io-test", targets: ["YourTargetName"])
], ],
dependencies: [ dependencies: [
.package(url: "https://github.com/socketio/socket.io-client-swift", .upToNextMinor(from: "13.0.0")) .package(url: "https://github.com/socketio/socket.io-client-swift", .upToNextMinor(from: "13.1.0"))
], ],
targets: [ targets: [
.target(name: "YourTargetName", dependencies: ["SocketIO"], path: "./Path/To/Your/Sources") .target(name: "YourTargetName", dependencies: ["SocketIO"], path: "./Path/To/Your/Sources")
@ -99,7 +99,7 @@ Then import `import SocketIO`.
### Carthage ### Carthage
Add this line to your `Cartfile`: Add this line to your `Cartfile`:
``` ```
github "socketio/socket.io-client-swift" ~> 13.0.0 github "socketio/socket.io-client-swift" ~> 13.1.0
``` ```
Run `carthage update --platform ios,macosx`. Run `carthage update --platform ios,macosx`.
@ -113,7 +113,7 @@ Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`:
use_frameworks! use_frameworks!
target 'YourApp' do target 'YourApp' do
pod 'Socket.IO-Client-Swift', '~> 13.0.0' pod 'Socket.IO-Client-Swift', '~> 13.1.0'
end end
``` ```

View File

@ -1,7 +1,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = "Socket.IO-Client-Swift" s.name = "Socket.IO-Client-Swift"
s.module_name = "SocketIO" s.module_name = "SocketIO"
s.version = "13.0.1" s.version = "13.1.0"
s.summary = "Socket.IO-client for iOS and OS X" s.summary = "Socket.IO-client for iOS and OS X"
s.description = <<-DESC s.description = <<-DESC
Socket.IO-client for iOS and OS X. Socket.IO-client for iOS and OS X.
@ -18,7 +18,7 @@ Pod::Spec.new do |s|
s.requires_arc = true s.requires_arc = true
s.source = { s.source = {
:git => "https://github.com/socketio/socket.io-client-swift.git", :git => "https://github.com/socketio/socket.io-client-swift.git",
:tag => 'v13.0.1', :tag => 'v13.1.0',
:submodules => true :submodules => true
} }
s.pod_target_xcconfig = { s.pod_target_xcconfig = {

View File

@ -532,6 +532,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Developer ID Application"; CODE_SIGN_IDENTITY = "Developer ID Application";
ENABLE_BITCODE = YES; ENABLE_BITCODE = YES;
"ENABLE_BITCODE[sdk=macosx*]" = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
"FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = ( "FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = (
@ -604,6 +605,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Developer ID Application"; CODE_SIGN_IDENTITY = "Developer ID Application";
ENABLE_BITCODE = YES; ENABLE_BITCODE = YES;
"ENABLE_BITCODE[sdk=macosx*]" = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
"FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = ( "FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = (
"$(inherited)", "$(inherited)",
@ -678,7 +680,8 @@
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath"; DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_BITCODE = NO; ENABLE_BITCODE = YES;
"ENABLE_BITCODE[sdk=macosx*]" = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = "$(inherited)"; FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@ -747,7 +750,8 @@
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath"; DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_BITCODE = NO; ENABLE_BITCODE = YES;
"ENABLE_BITCODE[sdk=macosx*]" = NO;
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;

View File

@ -27,6 +27,8 @@ import Foundation
/// The status of an ack. /// The status of an ack.
public enum SocketAckStatus : String { public enum SocketAckStatus : String {
// MARK: Cases
/// The ack timed out. /// The ack timed out.
case noAck = "NO ACK" case noAck = "NO ACK"
} }

View File

@ -127,7 +127,14 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
status = .connecting status = .connecting
manager.connectSocket(self) joinNamespace()
if manager.status == .connected && nsp == "/" {
// We might not get a connect event for the default nsp, fire immediately
didConnect(toNamespace: nsp)
return
}
guard timeoutAfter != 0 else { return } guard timeoutAfter != 0 else { return }
@ -183,7 +190,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
DefaultSocketLogger.Logger.log("Closing socket", type: logType) DefaultSocketLogger.Logger.log("Closing socket", type: logType)
leaveNamespace() leaveNamespace()
didDisconnect(reason: "Disconnect")
} }
/// Send an event to the server, with optional data items. /// Send an event to the server, with optional data items.
@ -366,21 +372,15 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
/// Call when you wish to leave a namespace and disconnect this socket. /// Call when you wish to leave a namespace and disconnect this socket.
@objc @objc
open func leaveNamespace() { open func leaveNamespace() {
guard nsp != "/" else { return }
status = .disconnected
manager?.disconnectSocket(self) manager?.disconnectSocket(self)
} }
/// Joins `nsp`. /// Joins `nsp`.
@objc @objc
open func joinNamespace() { open func joinNamespace() {
guard nsp != "/" else { return }
DefaultSocketLogger.Logger.log("Joining namespace \(nsp)", type: logType) DefaultSocketLogger.Logger.log("Joining namespace \(nsp)", type: logType)
manager?.engine?.send("0\(nsp)", withData: []) manager?.connectSocket(self)
} }
/// Removes handler(s) for a client event. /// Removes handler(s) for a client event.

View File

@ -129,6 +129,8 @@ public struct SocketIOClientConfiguration : ExpressibleByArrayLiteral, Collectio
/// Declares that a type can set configs from a `SocketIOClientConfiguration`. /// Declares that a type can set configs from a `SocketIOClientConfiguration`.
public protocol ConfigSettable { public protocol ConfigSettable {
// MARK: Methods
/// Called when an `ConfigSettable` should set/update its configs from a given configuration. /// Called when an `ConfigSettable` should set/update its configs from a given configuration.
/// ///
/// - parameter config: The `SocketIOClientConfiguration` that should be used to set/update configs. /// - parameter config: The `SocketIOClientConfiguration` that should be used to set/update configs.

View File

@ -44,6 +44,9 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
} }
} }
/// A dictionary of extra http headers that will be set during connection.
public var extraHeaders: [String: String]?
/// A queue of engine.io messages waiting for POSTing /// A queue of engine.io messages waiting for POSTing
/// ///
/// **You should not touch this directly** /// **You should not touch this directly**
@ -73,9 +76,6 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
/// An array of HTTPCookies that are sent during the connection. /// An array of HTTPCookies that are sent during the connection.
public private(set) var cookies: [HTTPCookie]? public private(set) var cookies: [HTTPCookie]?
/// A dictionary of extra http headers that will be set during connection.
public private(set) var extraHeaders: [String: String]?
/// When `true`, the engine is in the process of switching to WebSockets. /// When `true`, the engine is in the process of switching to WebSockets.
/// ///
/// **Do not touch this directly** /// **Do not touch this directly**
@ -112,6 +112,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
public private(set) var urlWebSocket = URL(string: "http://localhost/")! public private(set) var urlWebSocket = URL(string: "http://localhost/")!
/// If `true`, then the engine is currently in WebSockets mode. /// If `true`, then the engine is currently in WebSockets mode.
@available(*, deprecated, message: "No longer needed, if we're not polling, then we must be doing websockets")
public private(set) var websocket = false public private(set) var websocket = false
/// The WebSocket for this engine. /// The WebSocket for this engine.
@ -233,7 +234,6 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
if forceWebsockets { if forceWebsockets {
polling = false polling = false
websocket = true
createWebSocketAndConnect() createWebSocketAndConnect()
return return
} }
@ -283,18 +283,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
ws?.delegate = nil // TODO this seems a bit defensive, is this really needed? ws?.delegate = nil // TODO this seems a bit defensive, is this really needed?
var req = URLRequest(url: urlWebSocketWithSid) var req = URLRequest(url: urlWebSocketWithSid)
if cookies != nil { addHeaders(to: &req)
let headers = HTTPCookie.requestHeaderFields(with: cookies!)
for (headerName, value) in headers {
req.setValue(value, forHTTPHeaderField: headerName)
}
}
if extraHeaders != nil {
for (headerName, value) in extraHeaders! {
req.setValue(value, forHTTPHeaderField: headerName)
}
}
ws = WebSocket(request: req) ws = WebSocket(request: req)
ws?.callbackQueue = engineQueue ws?.callbackQueue = engineQueue
@ -323,19 +312,15 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
} }
private func _disconnect(reason: String) { private func _disconnect(reason: String) {
guard connected else { return closeOutEngine(reason: reason) } guard connected && !closed else { return closeOutEngine(reason: reason) }
DefaultSocketLogger.Logger.log("Engine is being closed.", type: SocketEngine.logType) DefaultSocketLogger.Logger.log("Engine is being closed.", type: SocketEngine.logType)
if closed { if polling {
return closeOutEngine(reason: reason) disconnectPolling(reason: reason)
} } else {
if websocket {
sendWebSocketMessage("", withType: .close, withData: []) sendWebSocketMessage("", withType: .close, withData: [])
closeOutEngine(reason: reason) closeOutEngine(reason: reason)
} else {
disconnectPolling(reason: reason)
} }
} }
@ -358,8 +343,9 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
"we'll probably disconnect soon. You should report this.", type: SocketEngine.logType) "we'll probably disconnect soon. You should report this.", type: SocketEngine.logType)
} }
DefaultSocketLogger.Logger.log("Switching to WebSockets", type: SocketEngine.logType)
sendWebSocketMessage("", withType: .upgrade, withData: []) sendWebSocketMessage("", withType: .upgrade, withData: [])
websocket = true
polling = false polling = false
fastUpgrade = false fastUpgrade = false
probing = false probing = false
@ -454,6 +440,9 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
// We should upgrade // We should upgrade
if message == "3probe" { if message == "3probe" {
DefaultSocketLogger.Logger.log("Received probe response, should upgrade to WebSockets",
type: SocketEngine.logType)
upgradeTransport() upgradeTransport()
} }
@ -520,7 +509,6 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
sid = "" sid = ""
waitingForPoll = false waitingForPoll = false
waitingForPost = false waitingForPost = false
websocket = false
} }
private func sendPing() { private func sendPing() {
@ -603,17 +591,20 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
public func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data]) { public func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data]) {
engineQueue.async { engineQueue.async {
guard self.connected else { return } guard self.connected else { return }
guard !self.probing else {
self.probeWait.append((msg, type, data))
if self.websocket { return
DefaultSocketLogger.Logger.log("Writing ws: \(msg) has data: \(data.count != 0)", }
type: SocketEngine.logType)
self.sendWebSocketMessage(msg, withType: type, withData: data) if self.polling {
} else if !self.probing {
DefaultSocketLogger.Logger.log("Writing poll: \(msg) has data: \(data.count != 0)", DefaultSocketLogger.Logger.log("Writing poll: \(msg) has data: \(data.count != 0)",
type: SocketEngine.logType) type: SocketEngine.logType)
self.sendPollMessage(msg, withType: type, withData: data) self.sendPollMessage(msg, withType: type, withData: data)
} else { } else {
self.probeWait.append((msg, type, data)) DefaultSocketLogger.Logger.log("Writing ws: \(msg) has data: \(data.count != 0)",
type: SocketEngine.logType)
self.sendWebSocketMessage(msg, withType: type, withData: data)
} }
} }
} }
@ -642,14 +633,14 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
return return
} }
guard websocket else { guard !polling else {
flushProbeWait() flushProbeWait()
return return
} }
connected = false connected = false
websocket = false polling = true
if let reason = error?.localizedDescription { if let reason = error?.localizedDescription {
didError(reason: reason) didError(reason: reason)

View File

@ -26,7 +26,7 @@ import Foundation
/// Protocol that is used to implement socket.io polling support /// Protocol that is used to implement socket.io polling support
public protocol SocketEnginePollable : SocketEngineSpec { public protocol SocketEnginePollable : SocketEngineSpec {
/// MARK: Properties // MARK: Properties
/// `true` If engine's session has been invalidated. /// `true` If engine's session has been invalidated.
var invalidated: Bool { get } var invalidated: Bool { get }
@ -51,6 +51,8 @@ public protocol SocketEnginePollable : SocketEngineSpec {
/// **Do not touch this directly** /// **Do not touch this directly**
var waitingForPost: Bool { get set } var waitingForPost: Bool { get set }
// MARK: Methods
/// Call to send a long-polling request. /// Call to send a long-polling request.
/// ///
/// You shouldn't need to call this directly, the engine should automatically maintain a long-poll request. /// You shouldn't need to call this directly, the engine should automatically maintain a long-poll request.
@ -99,7 +101,7 @@ extension SocketEnginePollable {
/// ///
/// You shouldn't need to call this directly, the engine should automatically maintain a long-poll request. /// You shouldn't need to call this directly, the engine should automatically maintain a long-poll request.
public func doPoll() { public func doPoll() {
guard !websocket && !waitingForPoll && connected && !closed else { return } guard polling && !waitingForPoll && connected && !closed else { return }
var req = URLRequest(url: urlPollingWithSid) var req = URLRequest(url: urlPollingWithSid)
addHeaders(to: &req) addHeaders(to: &req)
@ -149,7 +151,7 @@ extension SocketEnginePollable {
private func flushWaitingForPost() { private func flushWaitingForPost() {
guard postWait.count != 0 && connected else { return } guard postWait.count != 0 && connected else { return }
guard !websocket else { guard polling else {
flushWaitingForPostToWebSocket() flushWaitingForPostToWebSocket()
return return

View File

@ -28,6 +28,8 @@ import Starscream
/// Specifies a SocketEngine. /// Specifies a SocketEngine.
@objc public protocol SocketEngineSpec { @objc public protocol SocketEngineSpec {
// MARK: Properties
/// The client for this engine. /// The client for this engine.
var client: SocketEngineClient? { get set } var client: SocketEngineClient? { get set }
@ -50,7 +52,7 @@ import Starscream
var engineQueue: DispatchQueue { get } var engineQueue: DispatchQueue { get }
/// A dictionary of extra http headers that will be set during connection. /// A dictionary of extra http headers that will be set during connection.
var extraHeaders: [String: String]? { get } var extraHeaders: [String: String]? { get set }
/// When `true`, the engine is in the process of switching to WebSockets. /// When `true`, the engine is in the process of switching to WebSockets.
var fastUpgrade: Bool { get } var fastUpgrade: Bool { get }
@ -80,11 +82,14 @@ import Starscream
var urlWebSocket: URL { get } var urlWebSocket: URL { get }
/// If `true`, then the engine is currently in WebSockets mode. /// If `true`, then the engine is currently in WebSockets mode.
@available(*, deprecated, message: "No longer needed, if we're not polling, then we must be doing websockets")
var websocket: Bool { get } var websocket: Bool { get }
/// The WebSocket for this engine. /// The WebSocket for this engine.
var ws: WebSocket? { get } var ws: WebSocket? { get }
// MARK: Initializers
/// Creates a new engine. /// Creates a new engine.
/// ///
/// - parameter client: The client for this engine. /// - parameter client: The client for this engine.
@ -92,6 +97,8 @@ import Starscream
/// - parameter options: The options for this engine. /// - parameter options: The options for this engine.
init(client: SocketEngineClient, url: URL, options: [String: Any]?) init(client: SocketEngineClient, url: URL, options: [String: Any]?)
// MARK: Methods
/// Starts the connection to the server. /// Starts the connection to the server.
func connect() func connect()
@ -163,10 +170,10 @@ extension SocketEngineSpec {
} }
func createBinaryDataForSend(using data: Data) -> Either<Data, String> { func createBinaryDataForSend(using data: Data) -> Either<Data, String> {
if websocket { if polling {
return .left(Data(bytes: [0x4]) + data)
} else {
return .right("b4" + data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0))) return .right("b4" + data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)))
} else {
return .left(Data(bytes: [0x4]) + data)
} }
} }

View File

@ -28,6 +28,8 @@ import Starscream
/// 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 {
// MARK: Methods
/// Sends an engine.io message through the WebSocket transport. /// Sends an engine.io message through the WebSocket transport.
/// ///
/// You shouldn't call this directly, instead call the `write` method on `SocketEngine`. /// You shouldn't call this directly, instead call the `write` method on `SocketEngine`.

View File

@ -233,9 +233,6 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
/// ///
/// - parameter socket: The socket to disconnect. /// - parameter socket: The socket to disconnect.
open func disconnectSocket(_ socket: SocketIOClient) { open func disconnectSocket(_ socket: SocketIOClient) {
// Make sure we remove socket from nsps
nsps.removeValue(forKey: socket.nsp)
engine?.send("1\(socket.nsp)", withData: []) engine?.send("1\(socket.nsp)", withData: [])
socket.didDisconnect(reason: "Namespace leave") socket.didDisconnect(reason: "Namespace leave")
} }
@ -424,6 +421,18 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
engine?.disconnect(reason: "manual reconnect") engine?.disconnect(reason: "manual reconnect")
} }
/// Removes the socket from the manager's control. One of the disconnect methods should be called before calling this
/// method.
///
/// After calling this method the socket should no longer be considered usable.
///
/// - parameter socket: The socket to remove.
/// - returns: The socket removed, if it was owned by the manager.
@discardableResult
open func removeSocket(_ socket: SocketIOClient) -> SocketIOClient? {
return nsps.removeValue(forKey: socket.nsp)
}
private func tryReconnect(reason: String) { private func tryReconnect(reason: String) {
guard reconnecting else { return } guard reconnecting else { return }

View File

@ -63,6 +63,9 @@ public protocol SocketManagerSpec : class, SocketEngineClient {
/// called on. /// called on.
var handleQueue: DispatchQueue { get set } var handleQueue: DispatchQueue { get set }
/// The sockets in this manager indexed by namespace.
var nsps: [String: SocketIOClient] { get set }
/// If `true`, this manager will try and reconnect on any disconnects. /// If `true`, this manager will try and reconnect on any disconnects.
var reconnects: Bool { get set } var reconnects: Bool { get set }
@ -114,6 +117,14 @@ public protocol SocketManagerSpec : class, SocketEngineClient {
/// This will cause a `disconnect` event to be emitted, as well as an `reconnectAttempt` event. /// This will cause a `disconnect` event to be emitted, as well as an `reconnectAttempt` event.
func reconnect() func reconnect()
/// Removes the socket from the manager's control.
/// After calling this method the socket should no longer be considered usable.
///
/// - parameter socket: The socket to remove.
/// - returns: The socket removed, if it was owned by the manager.
@discardableResult
func removeSocket(_ socket: SocketIOClient) -> SocketIOClient?
/// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager. /// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager.
/// ///
/// Calling multiple times returns the same socket. /// Calling multiple times returns the same socket.

View File

@ -24,8 +24,6 @@ import Foundation
/// Defines that a type will be able to parse socket.io-protocol messages. /// Defines that a type will be able to parse socket.io-protocol messages.
public protocol SocketParsable : class { public protocol SocketParsable : class {
// MARK: Properties
// MARK: Methods // MARK: Methods
/// Called when the engine has received some binary data that should be attached to a packet. /// Called when the engine has received some binary data that should be attached to a packet.
@ -60,6 +58,8 @@ public enum SocketParsableError : Error {
/// Says that a type will be able to buffer binary data before all data for an event has come in. /// Says that a type will be able to buffer binary data before all data for an event has come in.
public protocol SocketDataBufferable : class { public protocol SocketDataBufferable : class {
// MARK: Properties
/// A list of packets that are waiting for binary data. /// A list of packets that are waiting for binary data.
/// ///
/// The way that socket.io works all data should be sent directly after each packet. /// The way that socket.io works all data should be sent directly after each packet.
@ -119,7 +119,7 @@ public extension SocketParsable where Self: SocketManagerSpec & SocketDataBuffer
} }
} }
var dataArray = String(message.utf16[message.utf16.index(reader.currentIndex, offsetBy: 1)..<message.utf16.endIndex])! var dataArray = String(message.utf16[message.utf16.index(reader.currentIndex, offsetBy: 1)...])!
if type == .error && !dataArray.hasPrefix("[") && !dataArray.hasSuffix("]") { if type == .error && !dataArray.hasPrefix("[") && !dataArray.hasSuffix("]") {
dataArray = "[" + dataArray + "]" dataArray = "[" + dataArray + "]"

View File

@ -27,6 +27,8 @@ import Starscream
/// A wrapper around Starscream's SSLSecurity that provides a minimal Objective-C interface. /// A wrapper around Starscream's SSLSecurity that provides a minimal Objective-C interface.
open class SSLSecurity : NSObject { open class SSLSecurity : NSObject {
// MARK: Properties
/// The internal Starscream SSLSecurity. /// The internal Starscream SSLSecurity.
public let security: Starscream.SSLSecurity public let security: Starscream.SSLSecurity
@ -34,6 +36,8 @@ open class SSLSecurity : NSObject {
self.security = security self.security = security
} }
// MARK: Methods
/// Creates a new SSLSecurity that specifies whether to use publicKeys or certificates should be used for SSL /// Creates a new SSLSecurity that specifies whether to use publicKeys or certificates should be used for SSL
/// pinning validation /// pinning validation
/// ///

View File

@ -54,7 +54,7 @@ struct SocketStringReader {
} }
mutating func readUntilOccurence(of string: String) -> String { mutating func readUntilOccurence(of string: String) -> String {
let substring = message.utf16[currentIndex..<message.utf16.endIndex] let substring = message.utf16[currentIndex...]
guard let foundIndex = substring.index(of: string.utf16.first!) else { guard let foundIndex = substring.index(of: string.utf16.first!) else {
currentIndex = message.utf16.endIndex currentIndex = message.utf16.endIndex

View File

@ -192,6 +192,14 @@ class SocketEngineTest: XCTestCase {
XCTAssertTrue(manager.engine!.forceWebsockets) XCTAssertTrue(manager.engine!.forceWebsockets)
} }
func testChangingEngineHeadersAfterInit() {
engine.extraHeaders = ["Hello": "World"]
let req = engine.createRequestForPostWithPostWait()
XCTAssertEqual("World", req.allHTTPHeaderFields?["Hello"])
}
var manager: SocketManager! var manager: SocketManager!
var socket: SocketIOClient! var socket: SocketIOClient!
var engine: SocketEngine! var engine: SocketEngine!

View File

@ -88,6 +88,14 @@ class SocketMangerTest : XCTestCase {
XCTAssertEqual(manager.reconnectWait, 5) XCTAssertEqual(manager.reconnectWait, 5)
} }
func testManagerRemovesSocket() {
setUpSockets()
manager.removeSocket(socket)
XCTAssertNil(manager.nsps[socket.nsp])
}
private func setUpSockets() { private func setUpSockets() {
socket = manager.testSocket(forNamespace: "/") socket = manager.testSocket(forNamespace: "/")
socket2 = manager.testSocket(forNamespace: "/swift") socket2 = manager.testSocket(forNamespace: "/swift")

View File

@ -250,6 +250,22 @@ class SocketSideEffectTest: XCTestCase {
waitForExpectations(timeout: 0.8) waitForExpectations(timeout: 0.8)
} }
func testConnectCallsConnectEventImmediatelyIfManagerAlreadyConnected() {
let expect = expectation(description: "The client should call the connect handler")
socket = manager.defaultSocket
socket.setTestStatus(.notConnected)
manager.setTestStatus(.connected)
socket.on(clientEvent: .connect) {data, ack in
expect.fulfill()
}
socket.connect(timeoutAfter: 0.3, withHandler: nil)
waitForExpectations(timeout: 0.8)
}
func testConnectDoesNotTimeOutIfConnected() { func testConnectDoesNotTimeOutIfConnected() {
let expect = expectation(description: "The client should not call the timeout function") let expect = expectation(description: "The client should not call the timeout function")
@ -450,7 +466,7 @@ class TestEngine : SocketEngineSpec {
var connectParams: [String: Any]? = nil var connectParams: [String: Any]? = nil
private(set) var cookies: [HTTPCookie]? = nil private(set) var cookies: [HTTPCookie]? = nil
private(set) var engineQueue = DispatchQueue.main private(set) var engineQueue = DispatchQueue.main
private(set) var extraHeaders: [String: String]? = nil var extraHeaders: [String: String]? = nil
private(set) var fastUpgrade = false private(set) var fastUpgrade = false
private(set) var forcePolling = false private(set) var forcePolling = false
private(set) var forceWebsockets = false private(set) var forceWebsockets = false

View File

@ -106,6 +106,14 @@
[self waitForExpectationsWithTimeout:0.3 handler:nil]; [self waitForExpectationsWithTimeout:0.3 handler:nil];
} }
- (void)testMangerRemoveSocket {
[self setUpSockets];
[self.manager removeSocket:self.socket];
XCTAssertNil(self.manager.nsps[self.socket.nsp]);
}
- (void)setUpSockets { - (void)setUpSockets {
self.socket = [self.manager testSocketForNamespace:@"/"]; self.socket = [self.manager testSocketForNamespace:@"/"];
self.socket2 = [self.manager testSocketForNamespace:@"/swift"]; self.socket2 = [self.manager testSocketForNamespace:@"/swift"];