Support socket.io 3 + starscream 4
This commit is contained in:
parent
6992ea5250
commit
6cd8f79e8b
@ -1,7 +1,7 @@
|
|||||||
language: objective-c
|
language: objective-c
|
||||||
xcode_project: Socket.IO-Client-Swift.xcodeproj # path to your xcodeproj folder
|
xcode_project: Socket.IO-Client-Swift.xcodeproj # path to your xcodeproj folder
|
||||||
xcode_scheme: SocketIO-Mac
|
xcode_scheme: SocketIO-Mac
|
||||||
osx_image: xcode11.2
|
osx_image: xcode12.2
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- 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
|
# v15.3.0
|
||||||
|
|
||||||
- Add `==` operators for `SocketAckStatus` and `String`
|
- 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",
|
"repositoryURL": "https://github.com/daltoniam/Starscream",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "9c03ef715d1bc9334b446c90df53586dd38cf849",
|
"revision": "df8d82047f6654d8e4b655d1b1525c64e1059d21",
|
||||||
"version": "3.1.0"
|
"version": "4.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// swift-tools-version:5.0
|
// swift-tools-version:5.3
|
||||||
|
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ let package = Package(
|
|||||||
.library(name: "SocketIO", targets: ["SocketIO"])
|
.library(name: "SocketIO", targets: ["SocketIO"])
|
||||||
],
|
],
|
||||||
dependencies: [
|
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: [
|
targets: [
|
||||||
.target(name: "SocketIO", dependencies: ["Starscream"]),
|
.target(name: "SocketIO", dependencies: ["Starscream"]),
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
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 = "15.2.0"
|
s.version = "16.0.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.
|
||||||
Supports ws/wss/polling connections and binary.
|
Supports ws/wss/polling connections and binary.
|
||||||
For socket.io 2.0+ and Swift.
|
For socket.io 3.0+ and Swift.
|
||||||
DESC
|
DESC
|
||||||
s.homepage = "https://github.com/socketio/socket.io-client-swift"
|
s.homepage = "https://github.com/socketio/socket.io-client-swift"
|
||||||
s.license = { :type => 'MIT' }
|
s.license = { :type => 'MIT' }
|
||||||
@ -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 => 'v15.2.0',
|
:tag => 'v16.0.0',
|
||||||
:submodules => true
|
:submodules => true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,5 +27,5 @@ Pod::Spec.new do |s|
|
|||||||
'SWIFT_VERSION' => '5.0'
|
'SWIFT_VERSION' => '5.0'
|
||||||
}
|
}
|
||||||
s.source_files = "Source/SocketIO/**/*.swift", "Source/SocketIO/*.swift"
|
s.source_files = "Source/SocketIO/**/*.swift", "Source/SocketIO/*.swift"
|
||||||
s.dependency "Starscream", "~> 3.1"
|
s.dependency "Starscream", "~> 4.0"
|
||||||
end
|
end
|
||||||
|
|||||||
@ -46,17 +46,8 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
|||||||
/// The namespace that this socket is currently connected to.
|
/// The namespace that this socket is currently connected to.
|
||||||
///
|
///
|
||||||
/// **Must** start with a `/`.
|
/// **Must** start with a `/`.
|
||||||
@objc
|
|
||||||
public let nsp: String
|
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.
|
/// A handler that will be called on any event.
|
||||||
public private(set) var anyHandler: ((SocketAnyEvent) -> ())?
|
public private(set) var anyHandler: ((SocketAnyEvent) -> ())?
|
||||||
|
|
||||||
@ -64,7 +55,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
|||||||
public private(set) var handlers = [SocketEventHandler]()
|
public private(set) var handlers = [SocketEventHandler]()
|
||||||
|
|
||||||
/// The manager for this socket.
|
/// The manager for this socket.
|
||||||
@objc
|
|
||||||
public private(set) weak var manager: SocketManagerSpec?
|
public private(set) weak var manager: SocketManagerSpec?
|
||||||
|
|
||||||
/// A view into this socket where emits do not check for binary data.
|
/// 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.
|
/// **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)
|
public private(set) lazy var rawEmitView = SocketRawView(socket: self)
|
||||||
|
|
||||||
/// The status of this client.
|
/// The status of this client.
|
||||||
@objc
|
|
||||||
public private(set) var status = SocketIOStatus.notConnected {
|
public private(set) var status = SocketIOStatus.notConnected {
|
||||||
didSet {
|
didSet {
|
||||||
handleClientEvent(.statusChange, data: [status, status.rawValue])
|
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()
|
let ackHandlers = SocketAckManager()
|
||||||
|
|
||||||
private(set) var currentAck = -1
|
private(set) var currentAck = -1
|
||||||
@ -99,7 +90,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
|||||||
///
|
///
|
||||||
/// - parameter manager: The manager for this socket.
|
/// - parameter manager: The manager for this socket.
|
||||||
/// - parameter nsp: The namespace of the socket.
|
/// - parameter nsp: The namespace of the socket.
|
||||||
@objc
|
|
||||||
public init(manager: SocketManagerSpec, nsp: String) {
|
public init(manager: SocketManagerSpec, nsp: String) {
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.nsp = nsp
|
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.
|
/// 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.
|
/// Only call after adding your event listeners, unless you know what you're doing.
|
||||||
@objc
|
|
||||||
open func connect() {
|
open func connect() {
|
||||||
connect(timeoutAfter: 0, withHandler: nil)
|
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
|
/// - parameter timeoutAfter: The number of seconds after which if we are not connected we assume the connection
|
||||||
/// has failed. Pass 0 to never timeout.
|
/// has failed. Pass 0 to never timeout.
|
||||||
/// - parameter handler: The handler to call when the client fails to connect.
|
/// - parameter handler: The handler to call when the client fails to connect.
|
||||||
@objc
|
|
||||||
open func connect(timeoutAfter: Double, withHandler handler: (() -> ())?) {
|
open func connect(timeoutAfter: Double, withHandler handler: (() -> ())?) {
|
||||||
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
||||||
|
|
||||||
@ -142,13 +130,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
|||||||
|
|
||||||
joinNamespace()
|
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 }
|
||||||
|
|
||||||
manager.handleQueue.asyncAfter(deadline: DispatchTime.now() + timeoutAfter) {[weak self] in
|
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.
|
/// then this is only called when the client connects to that namespace.
|
||||||
///
|
///
|
||||||
/// - parameter toNamespace: The namespace that was connected to.
|
/// - 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 }
|
guard status != .connected else { return }
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Socket connected", type: logType)
|
DefaultSocketLogger.Logger.log("Socket connected", type: logType)
|
||||||
|
|
||||||
status = .connected
|
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.
|
/// 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)
|
DefaultSocketLogger.Logger.log("Disconnected: \(reason)", type: logType)
|
||||||
|
|
||||||
status = .disconnected
|
status = .disconnected
|
||||||
|
sid = ""
|
||||||
|
|
||||||
handleClientEvent(.disconnect, data: [reason])
|
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
|
/// This will cause the socket to leave the namespace it is associated to, as well as remove itself from the
|
||||||
/// `manager`.
|
/// `manager`.
|
||||||
@objc
|
|
||||||
open func disconnect() {
|
open func disconnect() {
|
||||||
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
|
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
|
||||||
|
|
||||||
@ -215,7 +197,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
|||||||
/// - parameter completion: Callback called on transport write completion.
|
/// - parameter completion: Callback called on transport write completion.
|
||||||
open func emit(_ event: String, _ items: SocketData..., completion: (() -> ())? = nil) {
|
open func emit(_ event: String, _ items: SocketData..., completion: (() -> ())? = nil) {
|
||||||
do {
|
do {
|
||||||
try emit(event, with: items.map({ try $0.socketRepresentation() }), completion: completion)
|
emit([event] + (try items.map({ try $0.socketRepresentation() })), completion: completion)
|
||||||
} catch {
|
} catch {
|
||||||
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||||
type: logType)
|
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.
|
/// 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.
|
/// **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.
|
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||||
open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
|
open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
|
||||||
do {
|
do {
|
||||||
return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() }))
|
return createOnAck([event] + (try items.map({ try $0.socketRepresentation() })))
|
||||||
} catch {
|
} catch {
|
||||||
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||||
type: logType)
|
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],
|
func emit(_ data: [Any],
|
||||||
ack: Int? = nil,
|
ack: Int? = nil,
|
||||||
binary: Bool = true,
|
binary: Bool = true,
|
||||||
@ -338,7 +280,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
|||||||
///
|
///
|
||||||
/// - parameter ack: The number for this ack.
|
/// - parameter ack: The number for this ack.
|
||||||
/// - parameter data: The data sent back with this ack.
|
/// - parameter data: The data sent back with this ack.
|
||||||
@objc
|
|
||||||
open func handleAck(_ ack: Int, data: [Any]) {
|
open func handleAck(_ ack: Int, data: [Any]) {
|
||||||
guard status == .connected else { return }
|
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 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 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.
|
/// - 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) {
|
open func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int = -1) {
|
||||||
guard status == .connected || isInternalMessage else { return }
|
guard status == .connected || isInternalMessage else { return }
|
||||||
|
|
||||||
@ -387,7 +327,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
|||||||
case .ack, .binaryAck:
|
case .ack, .binaryAck:
|
||||||
handleAck(packet.id, data: packet.data)
|
handleAck(packet.id, data: packet.data)
|
||||||
case .connect:
|
case .connect:
|
||||||
didConnect(toNamespace: nsp)
|
didConnect(toNamespace: nsp, payload: packet.data.isEmpty ? nil : packet.data[0] as? [String: Any])
|
||||||
case .disconnect:
|
case .disconnect:
|
||||||
didDisconnect(reason: "Got Disconnect")
|
didDisconnect(reason: "Got Disconnect")
|
||||||
case .error:
|
case .error:
|
||||||
@ -396,13 +336,11 @@ 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
|
|
||||||
open func leaveNamespace() {
|
open func leaveNamespace() {
|
||||||
manager?.disconnectSocket(self)
|
manager?.disconnectSocket(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Joins `nsp`.
|
/// Joins `nsp`.
|
||||||
@objc
|
|
||||||
open func joinNamespace() {
|
open func joinNamespace() {
|
||||||
DefaultSocketLogger.Logger.log("Joining namespace \(nsp)", type: logType)
|
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.
|
/// 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.
|
/// - parameter event: The event to remove handlers for.
|
||||||
@objc
|
|
||||||
open func off(_ event: String) {
|
open func off(_ event: String) {
|
||||||
DefaultSocketLogger.Logger.log("Removing handler for event: \(event)", type: logType)
|
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.
|
/// 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.
|
/// - parameter id: The UUID of the handler you wish to remove.
|
||||||
@objc
|
|
||||||
open func off(id: UUID) {
|
open func off(id: UUID) {
|
||||||
DefaultSocketLogger.Logger.log("Removing handler with id: \(id)", type: logType)
|
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 event: The event name for this handler.
|
||||||
/// - parameter callback: The callback that will execute when this event is received.
|
/// - 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.
|
/// - returns: A unique id for the handler that can be used to remove it.
|
||||||
@objc
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
open func on(_ event: String, callback: @escaping NormalCallback) -> UUID {
|
open func on(_ event: String, callback: @escaping NormalCallback) -> UUID {
|
||||||
DefaultSocketLogger.Logger.log("Adding handler for event: \(event)", type: logType)
|
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 event: The event name for this handler.
|
||||||
/// - parameter callback: The callback that will execute when this event is received.
|
/// - 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.
|
/// - returns: A unique id for the handler that can be used to remove it.
|
||||||
@objc
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
open func once(_ event: String, callback: @escaping NormalCallback) -> UUID {
|
open func once(_ event: String, callback: @escaping NormalCallback) -> UUID {
|
||||||
DefaultSocketLogger.Logger.log("Adding once handler for event: \(event)", type: logType)
|
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.
|
/// Adds a handler that will be called on every event.
|
||||||
///
|
///
|
||||||
/// - parameter handler: The callback that will execute whenever an event is received.
|
/// - parameter handler: The callback that will execute whenever an event is received.
|
||||||
@objc
|
|
||||||
open func onAny(_ handler: @escaping (SocketAnyEvent) -> ()) {
|
open func onAny(_ handler: @escaping (SocketAnyEvent) -> ()) {
|
||||||
anyHandler = handler
|
anyHandler = handler
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to reconnect to the server.
|
/// Tries to reconnect to the server.
|
||||||
@objc
|
|
||||||
@available(*, unavailable, message: "Call the manager's reconnect method")
|
@available(*, unavailable, message: "Call the manager's reconnect method")
|
||||||
open func reconnect() { }
|
open func reconnect() { }
|
||||||
|
|
||||||
/// Removes all handlers.
|
/// Removes all handlers.
|
||||||
///
|
///
|
||||||
/// Can be used after disconnecting to break any potential remaining retain cycles.
|
/// Can be used after disconnecting to break any potential remaining retain cycles.
|
||||||
@objc
|
|
||||||
open func removeAllHandlers() {
|
open func removeAllHandlers() {
|
||||||
handlers.removeAll(keepingCapacity: false)
|
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.
|
/// Called when the manager detects a broken connection, or when a manual reconnect is triggered.
|
||||||
///
|
///
|
||||||
/// - parameter reason: The reason this socket is reconnecting.
|
/// - parameter reason: The reason this socket is reconnecting.
|
||||||
@objc
|
|
||||||
open func setReconnecting(reason: String) {
|
open func setReconnecting(reason: String) {
|
||||||
status = .connecting
|
status = .connecting
|
||||||
|
|
||||||
|
|||||||
@ -91,7 +91,7 @@ public enum SocketIOClientOption : ClientOption {
|
|||||||
case secure(Bool)
|
case secure(Bool)
|
||||||
|
|
||||||
/// Allows you to set which certs are valid. Useful for SSL pinning.
|
/// 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.
|
/// If you're using a self-signed set. Only use for development.
|
||||||
case selfSigned(Bool)
|
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.
|
/// **NOTE**: It is not safe to hold on to this view beyond the life of the socket.
|
||||||
var rawEmitView: SocketRawView { get }
|
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.
|
/// The status of this client.
|
||||||
var status: SocketIOStatus { get }
|
var status: SocketIOStatus { get }
|
||||||
|
|
||||||
@ -77,7 +80,7 @@ public protocol SocketIOClientSpec : AnyObject {
|
|||||||
/// then this is only called when the client connects to that namespace.
|
/// then this is only called when the client connects to that namespace.
|
||||||
///
|
///
|
||||||
/// - parameter toNamespace: The namespace that was connected to.
|
/// - 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.
|
/// 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.
|
/// The class that handles the engine.io protocol and transports.
|
||||||
/// See `SocketEnginePollable` and `SocketEngineWebsocket` for transport specific methods.
|
/// 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
|
// MARK: Properties
|
||||||
|
|
||||||
private static let logType = "SocketEngine"
|
private static let logType = "SocketEngine"
|
||||||
@ -120,6 +121,9 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
/// The WebSocket for this engine.
|
/// The WebSocket for this engine.
|
||||||
public private(set) var ws: WebSocket?
|
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.
|
/// The client for this engine.
|
||||||
public weak var client: SocketEngineClient?
|
public weak var client: SocketEngineClient?
|
||||||
|
|
||||||
@ -130,15 +134,15 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
private var pingInterval: Int?
|
private var pingInterval: Int?
|
||||||
private var pingTimeout = 0 {
|
private var pingTimeout = 0 {
|
||||||
didSet {
|
didSet {
|
||||||
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25000))
|
pingsMissedMax = Int(pingTimeout / (pingInterval ?? 25000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var pongsMissed = 0
|
private var pingsMissed = 0
|
||||||
private var pongsMissedMax = 0
|
private var pingsMissedMax = 0
|
||||||
private var probeWait = ProbeWaitQueue()
|
private var probeWait = ProbeWaitQueue()
|
||||||
private var secure = false
|
private var secure = false
|
||||||
private var security: SocketIO.SSLSecurity?
|
private var certPinner: CertificatePinning?
|
||||||
private var selfSigned = false
|
private var selfSigned = false
|
||||||
|
|
||||||
// MARK: Initializers
|
// MARK: Initializers
|
||||||
@ -198,7 +202,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
|
|
||||||
private func handleBase64(message: String) {
|
private func handleBase64(message: String) {
|
||||||
// binary in base64 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) {
|
if let data = Data(base64Encoded: noPrefix, options: .ignoreUnknownCharacters) {
|
||||||
client?.parseEngineBinaryData(data)
|
client?.parseEngineBinaryData(data)
|
||||||
@ -285,45 +289,14 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
private func createWebSocketAndConnect() {
|
private func createWebSocketAndConnect() {
|
||||||
var req = URLRequest(url: urlWebSocketWithSid)
|
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()
|
ws = WebSocket(request: req, certPinner: certPinner, compressionHandler: compress ? WSCompression() : nil)
|
||||||
stream.enableSOCKSProxy = enableSOCKSProxy
|
|
||||||
ws = WebSocket(request: req, stream: stream)
|
|
||||||
ws?.callbackQueue = engineQueue
|
ws?.callbackQueue = engineQueue
|
||||||
ws?.enableCompression = compress
|
ws?.delegate = self
|
||||||
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?.connect()
|
ws?.connect()
|
||||||
}
|
}
|
||||||
@ -445,7 +418,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
|
|
||||||
self.sid = sid
|
self.sid = sid
|
||||||
connected = true
|
connected = true
|
||||||
pongsMissed = 0
|
pingsMissed = 0
|
||||||
|
|
||||||
if let upgrades = json["upgrades"] as? [String] {
|
if let upgrades = json["upgrades"] as? [String] {
|
||||||
upgradeWs = upgrades.contains("websocket")
|
upgradeWs = upgrades.contains("websocket")
|
||||||
@ -462,18 +435,15 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
createWebSocketAndConnect()
|
createWebSocketAndConnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPing()
|
|
||||||
|
|
||||||
if !forceWebsockets {
|
if !forceWebsockets {
|
||||||
doPoll()
|
doPoll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkPings()
|
||||||
client?.engineDidOpen(reason: "Connect")
|
client?.engineDidOpen(reason: "Connect")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handlePong(with message: String) {
|
private func handlePong(with message: String) {
|
||||||
pongsMissed = 0
|
|
||||||
|
|
||||||
// We should upgrade
|
// We should upgrade
|
||||||
if message == "3probe" {
|
if message == "3probe" {
|
||||||
DefaultSocketLogger.Logger.log("Received probe response, should upgrade to WebSockets",
|
DefaultSocketLogger.Logger.log("Received probe response, should upgrade to WebSockets",
|
||||||
@ -481,8 +451,31 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
|
|
||||||
upgradeTransport()
|
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.
|
/// Parses raw binary received from engine.io.
|
||||||
@ -491,7 +484,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
open func parseEngineData(_ data: Data) {
|
open func parseEngineData(_ data: Data) {
|
||||||
DefaultSocketLogger.Logger.log("Got binary data: \(data)", type: SocketEngine.logType)
|
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.
|
/// Parses a raw engine.io packet.
|
||||||
@ -502,7 +495,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
|
|
||||||
let reader = SocketStringReader(message: message)
|
let reader = SocketStringReader(message: message)
|
||||||
|
|
||||||
if message.hasPrefix("b4") {
|
if message.hasPrefix("b") {
|
||||||
return handleBase64(message: message)
|
return handleBase64(message: message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,6 +510,8 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
handleMessage(String(message.dropFirst()))
|
handleMessage(String(message.dropFirst()))
|
||||||
case .noop:
|
case .noop:
|
||||||
handleNOOP()
|
handleNOOP()
|
||||||
|
case .ping:
|
||||||
|
handlePing(with: message)
|
||||||
case .pong:
|
case .pong:
|
||||||
handlePong(with: message)
|
handlePong(with: message)
|
||||||
case .open:
|
case .open:
|
||||||
@ -549,12 +544,12 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
guard connected, let pingInterval = pingInterval else { return }
|
guard connected, let pingInterval = pingInterval else { return }
|
||||||
|
|
||||||
// Server is not responding
|
// Server is not responding
|
||||||
if pongsMissed > pongsMissedMax {
|
if pingsMissed > pingsMissedMax {
|
||||||
closeOutEngine(reason: "Ping timeout")
|
closeOutEngine(reason: "Ping timeout")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pongsMissed += 1
|
pingsMissed += 1
|
||||||
write("", withType: .ping, withData: [], completion: nil)
|
write("", withType: .ping, withData: [], completion: nil)
|
||||||
|
|
||||||
engineQueue.asyncAfter(deadline: .now() + .milliseconds(pingInterval)) {[weak self, id = self.sid] in
|
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()
|
this.sendPing()
|
||||||
}
|
}
|
||||||
|
|
||||||
client?.engineDidSendPing()
|
client?.engineDidSendPong()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the engine should set/update its configs from a given configuration.
|
/// 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
|
self.secure = secure
|
||||||
case let .selfSigned(selfSigned):
|
case let .selfSigned(selfSigned):
|
||||||
self.selfSigned = selfSigned
|
self.selfSigned = selfSigned
|
||||||
case let .security(security):
|
case let .security(pinner):
|
||||||
self.security = security
|
self.certPinner = pinner
|
||||||
case .compress:
|
case .compress:
|
||||||
self.compress = true
|
self.compress = true
|
||||||
case .enableSOCKSProxy:
|
case .enableSOCKSProxy:
|
||||||
@ -609,7 +604,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
|
|
||||||
// Moves from long-polling to websockets
|
// Moves from long-polling to websockets
|
||||||
private func upgradeTransport() {
|
private func upgradeTransport() {
|
||||||
if ws?.isConnected ?? false {
|
if wsConnected {
|
||||||
DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: SocketEngine.logType)
|
DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: SocketEngine.logType)
|
||||||
|
|
||||||
fastUpgrade = true
|
fastUpgrade = true
|
||||||
@ -630,6 +625,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So
|
|||||||
completion?()
|
completion?()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard !self.probing else {
|
guard !self.probing else {
|
||||||
self.probeWait.append((msg, type, data, completion))
|
self.probeWait.append((msg, type, data, completion))
|
||||||
|
|
||||||
@ -705,3 +701,32 @@ extension SocketEngine {
|
|||||||
didError(reason: "Engine URLSession became invalid")
|
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.
|
/// - parameter reason: The reason the engine opened.
|
||||||
func engineDidOpen(reason: String)
|
func engineDidOpen(reason: String)
|
||||||
|
|
||||||
/// Called when the engine receives a pong message.
|
/// Called when the engine receives a ping message.
|
||||||
func engineDidReceivePong()
|
func engineDidReceivePing()
|
||||||
|
|
||||||
/// Called when the engine sends a ping to the server.
|
/// Called when the engine sends a pong to the server.
|
||||||
func engineDidSendPing()
|
func engineDidSendPong()
|
||||||
|
|
||||||
/// Called when the engine has a message that must be parsed.
|
/// Called when the engine has a message that must be parsed.
|
||||||
///
|
///
|
||||||
|
|||||||
@ -79,11 +79,7 @@ extension SocketEnginePollable {
|
|||||||
postWait.removeAll(keepingCapacity: true)
|
postWait.removeAll(keepingCapacity: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
var postStr = ""
|
let postStr = postWait.lazy.map({ $0.msg }).joined(separator: "\u{1e}")
|
||||||
|
|
||||||
for packet in postWait {
|
|
||||||
postStr += "\(packet.msg.utf16.count):\(packet.msg)"
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Created POST string: \(postStr)", type: "SocketEnginePolling")
|
DefaultSocketLogger.Logger.log("Created POST string: \(postStr)", type: "SocketEnginePolling")
|
||||||
|
|
||||||
@ -195,19 +191,14 @@ extension SocketEnginePollable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parsePollingMessage(_ str: String) {
|
func parsePollingMessage(_ str: String) {
|
||||||
guard str.count != 1 else { return }
|
guard !str.isEmpty else { return }
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Got poll message: \(str)", type: "SocketEnginePolling")
|
DefaultSocketLogger.Logger.log("Got poll message: \(str)", type: "SocketEnginePolling")
|
||||||
|
|
||||||
var reader = SocketStringReader(message: str)
|
let records = str.components(separatedBy: "\u{1e}")
|
||||||
|
|
||||||
while reader.hasNext {
|
for record in records {
|
||||||
if let n = Int(reader.readUntilOccurence(of: ":")) {
|
parseEngineMessage(record)
|
||||||
parseEngineMessage(reader.read(count: n))
|
|
||||||
} else {
|
|
||||||
parseEngineMessage(str)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import Foundation
|
|||||||
import Starscream
|
import Starscream
|
||||||
|
|
||||||
/// Specifies a SocketEngine.
|
/// Specifies a SocketEngine.
|
||||||
@objc public protocol SocketEngineSpec {
|
public protocol SocketEngineSpec: class {
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
/// The client for this engine.
|
/// The client for this engine.
|
||||||
@ -173,9 +173,9 @@ extension SocketEngineSpec {
|
|||||||
|
|
||||||
func createBinaryDataForSend(using data: Data) -> Either<Data, String> {
|
func createBinaryDataForSend(using data: Data) -> Either<Data, String> {
|
||||||
if polling {
|
if polling {
|
||||||
return .right("b4" + data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)))
|
return .right("b" + data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)))
|
||||||
} else {
|
} else {
|
||||||
return .left(Data([0x4]) + data)
|
return .left(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,11 @@ 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 {
|
public protocol SocketEngineWebsocket: SocketEngineSpec {
|
||||||
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// Whether or not the ws is connected
|
||||||
|
var wsConnected: Bool { get }
|
||||||
|
|
||||||
// MARK: Methods
|
// MARK: Methods
|
||||||
|
|
||||||
/// Sends an engine.io message through the WebSocket transport.
|
/// Sends an engine.io message through the WebSocket transport.
|
||||||
@ -47,7 +52,7 @@ public protocol SocketEngineWebsocket : SocketEngineSpec {
|
|||||||
// WebSocket methods
|
// WebSocket methods
|
||||||
extension SocketEngineWebsocket {
|
extension SocketEngineWebsocket {
|
||||||
func probeWebSocket() {
|
func probeWebSocket() {
|
||||||
if ws?.isConnected ?? false {
|
if wsConnected {
|
||||||
sendWebSocketMessage("probe", withType: .ping, withData: [], completion: nil)
|
sendWebSocketMessage("probe", withType: .ping, withData: [], completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,14 +74,14 @@ extension SocketEngineWebsocket {
|
|||||||
|
|
||||||
ws?.write(string: "\(type.rawValue)\(str)")
|
ws?.write(string: "\(type.rawValue)\(str)")
|
||||||
|
|
||||||
if data.count == 0 {
|
|
||||||
completion?()
|
|
||||||
}
|
|
||||||
|
|
||||||
for item in data {
|
for item in data {
|
||||||
if case let .left(bin) = createBinaryDataForSend(using: item) {
|
if case let .left(bin) = createBinaryDataForSend(using: item) {
|
||||||
ws?.write(data: bin, completion: completion)
|
ws?.write(data: bin, completion: completion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if data.count == 0 {
|
||||||
|
completion?()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -282,18 +282,8 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
|||||||
return
|
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
|
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)
|
DefaultSocketLogger.Logger.log("Engine opened \(reason)", type: SocketManager.logType)
|
||||||
|
|
||||||
status = .connected
|
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)
|
connectSocket(socket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the engine receives a pong message.
|
/// Called when the engine receives a pong message.
|
||||||
open func engineDidReceivePong() {
|
open func engineDidReceivePing() {
|
||||||
handleQueue.async {
|
handleQueue.async {
|
||||||
self._engineDidReceivePong()
|
self._engineDidReceivePing()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func _engineDidReceivePong() {
|
private func _engineDidReceivePing() {
|
||||||
emitAll(clientEvent: .pong, data: [])
|
emitAll(clientEvent: .ping, data: [])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the sends a ping to the server.
|
/// Called when the sends a ping to the server.
|
||||||
open func engineDidSendPing() {
|
open func engineDidSendPong() {
|
||||||
handleQueue.async {
|
handleQueue.async {
|
||||||
self._engineDidSendPing()
|
self._engineDidSendPong()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func _engineDidSendPing() {
|
private func _engineDidSendPong() {
|
||||||
emitAll(clientEvent: .ping, data: [])
|
emitAll(clientEvent: .pong, data: [])
|
||||||
}
|
}
|
||||||
|
|
||||||
private func forAll(do: (SocketIOClient) throws -> ()) rethrows {
|
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)
|
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
|
currentReconnectAttempt += 1
|
||||||
connect()
|
connect()
|
||||||
|
|
||||||
let interval = reconnectInterval(attempts: currentReconnectAttempt)
|
let interval = reconnectInterval(attempts: currentReconnectAttempt)
|
||||||
DefaultSocketLogger.Logger.log("Scheduling reconnect in \(interval)s", type: SocketManager.logType)
|
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 {
|
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,
|
/// 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.
|
/// or call one of the `disconnectSocket` methods on this class.
|
||||||
///
|
///
|
||||||
@objc
|
|
||||||
public protocol SocketManagerSpec : AnyObject, SocketEngineClient {
|
public protocol SocketManagerSpec : AnyObject, SocketEngineClient {
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
@ -116,7 +115,7 @@ public protocol SocketManagerSpec : AnyObject, SocketEngineClient {
|
|||||||
///
|
///
|
||||||
/// - parameter event: The event to send.
|
/// - parameter event: The event to send.
|
||||||
/// - parameter items: The data to send with this event.
|
/// - 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.
|
/// 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)...])!
|
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 + "]"
|
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)
|
return .randomizationFactor(factor)
|
||||||
case let ("secure", secure as Bool):
|
case let ("secure", secure as Bool):
|
||||||
return .secure(secure)
|
return .secure(secure)
|
||||||
case let ("security", security as SSLSecurity):
|
case let ("security", security as CertificatePinning):
|
||||||
return .security(security)
|
return .security(security)
|
||||||
case let ("selfSigned", selfSigned as Bool):
|
case let ("selfSigned", selfSigned as Bool):
|
||||||
return .selfSigned(selfSigned)
|
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