Support socket.io 3 + starscream 4
This commit is contained in:
parent
6992ea5250
commit
6cd8f79e8b
@ -1,7 +1,7 @@
|
||||
language: objective-c
|
||||
xcode_project: Socket.IO-Client-Swift.xcodeproj # path to your xcodeproj folder
|
||||
xcode_scheme: SocketIO-Mac
|
||||
osx_image: xcode11.2
|
||||
osx_image: xcode12.2
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
# v16.0.0
|
||||
|
||||
- Removed Objective-C support. It's time for you to embrace Swift.
|
||||
- Socket.io 3 support.
|
||||
|
||||
# v15.3.0
|
||||
|
||||
- Add `==` operators for `SocketAckStatus` and `String`
|
||||
|
||||
2
Cartfile
2
Cartfile
@ -1 +1 @@
|
||||
github "daltoniam/Starscream" ~> 3.1
|
||||
github "daltoniam/Starscream" ~> 4.0
|
||||
|
||||
@ -1 +1 @@
|
||||
github "daltoniam/Starscream" "3.1.0"
|
||||
github "daltoniam/Starscream" "4.0.4"
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
"repositoryURL": "https://github.com/daltoniam/Starscream",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "9c03ef715d1bc9334b446c90df53586dd38cf849",
|
||||
"version": "3.1.0"
|
||||
"revision": "df8d82047f6654d8e4b655d1b1525c64e1059d21",
|
||||
"version": "4.0.4"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// swift-tools-version:5.0
|
||||
// swift-tools-version:5.3
|
||||
|
||||
import PackageDescription
|
||||
|
||||
@ -8,7 +8,7 @@ let package = Package(
|
||||
.library(name: "SocketIO", targets: ["SocketIO"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/daltoniam/Starscream", .upToNextMinor(from: "3.1.0")),
|
||||
.package(url: "https://github.com/daltoniam/Starscream", .upToNextMinor(from: "4.0.0")),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "SocketIO", dependencies: ["Starscream"]),
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Socket.IO-Client-Swift"
|
||||
s.module_name = "SocketIO"
|
||||
s.version = "15.2.0"
|
||||
s.version = "16.0.0"
|
||||
s.summary = "Socket.IO-client for iOS and OS X"
|
||||
s.description = <<-DESC
|
||||
Socket.IO-client for iOS and OS X.
|
||||
Supports ws/wss/polling connections and binary.
|
||||
For socket.io 2.0+ and Swift.
|
||||
For socket.io 3.0+ and Swift.
|
||||
DESC
|
||||
s.homepage = "https://github.com/socketio/socket.io-client-swift"
|
||||
s.license = { :type => 'MIT' }
|
||||
@ -18,7 +18,7 @@ Pod::Spec.new do |s|
|
||||
s.requires_arc = true
|
||||
s.source = {
|
||||
:git => "https://github.com/socketio/socket.io-client-swift.git",
|
||||
:tag => 'v15.2.0',
|
||||
:tag => 'v16.0.0',
|
||||
:submodules => true
|
||||
}
|
||||
|
||||
@ -27,5 +27,5 @@ Pod::Spec.new do |s|
|
||||
'SWIFT_VERSION' => '5.0'
|
||||
}
|
||||
s.source_files = "Source/SocketIO/**/*.swift", "Source/SocketIO/*.swift"
|
||||
s.dependency "Starscream", "~> 3.1"
|
||||
s.dependency "Starscream", "~> 4.0"
|
||||
end
|
||||
|
||||
@ -40,23 +40,14 @@ import Foundation
|
||||
///
|
||||
/// **NOTE**: The client is not thread/queue safe, all interaction with the socket should be done on the `manager.handleQueue`
|
||||
///
|
||||
open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
open class SocketIOClient: NSObject, SocketIOClientSpec {
|
||||
// MARK: Properties
|
||||
|
||||
/// The namespace that this socket is currently connected to.
|
||||
///
|
||||
/// **Must** start with a `/`.
|
||||
@objc
|
||||
public let nsp: String
|
||||
|
||||
/// The session id of this client.
|
||||
@objc
|
||||
public var sid: String {
|
||||
guard let engine = manager?.engine else { return "" }
|
||||
|
||||
return nsp == "/" ? engine.sid : "\(nsp)#\(engine.sid)"
|
||||
}
|
||||
|
||||
/// A handler that will be called on any event.
|
||||
public private(set) var anyHandler: ((SocketAnyEvent) -> ())?
|
||||
|
||||
@ -64,7 +55,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
public private(set) var handlers = [SocketEventHandler]()
|
||||
|
||||
/// The manager for this socket.
|
||||
@objc
|
||||
public private(set) weak var manager: SocketManagerSpec?
|
||||
|
||||
/// A view into this socket where emits do not check for binary data.
|
||||
@ -76,17 +66,18 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// ```
|
||||
///
|
||||
/// **NOTE**: It is not safe to hold on to this view beyond the life of the socket.
|
||||
@objc
|
||||
public private(set) lazy var rawEmitView = SocketRawView(socket: self)
|
||||
|
||||
/// The status of this client.
|
||||
@objc
|
||||
public private(set) var status = SocketIOStatus.notConnected {
|
||||
didSet {
|
||||
handleClientEvent(.statusChange, data: [status, status.rawValue])
|
||||
}
|
||||
}
|
||||
|
||||
/// The id of this socket.io connect. This is different from the sid of the engine.io connection.
|
||||
public private(set) var sid: String?
|
||||
|
||||
let ackHandlers = SocketAckManager()
|
||||
|
||||
private(set) var currentAck = -1
|
||||
@ -99,7 +90,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
///
|
||||
/// - parameter manager: The manager for this socket.
|
||||
/// - parameter nsp: The namespace of the socket.
|
||||
@objc
|
||||
public init(manager: SocketManagerSpec, nsp: String) {
|
||||
self.manager = manager
|
||||
self.nsp = nsp
|
||||
@ -117,7 +107,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// Connect to the server. The same as calling `connect(timeoutAfter:withHandler:)` with a timeout of 0.
|
||||
///
|
||||
/// Only call after adding your event listeners, unless you know what you're doing.
|
||||
@objc
|
||||
open func connect() {
|
||||
connect(timeoutAfter: 0, withHandler: nil)
|
||||
}
|
||||
@ -129,7 +118,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// - parameter timeoutAfter: The number of seconds after which if we are not connected we assume the connection
|
||||
/// has failed. Pass 0 to never timeout.
|
||||
/// - parameter handler: The handler to call when the client fails to connect.
|
||||
@objc
|
||||
open func connect(timeoutAfter: Double, withHandler handler: (() -> ())?) {
|
||||
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
||||
|
||||
@ -142,13 +130,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
|
||||
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 }
|
||||
|
||||
manager.handleQueue.asyncAfter(deadline: DispatchTime.now() + timeoutAfter) {[weak self] in
|
||||
@ -171,14 +152,15 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// then this is only called when the client connects to that namespace.
|
||||
///
|
||||
/// - parameter toNamespace: The namespace that was connected to.
|
||||
open func didConnect(toNamespace namespace: String) {
|
||||
open func didConnect(toNamespace namespace: String, payload: [String: Any]?) {
|
||||
guard status != .connected else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Socket connected", type: logType)
|
||||
|
||||
status = .connected
|
||||
sid = payload?["sid"] as? String
|
||||
|
||||
handleClientEvent(.connect, data: [namespace])
|
||||
handleClientEvent(.connect, data: payload == nil ? [namespace] : [namespace, payload!])
|
||||
}
|
||||
|
||||
/// Called when the client has disconnected from socket.io.
|
||||
@ -190,6 +172,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
DefaultSocketLogger.Logger.log("Disconnected: \(reason)", type: logType)
|
||||
|
||||
status = .disconnected
|
||||
sid = ""
|
||||
|
||||
handleClientEvent(.disconnect, data: [reason])
|
||||
}
|
||||
@ -198,7 +181,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
///
|
||||
/// This will cause the socket to leave the namespace it is associated to, as well as remove itself from the
|
||||
/// `manager`.
|
||||
@objc
|
||||
open func disconnect() {
|
||||
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
|
||||
|
||||
@ -215,7 +197,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
open func emit(_ event: String, _ items: SocketData..., completion: (() -> ())? = nil) {
|
||||
do {
|
||||
try emit(event, with: items.map({ try $0.socketRepresentation() }), completion: completion)
|
||||
emit([event] + (try items.map({ try $0.socketRepresentation() })), completion: completion)
|
||||
} catch {
|
||||
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||
type: logType)
|
||||
@ -224,25 +206,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as emit, but meant for Objective-C
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. Send an empty array to send no data.
|
||||
@objc
|
||||
open func emit(_ event: String, with items: [Any]) {
|
||||
emit([event] + items)
|
||||
}
|
||||
|
||||
/// Same as emit, but meant for Objective-C
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. Send an empty array to send no data.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
@objc
|
||||
open func emit(_ event: String, with items: [Any], completion: (() -> ())? = nil) {
|
||||
emit([event] + items, completion: completion)
|
||||
}
|
||||
|
||||
/// Sends a message to the server, requesting an ack.
|
||||
///
|
||||
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
@ -264,7 +227,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||
open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
|
||||
do {
|
||||
return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() }))
|
||||
return createOnAck([event] + (try items.map({ try $0.socketRepresentation() })))
|
||||
} catch {
|
||||
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||
type: logType)
|
||||
@ -275,27 +238,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as emitWithAck, but for Objective-C
|
||||
///
|
||||
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
/// Check that your server's api will ack the event being sent.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.emitWithAck("myEvent", with: [1]).timingOut(after: 1) {data in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. Use `[]` to send nothing.
|
||||
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||
@objc
|
||||
open func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback {
|
||||
return createOnAck([event] + items)
|
||||
}
|
||||
|
||||
func emit(_ data: [Any],
|
||||
ack: Int? = nil,
|
||||
binary: Bool = true,
|
||||
@ -338,7 +280,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
///
|
||||
/// - parameter ack: The number for this ack.
|
||||
/// - parameter data: The data sent back with this ack.
|
||||
@objc
|
||||
open func handleAck(_ ack: Int, data: [Any]) {
|
||||
guard status == .connected else { return }
|
||||
|
||||
@ -361,7 +302,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// - parameter data: The data that was sent with this event.
|
||||
/// - parameter isInternalMessage: Whether this event was sent internally. If `true` it is always sent to handlers.
|
||||
/// - parameter ack: If > 0 then this event expects to get an ack back from the client.
|
||||
@objc
|
||||
open func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int = -1) {
|
||||
guard status == .connected || isInternalMessage else { return }
|
||||
|
||||
@ -387,7 +327,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
case .ack, .binaryAck:
|
||||
handleAck(packet.id, data: packet.data)
|
||||
case .connect:
|
||||
didConnect(toNamespace: nsp)
|
||||
didConnect(toNamespace: nsp, payload: packet.data.isEmpty ? nil : packet.data[0] as? [String: Any])
|
||||
case .disconnect:
|
||||
didDisconnect(reason: "Got Disconnect")
|
||||
case .error:
|
||||
@ -396,13 +336,11 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
}
|
||||
|
||||
/// Call when you wish to leave a namespace and disconnect this socket.
|
||||
@objc
|
||||
open func leaveNamespace() {
|
||||
manager?.disconnectSocket(self)
|
||||
}
|
||||
|
||||
/// Joins `nsp`.
|
||||
@objc
|
||||
open func joinNamespace() {
|
||||
DefaultSocketLogger.Logger.log("Joining namespace \(nsp)", type: logType)
|
||||
|
||||
@ -423,7 +361,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// If you wish to remove a specific event, call the `off(id:)` with the UUID received from its `on` call.
|
||||
///
|
||||
/// - parameter event: The event to remove handlers for.
|
||||
@objc
|
||||
open func off(_ event: String) {
|
||||
DefaultSocketLogger.Logger.log("Removing handler for event: \(event)", type: logType)
|
||||
|
||||
@ -435,7 +372,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// If you want to remove all events for an event, call the off `off(_:)` method with the event name.
|
||||
///
|
||||
/// - parameter id: The UUID of the handler you wish to remove.
|
||||
@objc
|
||||
open func off(id: UUID) {
|
||||
DefaultSocketLogger.Logger.log("Removing handler with id: \(id)", type: logType)
|
||||
|
||||
@ -447,7 +383,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// - parameter event: The event name for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
@objc
|
||||
@discardableResult
|
||||
open func on(_ event: String, callback: @escaping NormalCallback) -> UUID {
|
||||
DefaultSocketLogger.Logger.log("Adding handler for event: \(event)", type: logType)
|
||||
@ -491,7 +426,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// - parameter event: The event name for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
@objc
|
||||
@discardableResult
|
||||
open func once(_ event: String, callback: @escaping NormalCallback) -> UUID {
|
||||
DefaultSocketLogger.Logger.log("Adding once handler for event: \(event)", type: logType)
|
||||
@ -512,20 +446,17 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// Adds a handler that will be called on every event.
|
||||
///
|
||||
/// - parameter handler: The callback that will execute whenever an event is received.
|
||||
@objc
|
||||
open func onAny(_ handler: @escaping (SocketAnyEvent) -> ()) {
|
||||
anyHandler = handler
|
||||
}
|
||||
|
||||
/// Tries to reconnect to the server.
|
||||
@objc
|
||||
@available(*, unavailable, message: "Call the manager's reconnect method")
|
||||
open func reconnect() { }
|
||||
|
||||
/// Removes all handlers.
|
||||
///
|
||||
/// Can be used after disconnecting to break any potential remaining retain cycles.
|
||||
@objc
|
||||
open func removeAllHandlers() {
|
||||
handlers.removeAll(keepingCapacity: false)
|
||||
}
|
||||
@ -534,7 +465,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// Called when the manager detects a broken connection, or when a manual reconnect is triggered.
|
||||
///
|
||||
/// - parameter reason: The reason this socket is reconnecting.
|
||||
@objc
|
||||
open func setReconnecting(reason: String) {
|
||||
status = .connecting
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ public enum SocketIOClientOption : ClientOption {
|
||||
case secure(Bool)
|
||||
|
||||
/// Allows you to set which certs are valid. Useful for SSL pinning.
|
||||
case security(SSLSecurity)
|
||||
case security(CertificatePinning)
|
||||
|
||||
/// If you're using a self-signed set. Only use for development.
|
||||
case selfSigned(Bool)
|
||||
|
||||
@ -54,6 +54,9 @@ public protocol SocketIOClientSpec : AnyObject {
|
||||
/// **NOTE**: It is not safe to hold on to this view beyond the life of the socket.
|
||||
var rawEmitView: SocketRawView { get }
|
||||
|
||||
/// The id of this socket.io connect. This is different from the sid of the engine.io connection.
|
||||
var sid: String? { get }
|
||||
|
||||
/// The status of this client.
|
||||
var status: SocketIOStatus { get }
|
||||
|
||||
@ -77,7 +80,7 @@ public protocol SocketIOClientSpec : AnyObject {
|
||||
/// then this is only called when the client connects to that namespace.
|
||||
///
|
||||
/// - parameter toNamespace: The namespace that was connected to.
|
||||
func didConnect(toNamespace namespace: String)
|
||||
func didConnect(toNamespace namespace: String, payload: [String: Any]?)
|
||||
|
||||
/// Called when the client has disconnected from socket.io.
|
||||
///
|
||||
|
||||
@ -28,7 +28,8 @@ import Starscream
|
||||
|
||||
/// The class that handles the engine.io protocol and transports.
|
||||
/// See `SocketEnginePollable` and `SocketEngineWebsocket` for transport specific methods.
|
||||
open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, SocketEngineWebsocket, ConfigSettable {
|
||||
open class SocketEngine:
|
||||
NSObject, WebSocketDelegate, URLSessionDelegate, SocketEnginePollable, SocketEngineWebsocket, ConfigSettable {
|
||||
// MARK: Properties
|
||||
|
||||
private static let logType = "SocketEngine"
|
||||
@ -120,6 +121,9 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
/// The WebSocket for this engine.
|
||||
public private(set) var ws: WebSocket?
|
||||
|
||||
/// Whether or not the WebSocket is currently connected.
|
||||
public private(set) var wsConnected = false
|
||||
|
||||
/// The client for this engine.
|
||||
public weak var client: SocketEngineClient?
|
||||
|
||||
@ -130,15 +134,15 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
private var pingInterval: Int?
|
||||
private var pingTimeout = 0 {
|
||||
didSet {
|
||||
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25000))
|
||||
pingsMissedMax = Int(pingTimeout / (pingInterval ?? 25000))
|
||||
}
|
||||
}
|
||||
|
||||
private var pongsMissed = 0
|
||||
private var pongsMissedMax = 0
|
||||
private var pingsMissed = 0
|
||||
private var pingsMissedMax = 0
|
||||
private var probeWait = ProbeWaitQueue()
|
||||
private var secure = false
|
||||
private var security: SocketIO.SSLSecurity?
|
||||
private var certPinner: CertificatePinning?
|
||||
private var selfSigned = false
|
||||
|
||||
// MARK: Initializers
|
||||
@ -198,7 +202,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
|
||||
private func handleBase64(message: String) {
|
||||
// binary in base64 string
|
||||
let noPrefix = String(message[message.index(message.startIndex, offsetBy: 2)..<message.endIndex])
|
||||
let noPrefix = String(message[message.index(message.startIndex, offsetBy: 1)..<message.endIndex])
|
||||
|
||||
if let data = Data(base64Encoded: noPrefix, options: .ignoreUnknownCharacters) {
|
||||
client?.parseEngineBinaryData(data)
|
||||
@ -285,45 +289,14 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
private func createWebSocketAndConnect() {
|
||||
var req = URLRequest(url: urlWebSocketWithSid)
|
||||
|
||||
addHeaders(to: &req, includingCookies: session?.configuration.httpCookieStorage?.cookies(for: urlPollingWithSid))
|
||||
addHeaders(
|
||||
to: &req,
|
||||
includingCookies: session?.configuration.httpCookieStorage?.cookies(for: urlPollingWithSid)
|
||||
)
|
||||
|
||||
let stream = FoundationStream()
|
||||
stream.enableSOCKSProxy = enableSOCKSProxy
|
||||
ws = WebSocket(request: req, stream: stream)
|
||||
ws = WebSocket(request: req, certPinner: certPinner, compressionHandler: compress ? WSCompression() : nil)
|
||||
ws?.callbackQueue = engineQueue
|
||||
ws?.enableCompression = compress
|
||||
ws?.disableSSLCertValidation = selfSigned
|
||||
ws?.security = security?.security
|
||||
|
||||
ws?.onConnect = {[weak self] in
|
||||
guard let this = self else { return }
|
||||
|
||||
this.websocketDidConnect()
|
||||
}
|
||||
|
||||
ws?.onDisconnect = {[weak self] error in
|
||||
guard let this = self else { return }
|
||||
|
||||
this.websocketDidDisconnect(error: error)
|
||||
}
|
||||
|
||||
ws?.onData = {[weak self] data in
|
||||
guard let this = self else { return }
|
||||
|
||||
this.parseEngineData(data)
|
||||
}
|
||||
|
||||
ws?.onText = {[weak self] message in
|
||||
guard let this = self else { return }
|
||||
|
||||
this.parseEngineMessage(message)
|
||||
}
|
||||
|
||||
ws?.onHttpResponseHeaders = {[weak self] headers in
|
||||
guard let this = self else { return }
|
||||
|
||||
this.client?.engineDidWebsocketUpgrade(headers: headers)
|
||||
}
|
||||
ws?.delegate = self
|
||||
|
||||
ws?.connect()
|
||||
}
|
||||
@ -445,7 +418,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
|
||||
self.sid = sid
|
||||
connected = true
|
||||
pongsMissed = 0
|
||||
pingsMissed = 0
|
||||
|
||||
if let upgrades = json["upgrades"] as? [String] {
|
||||
upgradeWs = upgrades.contains("websocket")
|
||||
@ -462,18 +435,15 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
createWebSocketAndConnect()
|
||||
}
|
||||
|
||||
sendPing()
|
||||
|
||||
if !forceWebsockets {
|
||||
doPoll()
|
||||
}
|
||||
|
||||
checkPings()
|
||||
client?.engineDidOpen(reason: "Connect")
|
||||
}
|
||||
|
||||
private func handlePong(with message: String) {
|
||||
pongsMissed = 0
|
||||
|
||||
// We should upgrade
|
||||
if message == "3probe" {
|
||||
DefaultSocketLogger.Logger.log("Received probe response, should upgrade to WebSockets",
|
||||
@ -481,8 +451,31 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
|
||||
upgradeTransport()
|
||||
}
|
||||
}
|
||||
|
||||
client?.engineDidReceivePong()
|
||||
private func handlePing(with message: String) {
|
||||
pingsMissed = 0
|
||||
|
||||
write("", withType: .pong, withData: [])
|
||||
|
||||
client?.engineDidReceivePing()
|
||||
}
|
||||
|
||||
private func checkPings() {
|
||||
let pingInterval = self.pingInterval ?? 25_000
|
||||
|
||||
engineQueue.asyncAfter(deadline: .now() + .milliseconds(pingInterval)) {[weak self, id = self.sid] in
|
||||
// Make sure not to ping old connections
|
||||
guard let this = self, this.sid == id else { return }
|
||||
|
||||
if this.pingsMissed > this.pingsMissedMax {
|
||||
this.closeOutEngine(reason: "Ping timeout")
|
||||
} else {
|
||||
this.pingsMissed += 1
|
||||
|
||||
this.checkPings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses raw binary received from engine.io.
|
||||
@ -491,7 +484,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
open func parseEngineData(_ data: Data) {
|
||||
DefaultSocketLogger.Logger.log("Got binary data: \(data)", type: SocketEngine.logType)
|
||||
|
||||
client?.parseEngineBinaryData(data.subdata(in: 1..<data.endIndex))
|
||||
client?.parseEngineBinaryData(data)
|
||||
}
|
||||
|
||||
/// Parses a raw engine.io packet.
|
||||
@ -502,7 +495,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
|
||||
let reader = SocketStringReader(message: message)
|
||||
|
||||
if message.hasPrefix("b4") {
|
||||
if message.hasPrefix("b") {
|
||||
return handleBase64(message: message)
|
||||
}
|
||||
|
||||
@ -517,6 +510,8 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
handleMessage(String(message.dropFirst()))
|
||||
case .noop:
|
||||
handleNOOP()
|
||||
case .ping:
|
||||
handlePing(with: message)
|
||||
case .pong:
|
||||
handlePong(with: message)
|
||||
case .open:
|
||||
@ -549,12 +544,12 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
guard connected, let pingInterval = pingInterval else { return }
|
||||
|
||||
// Server is not responding
|
||||
if pongsMissed > pongsMissedMax {
|
||||
if pingsMissed > pingsMissedMax {
|
||||
closeOutEngine(reason: "Ping timeout")
|
||||
return
|
||||
}
|
||||
|
||||
pongsMissed += 1
|
||||
pingsMissed += 1
|
||||
write("", withType: .ping, withData: [], completion: nil)
|
||||
|
||||
engineQueue.asyncAfter(deadline: .now() + .milliseconds(pingInterval)) {[weak self, id = self.sid] in
|
||||
@ -564,7 +559,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
this.sendPing()
|
||||
}
|
||||
|
||||
client?.engineDidSendPing()
|
||||
client?.engineDidSendPong()
|
||||
}
|
||||
|
||||
/// Called when the engine should set/update its configs from a given configuration.
|
||||
@ -595,8 +590,8 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
self.secure = secure
|
||||
case let .selfSigned(selfSigned):
|
||||
self.selfSigned = selfSigned
|
||||
case let .security(security):
|
||||
self.security = security
|
||||
case let .security(pinner):
|
||||
self.certPinner = pinner
|
||||
case .compress:
|
||||
self.compress = true
|
||||
case .enableSOCKSProxy:
|
||||
@ -609,7 +604,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
|
||||
// Moves from long-polling to websockets
|
||||
private func upgradeTransport() {
|
||||
if ws?.isConnected ?? false {
|
||||
if wsConnected {
|
||||
DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: SocketEngine.logType)
|
||||
|
||||
fastUpgrade = true
|
||||
@ -630,6 +625,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
||||
completion?()
|
||||
return
|
||||
}
|
||||
|
||||
guard !self.probing else {
|
||||
self.probeWait.append((msg, type, data, completion))
|
||||
|
||||
@ -705,3 +701,32 @@ extension SocketEngine {
|
||||
didError(reason: "Engine URLSession became invalid")
|
||||
}
|
||||
}
|
||||
|
||||
enum EngineError: Error {
|
||||
case canceled
|
||||
}
|
||||
|
||||
extension SocketEngine {
|
||||
public func didReceive(event: WebSocketEvent, client _: WebSocket) {
|
||||
switch event {
|
||||
case let .connected(headers):
|
||||
wsConnected = true
|
||||
client?.engineDidWebsocketUpgrade(headers: headers)
|
||||
websocketDidConnect()
|
||||
case let .error(err):
|
||||
print(err)
|
||||
case .cancelled:
|
||||
wsConnected = false
|
||||
websocketDidDisconnect(error: EngineError.canceled)
|
||||
case let .disconnected(reason, code):
|
||||
wsConnected = false
|
||||
websocketDidDisconnect(error: nil)
|
||||
case let .text(msg):
|
||||
parseEngineMessage(msg)
|
||||
case let .binary(data):
|
||||
parseEngineData(data)
|
||||
case _:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,11 +44,11 @@ import Foundation
|
||||
/// - parameter reason: The reason the engine opened.
|
||||
func engineDidOpen(reason: String)
|
||||
|
||||
/// Called when the engine receives a pong message.
|
||||
func engineDidReceivePong()
|
||||
/// Called when the engine receives a ping message.
|
||||
func engineDidReceivePing()
|
||||
|
||||
/// Called when the engine sends a ping to the server.
|
||||
func engineDidSendPing()
|
||||
/// Called when the engine sends a pong to the server.
|
||||
func engineDidSendPong()
|
||||
|
||||
/// Called when the engine has a message that must be parsed.
|
||||
///
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
import Foundation
|
||||
|
||||
/// Represents the type of engine.io packet types.
|
||||
@objc public enum SocketEnginePacketType : Int {
|
||||
@objc public enum SocketEnginePacketType: Int {
|
||||
/// Open message.
|
||||
case open
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
import Foundation
|
||||
|
||||
/// Protocol that is used to implement socket.io polling support
|
||||
public protocol SocketEnginePollable : SocketEngineSpec {
|
||||
public protocol SocketEnginePollable: SocketEngineSpec {
|
||||
// MARK: Properties
|
||||
|
||||
/// `true` If engine's session has been invalidated.
|
||||
@ -79,11 +79,7 @@ extension SocketEnginePollable {
|
||||
postWait.removeAll(keepingCapacity: true)
|
||||
}
|
||||
|
||||
var postStr = ""
|
||||
|
||||
for packet in postWait {
|
||||
postStr += "\(packet.msg.utf16.count):\(packet.msg)"
|
||||
}
|
||||
let postStr = postWait.lazy.map({ $0.msg }).joined(separator: "\u{1e}")
|
||||
|
||||
DefaultSocketLogger.Logger.log("Created POST string: \(postStr)", type: "SocketEnginePolling")
|
||||
|
||||
@ -195,19 +191,14 @@ extension SocketEnginePollable {
|
||||
}
|
||||
|
||||
func parsePollingMessage(_ str: String) {
|
||||
guard str.count != 1 else { return }
|
||||
guard !str.isEmpty else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Got poll message: \(str)", type: "SocketEnginePolling")
|
||||
|
||||
var reader = SocketStringReader(message: str)
|
||||
let records = str.components(separatedBy: "\u{1e}")
|
||||
|
||||
while reader.hasNext {
|
||||
if let n = Int(reader.readUntilOccurence(of: ":")) {
|
||||
parseEngineMessage(reader.read(count: n))
|
||||
} else {
|
||||
parseEngineMessage(str)
|
||||
break
|
||||
}
|
||||
for record in records {
|
||||
parseEngineMessage(record)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ import Foundation
|
||||
import Starscream
|
||||
|
||||
/// Specifies a SocketEngine.
|
||||
@objc public protocol SocketEngineSpec {
|
||||
public protocol SocketEngineSpec: class {
|
||||
// MARK: Properties
|
||||
|
||||
/// The client for this engine.
|
||||
@ -173,9 +173,9 @@ extension SocketEngineSpec {
|
||||
|
||||
func createBinaryDataForSend(using data: Data) -> Either<Data, String> {
|
||||
if polling {
|
||||
return .right("b4" + data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)))
|
||||
return .right("b" + data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)))
|
||||
} else {
|
||||
return .left(Data([0x4]) + data)
|
||||
return .left(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,12 @@ import Foundation
|
||||
import Starscream
|
||||
|
||||
/// Protocol that is used to implement socket.io WebSocket support
|
||||
public protocol SocketEngineWebsocket : SocketEngineSpec {
|
||||
public protocol SocketEngineWebsocket: SocketEngineSpec {
|
||||
// MARK: Properties
|
||||
|
||||
/// Whether or not the ws is connected
|
||||
var wsConnected: Bool { get }
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Sends an engine.io message through the WebSocket transport.
|
||||
@ -47,7 +52,7 @@ public protocol SocketEngineWebsocket : SocketEngineSpec {
|
||||
// WebSocket methods
|
||||
extension SocketEngineWebsocket {
|
||||
func probeWebSocket() {
|
||||
if ws?.isConnected ?? false {
|
||||
if wsConnected {
|
||||
sendWebSocketMessage("probe", withType: .ping, withData: [], completion: nil)
|
||||
}
|
||||
}
|
||||
@ -69,14 +74,14 @@ extension SocketEngineWebsocket {
|
||||
|
||||
ws?.write(string: "\(type.rawValue)\(str)")
|
||||
|
||||
if data.count == 0 {
|
||||
completion?()
|
||||
}
|
||||
|
||||
for item in data {
|
||||
if case let .left(bin) = createBinaryDataForSend(using: item) {
|
||||
ws?.write(data: bin, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
if data.count == 0 {
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ import Foundation
|
||||
///
|
||||
/// **NOTE**: The manager is not thread/queue safe, all interaction with the manager should be done on the `handleQueue`
|
||||
///
|
||||
open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDataBufferable, ConfigSettable {
|
||||
open class SocketManager: NSObject, SocketManagerSpec, SocketParsable, SocketDataBufferable, ConfigSettable {
|
||||
private static let logType = "SocketManager"
|
||||
|
||||
// MARK: Properties
|
||||
@ -282,18 +282,8 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
||||
return
|
||||
}
|
||||
|
||||
emitAll(event, withItems: emitData)
|
||||
}
|
||||
|
||||
/// Sends an event to the server on all namespaces in this manager.
|
||||
///
|
||||
/// Same as `emitAll(_:_:)`, but meant for Objective-C.
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The data to send with this event.
|
||||
open func emitAll(_ event: String, withItems items: [Any]) {
|
||||
forAll {socket in
|
||||
socket.emit(event, with: items, completion: nil)
|
||||
socket.emit([event] + emitData, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,33 +339,32 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
||||
DefaultSocketLogger.Logger.log("Engine opened \(reason)", type: SocketManager.logType)
|
||||
|
||||
status = .connected
|
||||
nsps["/"]?.didConnect(toNamespace: "/")
|
||||
|
||||
for (nsp, socket) in nsps where nsp != "/" && socket.status == .connecting {
|
||||
for (_, socket) in nsps where socket.status == .connecting {
|
||||
connectSocket(socket)
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the engine receives a pong message.
|
||||
open func engineDidReceivePong() {
|
||||
open func engineDidReceivePing() {
|
||||
handleQueue.async {
|
||||
self._engineDidReceivePong()
|
||||
self._engineDidReceivePing()
|
||||
}
|
||||
}
|
||||
|
||||
private func _engineDidReceivePong() {
|
||||
emitAll(clientEvent: .pong, data: [])
|
||||
private func _engineDidReceivePing() {
|
||||
emitAll(clientEvent: .ping, data: [])
|
||||
}
|
||||
|
||||
/// Called when the sends a ping to the server.
|
||||
open func engineDidSendPing() {
|
||||
open func engineDidSendPong() {
|
||||
handleQueue.async {
|
||||
self._engineDidSendPing()
|
||||
self._engineDidSendPong()
|
||||
}
|
||||
}
|
||||
|
||||
private func _engineDidSendPing() {
|
||||
emitAll(clientEvent: .ping, data: [])
|
||||
private func _engineDidSendPong() {
|
||||
emitAll(clientEvent: .pong, data: [])
|
||||
}
|
||||
|
||||
private func forAll(do: (SocketIOClient) throws -> ()) rethrows {
|
||||
@ -476,14 +465,19 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Trying to reconnect", type: SocketManager.logType)
|
||||
emitAll(clientEvent: .reconnectAttempt, data: [(reconnectAttempts - currentReconnectAttempt)])
|
||||
|
||||
forAll {socket in
|
||||
guard socket.status == .connecting else { return }
|
||||
|
||||
socket.handleClientEvent(.reconnectAttempt, data: [(reconnectAttempts - currentReconnectAttempt)])
|
||||
}
|
||||
|
||||
currentReconnectAttempt += 1
|
||||
connect()
|
||||
|
||||
let interval = reconnectInterval(attempts: currentReconnectAttempt)
|
||||
DefaultSocketLogger.Logger.log("Scheduling reconnect in \(interval)s", type: SocketManager.logType)
|
||||
handleQueue.asyncAfter(deadline: DispatchTime.now() + interval, execute: _tryReconnect)
|
||||
handleQueue.asyncAfter(deadline: .now() + interval, execute: _tryReconnect)
|
||||
}
|
||||
|
||||
func reconnectInterval(attempts: Int) -> Double {
|
||||
|
||||
@ -45,7 +45,6 @@ import Foundation
|
||||
/// To disconnect a socket and remove it from the manager, either call `SocketIOClient.disconnect()` on the socket,
|
||||
/// or call one of the `disconnectSocket` methods on this class.
|
||||
///
|
||||
@objc
|
||||
public protocol SocketManagerSpec : AnyObject, SocketEngineClient {
|
||||
// MARK: Properties
|
||||
|
||||
@ -116,7 +115,7 @@ public protocol SocketManagerSpec : AnyObject, SocketEngineClient {
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The data to send with this event.
|
||||
func emitAll(_ event: String, withItems items: [Any])
|
||||
func emitAll(_ event: String, _ items: SocketData...)
|
||||
|
||||
/// Tries to reconnect to the server.
|
||||
///
|
||||
|
||||
@ -118,7 +118,7 @@ public extension SocketParsable where Self: SocketManagerSpec & SocketDataBuffer
|
||||
|
||||
var dataArray = String(message.utf16[message.utf16.index(reader.currentIndex, offsetBy: 1)...])!
|
||||
|
||||
if type == .error && !dataArray.hasPrefix("[") && !dataArray.hasSuffix("]") {
|
||||
if (type == .error || type == .connect) && !dataArray.hasPrefix("[") && !dataArray.hasSuffix("]") {
|
||||
dataArray = "[" + dataArray + "]"
|
||||
}
|
||||
|
||||
|
||||
@ -1,72 +0,0 @@
|
||||
//
|
||||
// SSLSecurity.swift
|
||||
// SocketIO-iOS
|
||||
//
|
||||
// Created by Lukas Schmidt on 24.09.17.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import Foundation
|
||||
import Starscream
|
||||
|
||||
/// A wrapper around Starscream's SSLSecurity that provides a minimal Objective-C interface.
|
||||
open class SSLSecurity : NSObject {
|
||||
// MARK: Properties
|
||||
|
||||
/// The internal Starscream SSLSecurity.
|
||||
public let security: Starscream.SSLSecurity
|
||||
|
||||
init(security: Starscream.SSLSecurity) {
|
||||
self.security = security
|
||||
}
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Creates a new SSLSecurity that specifies whether to use publicKeys or certificates should be used for SSL
|
||||
/// pinning validation
|
||||
///
|
||||
/// - parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning
|
||||
/// validation
|
||||
@objc
|
||||
public convenience init(usePublicKeys: Bool = true) {
|
||||
let security = Starscream.SSLSecurity(usePublicKeys: usePublicKeys)
|
||||
self.init(security: security)
|
||||
}
|
||||
|
||||
|
||||
/// Designated init
|
||||
///
|
||||
/// - parameter certs: is the certificates or public keys to use
|
||||
/// - parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning
|
||||
/// validation
|
||||
/// - returns: a representation security object to be used with
|
||||
public convenience init(certs: [SSLCert], usePublicKeys: Bool) {
|
||||
let security = Starscream.SSLSecurity(certs: certs, usePublicKeys: usePublicKeys)
|
||||
self.init(security: security)
|
||||
}
|
||||
|
||||
/// Returns whether or not the given trust is valid.
|
||||
///
|
||||
/// - parameter trust: The trust to validate.
|
||||
/// - parameter domain: The CN domain to validate.
|
||||
/// - returns: Whether or not this is valid.
|
||||
public func isValid(_ trust: SecTrust, domain: String?) -> Bool {
|
||||
return security.isValid(trust, domain: domain)
|
||||
}
|
||||
}
|
||||
@ -77,7 +77,7 @@ extension Dictionary where Key == String, Value == Any {
|
||||
return .randomizationFactor(factor)
|
||||
case let ("secure", secure as Bool):
|
||||
return .secure(secure)
|
||||
case let ("security", security as SSLSecurity):
|
||||
case let ("security", security as CertificatePinning):
|
||||
return .security(security)
|
||||
case let ("selfSigned", selfSigned as Bool):
|
||||
return .selfSigned(selfSigned)
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
//
|
||||
// Created by Erik Little on 10/21/17.
|
||||
//
|
||||
|
||||
#import "SocketIO_Tests-Swift.h"
|
||||
|
||||
@import XCTest;
|
||||
@import SocketIO;
|
||||
|
||||
@interface ManagerObjectiveCTest : XCTestCase
|
||||
|
||||
@property TestSocket* socket;
|
||||
@property TestSocket* socket2;
|
||||
@property TestManager* manager;
|
||||
|
||||
@end
|
||||
@ -1,141 +0,0 @@
|
||||
//
|
||||
// Created by Erik Little on 10/21/17.
|
||||
//
|
||||
|
||||
#import "ManagerObjectiveCTest.h"
|
||||
|
||||
@import Dispatch;
|
||||
@import Foundation;
|
||||
@import XCTest;
|
||||
@import SocketIO;
|
||||
|
||||
@implementation ManagerObjectiveCTest
|
||||
|
||||
- (void)testSettingConfig {
|
||||
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
|
||||
NSDictionary* headers = @{@"My Header": @"Some Value"};
|
||||
|
||||
self.manager = [[TestManager alloc] initWithSocketURL:url config:@{
|
||||
@"forceNew": @YES,
|
||||
@"extraHeaders": headers
|
||||
}];
|
||||
|
||||
[self.manager connect];
|
||||
|
||||
XCTAssertTrue(self.manager.forceNew);
|
||||
XCTAssertTrue([self.manager.engine.extraHeaders isEqualToDictionary:headers]);
|
||||
|
||||
}
|
||||
|
||||
- (void)testManagerProperties {
|
||||
XCTAssertNotNil(self.manager.defaultSocket);
|
||||
XCTAssertNil(self.manager.engine);
|
||||
XCTAssertFalse(self.manager.forceNew);
|
||||
XCTAssertEqual(self.manager.handleQueue, dispatch_get_main_queue());
|
||||
XCTAssertTrue(self.manager.reconnects);
|
||||
XCTAssertEqual(self.manager.reconnectWait, 10);
|
||||
XCTAssertEqual(self.manager.reconnectWaitMax, 30);
|
||||
XCTAssertEqual(self.manager.randomizationFactor, 0.5);
|
||||
XCTAssertEqual(self.manager.status, SocketIOStatusNotConnected);
|
||||
}
|
||||
|
||||
- (void)testConnectSocketSyntax {
|
||||
[self setUpSockets];
|
||||
[self.manager connectSocket:self.socket];
|
||||
}
|
||||
|
||||
- (void)testDisconnectSocketSyntax {
|
||||
[self setUpSockets];
|
||||
[self.manager disconnectSocket:self.socket];
|
||||
}
|
||||
|
||||
- (void)testSocketForNamespaceSyntax {
|
||||
SocketIOClient* client = [self.manager socketForNamespace:@"/swift"];
|
||||
client = nil;
|
||||
}
|
||||
|
||||
- (void)testManagerCallsConnect {
|
||||
[self setUpSockets];
|
||||
|
||||
XCTestExpectation* expect = [self expectationWithDescription:@"The manager should call connect on the default socket"];
|
||||
XCTestExpectation* expect2 = [self expectationWithDescription:@"The manager should call connect on the socket"];
|
||||
|
||||
self.socket.expects[@"didConnectCalled"] = expect;
|
||||
self.socket2.expects[@"didConnectCalled"] = expect2;
|
||||
|
||||
[self.socket connect];
|
||||
[self.socket2 connect];
|
||||
|
||||
[self.manager fakeConnecting];
|
||||
[self.manager fakeConnectingToNamespace:@"/swift"];
|
||||
|
||||
[self waitForExpectationsWithTimeout:0.3 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testManagerCallsDisconnect {
|
||||
[self setUpSockets];
|
||||
|
||||
XCTestExpectation* expect = [self expectationWithDescription:@"The manager should call disconnect on the default socket"];
|
||||
XCTestExpectation* expect2 = [self expectationWithDescription:@"The manager should call disconnect on the socket"];
|
||||
|
||||
self.socket.expects[@"didDisconnectCalled"] = expect;
|
||||
self.socket2.expects[@"didDisconnectCalled"] = expect2;
|
||||
|
||||
[self.socket2 on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||
[self.manager disconnect];
|
||||
[self.manager fakeDisconnecting];
|
||||
}];
|
||||
|
||||
[self.socket connect];
|
||||
[self.socket2 connect];
|
||||
|
||||
[self.manager fakeConnecting];
|
||||
[self.manager fakeConnectingToNamespace:@"/swift"];
|
||||
|
||||
[self waitForExpectationsWithTimeout:0.3 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testManagerEmitAll {
|
||||
[self setUpSockets];
|
||||
|
||||
XCTestExpectation* expect = [self expectationWithDescription:@"The manager should emit an event to the default socket"];
|
||||
XCTestExpectation* expect2 = [self expectationWithDescription:@"The manager should emit an event to the socket"];
|
||||
|
||||
self.socket.expects[@"emitAllEventCalled"] = expect;
|
||||
self.socket2.expects[@"emitAllEventCalled"] = expect2;
|
||||
|
||||
[self.socket2 on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||
[self.manager emitAll:@"event" withItems:@[@"testing"]];
|
||||
}];
|
||||
|
||||
[self.socket connect];
|
||||
[self.socket2 connect];
|
||||
|
||||
[self.manager fakeConnecting];
|
||||
[self.manager fakeConnectingToNamespace:@"/swift"];
|
||||
|
||||
[self waitForExpectationsWithTimeout:0.3 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testMangerRemoveSocket {
|
||||
[self setUpSockets];
|
||||
|
||||
[self.manager removeSocket:self.socket];
|
||||
|
||||
XCTAssertNil(self.manager.nsps[self.socket.nsp]);
|
||||
}
|
||||
|
||||
- (void)setUpSockets {
|
||||
self.socket = [self.manager testSocketForNamespace:@"/"];
|
||||
self.socket2 = [self.manager testSocketForNamespace:@"/swift"];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
|
||||
self.manager = [[TestManager alloc] initWithSocketURL:url config:@{@"log": @NO}];
|
||||
self.socket = nil;
|
||||
self.socket2 = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@ -1,16 +0,0 @@
|
||||
//
|
||||
// Created by Erik Little on 10/21/17.
|
||||
//
|
||||
|
||||
|
||||
@import Dispatch;
|
||||
@import Foundation;
|
||||
@import XCTest;
|
||||
@import SocketIO;
|
||||
|
||||
@interface SocketObjectiveCTest : XCTestCase
|
||||
|
||||
@property SocketIOClient* socket;
|
||||
@property SocketManager* manager;
|
||||
|
||||
@end
|
||||
@ -1,122 +0,0 @@
|
||||
//
|
||||
// SocketObjectiveCTest.m
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/25/16.
|
||||
//
|
||||
// Merely tests whether the Objective-C api breaks
|
||||
//
|
||||
|
||||
#import "SocketIO_Tests-Swift.h"
|
||||
#import "SocketObjectiveCTest.h"
|
||||
|
||||
@import Dispatch;
|
||||
@import Foundation;
|
||||
@import XCTest;
|
||||
@import SocketIO;
|
||||
|
||||
// TODO Manager interface tests
|
||||
|
||||
@implementation SocketObjectiveCTest
|
||||
|
||||
- (void)testProperties {
|
||||
XCTAssertTrue([self.socket.nsp isEqualToString:@"/"]);
|
||||
XCTAssertEqual(self.socket.status, SocketIOStatusNotConnected);
|
||||
}
|
||||
|
||||
- (void)testOnSyntax {
|
||||
[self.socket on:@"someCallback" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||
[ack with:@[@1]];
|
||||
[[ack rawEmitView] with:@[@"hello"]];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testConnectSyntax {
|
||||
[self.socket connect];
|
||||
}
|
||||
|
||||
- (void)testConnectTimeoutAfterSyntax {
|
||||
[self.socket connectWithTimeoutAfter:1 withHandler: ^() { }];
|
||||
}
|
||||
|
||||
- (void)testDisconnectSyntax {
|
||||
[self.socket disconnect];
|
||||
}
|
||||
|
||||
- (void)testLeaveNamespaceSyntax {
|
||||
[self.socket leaveNamespace];
|
||||
}
|
||||
|
||||
- (void)testJoinNamespaceSyntax {
|
||||
[self.socket joinNamespace];
|
||||
}
|
||||
|
||||
- (void)testOnAnySyntax {
|
||||
[self.socket onAny:^(SocketAnyEvent* any) {
|
||||
NSString* event = any.event;
|
||||
NSArray* data = any.items;
|
||||
|
||||
[self.socket emit:event with:data];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testRemoveAllHandlersSyntax {
|
||||
[self.socket removeAllHandlers];
|
||||
}
|
||||
|
||||
- (void)testEmitSyntax {
|
||||
[self.socket emit:@"testEmit" with:@[@YES]];
|
||||
}
|
||||
|
||||
- (void)testEmitWriteCompletionSyntax {
|
||||
[self.socket emit:@"testEmit" with:@[@YES] completion:^{}];
|
||||
}
|
||||
|
||||
- (void)testEmitWriteCompletion {
|
||||
XCTestExpectation* expect = [self expectationWithDescription:@"Write completion should be called"];
|
||||
|
||||
[self.socket emit:@"testEmit" with:@[@YES] completion:^{
|
||||
[expect fulfill];
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithTimeout:0.3 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testRawEmitSyntax {
|
||||
[[self.socket rawEmitView] emit:@"myEvent" with:@[@1]];
|
||||
}
|
||||
|
||||
- (void)testEmitWithAckSyntax {
|
||||
[[self.socket emitWithAck:@"testAckEmit" with:@[@YES]] timingOutAfter:0 callback:^(NSArray* data) { }];
|
||||
}
|
||||
|
||||
- (void)testOffSyntax {
|
||||
[self.socket off:@"test"];
|
||||
}
|
||||
|
||||
- (void)testSSLSecurity {
|
||||
SSLSecurity* sec = [[SSLSecurity alloc] initWithUsePublicKeys:0];
|
||||
sec = nil;
|
||||
}
|
||||
|
||||
- (void)testStatusChangeHandler {
|
||||
XCTestExpectation* expect = [self expectationWithDescription:@"statusChange should be correctly called"];
|
||||
|
||||
[self.socket on:@"statusChange" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||
XCTAssertTrue([data[1] integerValue] == SocketIOStatusConnecting);
|
||||
[expect fulfill];
|
||||
}];
|
||||
|
||||
[OBjcUtils setTestStatusWithSocket:self.socket status:SocketIOStatusConnecting];
|
||||
|
||||
[self waitForExpectationsWithTimeout:0.3 handler:nil];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
|
||||
self.manager = [[SocketManager alloc] initWithSocketURL:url config:@{@"log": @NO}];
|
||||
self.socket = [self.manager defaultSocket];
|
||||
}
|
||||
|
||||
@end
|
||||
Loading…
x
Reference in New Issue
Block a user