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:
commit
313032aa41
@ -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`
|
||||||
|
|||||||
@ -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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -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 = {
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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`.
|
||||||
|
|||||||
@ -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 }
|
||||||
|
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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 + "]"
|
||||||
|
|||||||
@ -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
|
||||||
///
|
///
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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!
|
||||||
|
|||||||
@ -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")
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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"];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user