Compare commits

..

No commits in common. "master" and "v5.3.1" have entirely different histories.

141 changed files with 5990 additions and 36011 deletions

View File

@ -1,19 +0,0 @@
name: Swift
on:
push:
branches: [ "master", "development" ]
pull_request:
branches: [ "master", "development" ]
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: swift build -v
- name: Run tests
run: swift test -v

6
.gitignore vendored
View File

@ -46,9 +46,3 @@ DerivedData
*.xcuserstate
Socket.IO-Test-Server/node_modules/*
.idea/
docs/docsets/
docs/undocumented.json
.swiftpm

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

13
.travis.yml Normal file
View File

@ -0,0 +1,13 @@
language: objective-c
xcode_project: Socket.IO-Client-Swift.xcodeproj # path to your xcodeproj folder
xcode_scheme: SocketIO-iOS
osx_image: xcode7
before_install:
- cd Socket.IO-Test-Server/
- npm install
- cd ..
install: node Socket.IO-Test-Server/main.js &
script: xctool -project Socket.IO-Client-Swift.xcodeproj -scheme SocketIO-Mac build test -parallelize
cache:
directories:
- Socket.IO-Test-Server/node_modules

View File

@ -1,104 +0,0 @@
# v16.1.0
- Remove support for iOS 11.
- Update to Starscream 4.0.6
# 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`
# v15.2.0
- Small fixes.
# v15.1.0
- Add ability to enable websockets SOCKS proxy.
- Fix emit completion callback not firing on websockets [#1178](https://github.com/socketio/socket.io-client-swift/issues/1178)
# v15.0.0
- Swift 5
# v14.0.0
- Minimum version of the client is now Swift 4.2.
- Add exponential backoff for reconnects, with `reconnectWaitMax` and `randomizationFactor` options [#1149](https://github.com/socketio/socket.io-client-swift/pull/1149)
- `statusChange` event's data format adds a second value, the raw value of the status. This is for use in Objective-C. [#1147](https://github.com/socketio/socket.io-client-swift/issues/1147)
# v13.4.0
- Add emits with write completion handlers. [#1096](https://github.com/socketio/socket.io-client-swift/issues/1096)
- Add ability to listen for when a websocket upgrade happens
# v13.3.1
- Fixes various bugs. [#857](https://github.com/socketio/socket.io-client-swift/issues/857), [#1078](https://github.com/socketio/socket.io-client-swift/issues/1078)
# v13.3.0
- Copy cookies from polling to WebSockets ([#1057](https://github.com/socketio/socket.io-client-swift/issues/1057), [#1058](https://github.com/socketio/socket.io-client-swift/issues/1058))
# v13.2.1
- Fix packets getting lost when WebSocket upgrade fails. [#1033](https://github.com/socketio/socket.io-client-swift/issues/1033)
- Fix bad unit tests. [#794](https://github.com/socketio/socket.io-client-swift/issues/794)
# v13.2.0
- Add ability to bypass Data inspection in emits. [#992]((https://github.com/socketio/socket.io-client-swift/issues/992))
- Allow `SocketEngine` to be subclassed
# v13.1.3
- Fix setting reconnectAttempts [#989]((https://github.com/socketio/socket.io-client-swift/issues/989))
# v13.1.2
- Fix [#950](https://github.com/socketio/socket.io-client-swift/issues/950)
- Conforming to `SocketEngineWebsocket` no longer requires conforming to `WebsocketDelegate`
# v13.1.1
- Fix [#923](https://github.com/socketio/socket.io-client-swift/issues/923)
- Fix [#894](https://github.com/socketio/socket.io-client-swift/issues/894)
# v13.1.0
- Allow setting `SocketEngineSpec.extraHeaders` after init.
- Deprecate `SocketEngineSpec.websocket` in favor of just using the `SocketEngineSpec.polling` property.
- Enable bitcode for most platforms.
- Fix [#882](https://github.com/socketio/socket.io-client-swift/issues/882). This adds a new method
`SocketManger.removeSocket(_:)` that should be called if when you no longer wish to use a socket again.
This will cause the engine to no longer keep a strong reference to the socket and no longer track it.
# v13.0.1
- Fix not setting handleQueue on `SocketManager`
# v13.0.0
Checkout out the migration guide in Usage Docs for a more detailed guide on how to migrate to this version.
What's new:
---
- Adds a new `SocketManager` class that multiplexes multiple namespaces through a single engine.
- Adds `.sentPing` and `.gotPong` client events for tracking ping/pongs.
- watchOS support.
Important API changes
---
- Many properties that were previously on `SocketIOClient` have been moved to the `SocketManager`.
- `SocketIOClientOption.nsp` has been removed. Use `SocketManager.socket(forNamespace:)` to create/get a socket attached to a specific namespace.
- Adds `.sentPing` and `.gotPong` client events for tracking ping/pongs.
- Makes the framework a single target.
- Updates Starscream to 3.0

View File

@ -1 +0,0 @@
github "daltoniam/Starscream" ~> 4.0.8

View File

@ -1 +0,0 @@
github "daltoniam/Starscream" "4.0.8"

View File

@ -1,16 +0,0 @@
{
"object": {
"pins": [
{
"package": "Starscream",
"repositoryURL": "https://github.com/daltoniam/Starscream",
"state": {
"branch": null,
"revision": "c6bfd1af48efcc9a9ad203665db12375ba6b145a",
"version": "4.0.8"
}
}
]
},
"version": 1
}

View File

@ -1,17 +1,5 @@
// swift-tools-version:5.4
import PackageDescription
let package = Package(
name: "SocketIO",
products: [
.library(name: "SocketIO", targets: ["SocketIO"])
],
dependencies: [
.package(url: "https://github.com/daltoniam/Starscream", .upToNextMajor(from: "4.0.8")),
],
targets: [
.target(name: "SocketIO", dependencies: ["Starscream"]),
.testTarget(name: "TestSocketIO", dependencies: ["SocketIO"]),
]
name: "SocketIOClientSwift"
)

184
README.md
View File

@ -1,95 +1,106 @@
[![Build Status](https://travis-ci.org/socketio/socket.io-client-swift.svg?branch=master)](https://travis-ci.org/socketio/socket.io-client-swift)
# Socket.IO-Client-Swift
#Socket.IO-Client-Swift
Socket.IO-client for iOS/OS X.
## Example
##Example
```swift
import SocketIO
let socket = SocketIOClient(socketURL: NSURL(string: "http://localhost:8080")!, options: [.Log(true), .ForcePolling(true)])
let manager = SocketManager(socketURL: URL(string: "http://localhost:8080")!, config: [.log(true), .compress])
let socket = manager.defaultSocket
socket.on(clientEvent: .connect) {data, ack in
socket.on("connect") {data, ack in
print("socket connected")
}
socket.on("currentAmount") {data, ack in
guard let cur = data[0] as? Double else { return }
socket.emitWithAck("canUpdate", cur).timingOut(after: 0) {data in
if data.first as? String ?? "passed" == SocketAckStatus.noAck {
// Handle ack timeout
if let cur = data[0] as? Double {
socket.emitWithAck("canUpdate", cur)(timeoutAfter: 0) {data in
socket.emit("update", ["amount": cur + 2.50])
}
socket.emit("update", ["amount": cur + 2.50])
ack.with("Got your currentAmount", "dude")
}
ack.with("Got your currentAmount", "dude")
}
socket.connect()
```
## Features
- Supports Socket.IO server 2.0+/3.0+/4.0+ (see the [compatibility table](https://nuclearace.github.io/Socket.IO-Client-Swift/Compatibility.html))
- Supports Binary
##Objective-C Example
```objective-c
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost:8080"];
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url options:@{@"log": @YES, @"forcePolling": @YES}];
[socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
NSLog(@"socket connected");
}];
[socket on:@"currentAmount" callback:^(NSArray* data, SocketAckEmitter* ack) {
double cur = [[data objectAtIndex:0] floatValue];
[socket emitWithAck:@"canUpdate" withItems:@[@(cur)]](0, ^(NSArray* data) {
[socket emit:@"update" withItems:@[@{@"amount": @(cur + 2.50)}]];
});
[ack with:@[@"Got your currentAmount, ", @"dude"]];
}];
[socket connect];
```
##Features
- Supports socket.io 1.0+
- Supports binary
- Supports Polling and WebSockets
- Supports TLS/SSL
- Can be used from Objective-C
## FAQS
Checkout the [FAQs](https://nuclearace.github.io/Socket.IO-Client-Swift/faq.html) for commonly asked questions.
##Installation
Requires Swift 2/Xcode 7
If you need Swift 1.2/Xcode 6.3/4 use v2.4.5 (Pre-Swift 2 support is no longer maintained)
Checkout the [12to13](https://nuclearace.github.io/Socket.IO-Client-Swift/12to13.html) guide for migrating to v13+ from v12 below.
If you need Swift 1.1/Xcode 6.2 use v1.5.2. (Pre-Swift 1.2 support is no longer maintained)
Checkout the [15to16](https://nuclearace.github.io/Socket.IO-Client-Swift/15to16.html) guide for migrating to v16+ from v15.
Manually (iOS 7+)
-----------------
1. Copy the Source folder into your Xcode project. (Make sure you add the files to your target(s))
2. If you plan on using this from Objective-C, read [this](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html) on exposing Swift code to Objective-C.
## Installation
Requires Swift 4/5 and Xcode 10.x
### Swift Package Manager
Swift Package Manager
---------------------
Add the project as a dependency to your Package.swift:
```swift
// swift-tools-version:4.2
import PackageDescription
let package = Package(
name: "socket.io-test",
products: [
.executable(name: "socket.io-test", targets: ["YourTargetName"])
],
name: "YourSocketIOProject",
dependencies: [
.package(url: "https://github.com/socketio/socket.io-client-swift", .upToNextMinor(from: "16.1.1"))
],
targets: [
.target(name: "YourTargetName", dependencies: ["SocketIO"], path: "./Path/To/Your/Sources")
.Package(url: "https://github.com/socketio/socket.io-client-swift", majorVersion: 5)
]
)
```
Then import `import SocketIO`.
Then import `import SocketIOClientSwift`.
### Carthage
Carthage
-----------------
Add this line to your `Cartfile`:
```
github "socketio/socket.io-client-swift" ~> 16.1.1
github "socketio/socket.io-client-swift" ~> 5.3.1 # Or latest version
```
Run `carthage update --platform ios,macosx`.
Add the `Starscream` and `SocketIO` frameworks to your projects and follow the usual Carthage process.
### CocoaPods 1.0.0 or later
CocoaPods 0.36.0 or later (iOS 8+)
------------------
Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`:
```ruby
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
target 'YourApp' do
pod 'Socket.IO-Client-Swift', '~> 16.1.1'
end
pod 'Socket.IO-Client-Swift', '~> 5.3.1' # Or latest version
```
Install pods:
@ -102,27 +113,88 @@ Import the module:
Swift:
```swift
import SocketIO
import SocketIOClientSwift
```
Objective-C:
```Objective-C
@import SocketIO;
#import <SocketIOClientSwift/SocketIOClientSwift-Swift.h>
```
CocoaSeeds
-----------------
# [Docs](https://nuclearace.github.io/Socket.IO-Client-Swift/index.html)
Add this line to your `Seedfile`:
- [Client](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketIOClient.html)
- [Manager](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketManager.html)
- [Engine](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketEngine.html)
- [Options](https://nuclearace.github.io/Socket.IO-Client-Swift/Enums/SocketIOClientOption.html)
```
github "socketio/socket.io-client-swift", "v5.3.1", :files => "Source/*.swift" # Or latest version
```
## Detailed Example
Run `seed install`.
##API
Constructors
-----------
`init(var socketURL: NSURL, options: Set<SocketIOClientOption> = [])` - Creates a new SocketIOClient. options is a Set of SocketIOClientOption. If your socket.io server is secure, you need to specify `https` in your socketURL.
`convenience init(socketURL: NSURL, options: NSDictionary?)` - Same as above, but meant for Objective-C. See Options on how convert between SocketIOClientOptions and dictionary keys.
Options
-------
All options are a case of SocketIOClientOption. To get the Objective-C Option, convert the name to lowerCamelCase.
```swift
case ConnectParams([String: AnyObject]) // Dictionary whose contents will be passed with the connection.
case Reconnects(Bool) // Whether to reconnect on server lose. Default is `true`
case ReconnectAttempts(Int) // How many times to reconnect. Default is `-1` (infinite tries)
case ReconnectWait(Int) // Amount of time to wait between reconnects. Default is `10`
case ForcePolling(Bool) // `true` forces the client to use xhr-polling. Default is `false`
case ForceNew(Bool) // Will a create a new engine for each connect. Useful if you find a bug in the engine related to reconnects
case ForceWebsockets(Bool) // `true` forces the client to use WebSockets. Default is `false`
case Nsp(String) // The namespace to connect to. Must begin with /. Default is `/`
case Cookies([NSHTTPCookie]) // An array of NSHTTPCookies. Passed during the handshake. Default is nil.
case Log(Bool) // If `true` socket will log debug messages. Default is false.
case Logger(SocketLogger) // Custom logger that conforms to SocketLogger. Will use the default logging otherwise.
case SessionDelegate(NSURLSessionDelegate) // Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs. Default is nil.
case Path(String) // If the server uses a custom path. ex: `"/swift/"`. Default is `""`
case ExtraHeaders([String: String]) // Adds custom headers to the initial request. Default is nil.
case HandleQueue(dispatch_queue_t) // The dispatch queue that handlers are run on. Default is the main queue.
case VoipEnabled(Bool) // Only use this option if you're using the client with VoIP services. Changes the way the WebSocket is created. Default is false
case Secure(Bool) // If the connection should use TLS. Default is false.
case SelfSigned(Bool) // Sets WebSocket.selfSignedSSL (Don't do this, iOS will yell at you)
```
Methods
-------
1. `on(event: String, callback: NormalCallback) -> NSUUID` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example. Returns a unique id for the handler.
2. `once(event: String, callback: NormalCallback) -> NSUUID` - Adds a handler that will only be executed once. Returns a unique id for the handler.
3. `onAny(callback:((event: String, items: AnyObject?)) -> Void)` - Adds a handler for all events. It will be called on any received event.
4. `emit(event: String, _ items: AnyObject...)` - Sends a message. Can send multiple items.
5. `emit(event: String, withItems items: [AnyObject])` - `emit` for Objective-C
6. `emitWithAck(event: String, _ items: AnyObject...) -> (timeoutAfter: UInt64, callback: (NSArray?) -> Void) -> Void` - Sends a message that requests an acknowledgement from the server. Returns a function which you can use to add a handler. See example. Note: The message is not sent until you call the returned function.
7. `emitWithAck(event: String, withItems items: [AnyObject]) -> (UInt64, (NSArray?) -> Void) -> Void` - `emitWithAck` for Objective-C. Note: The message is not sent until you call the returned function.
8. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
9. `connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called.
10. `disconnect()` - Closes the socket. Reopening a disconnected socket is not fully tested.
11. `reconnect()` - Causes the client to reconnect to the server.
12. `joinNamespace(namespace: String)` - Causes the client to join namespace. Shouldn't need to be called unless you change namespaces manually.
13. `leaveNamespace()` - Causes the client to leave the nsp and go back to /
14. `off(event: String)` - Removes all event handlers for event.
15. `off(id id: NSUUID)` - Removes the event that corresponds to id.
16. `removeAllHandlers()` - Removes all handlers.
Client Events
------
1. `connect` - Emitted when on a successful connection.
2. `disconnect` - Emitted when the connection is closed.
3. `error` - Emitted on an error.
4. `reconnect` - Emitted when the connection is starting to reconnect.
5. `reconnectAttempt` - Emitted when attempting to reconnect.
##Detailed Example
A more detailed example can be found [here](https://github.com/nuclearace/socket.io-client-swift-example)
An example using the Swift Package Manager can be found [here](https://github.com/nuclearace/socket.io-client-swift-spm-example)
## License
##License
MIT

View File

@ -1,31 +1,21 @@
Pod::Spec.new do |s|
s.name = "Socket.IO-Client-Swift"
s.module_name = "SocketIO"
s.version = "16.1.1"
s.module_name = "SocketIOClientSwift"
s.version = "5.3.1"
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 3.0+ and Swift.
For socket.io 1.0+ and Swift.
DESC
s.homepage = "https://github.com/socketio/socket.io-client-swift"
s.license = { :type => 'MIT' }
s.author = { "Erik" => "nuclear.ace@gmail.com" }
s.ios.deployment_target = '12.0'
s.osx.deployment_target = '10.13'
s.tvos.deployment_target = '12.0'
s.watchos.deployment_target = '5.0'
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.10'
s.tvos.deployment_target = '9.0'
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v5.3.1' }
s.source_files = "Source/**/*.swift"
s.requires_arc = true
s.source = {
:git => "https://github.com/socketio/socket.io-client-swift.git",
:tag => 'v16.1.1',
:submodules => true
}
s.swift_version = "5"
s.pod_target_xcconfig = {
'SWIFT_VERSION' => '5.4'
}
s.source_files = "Source/SocketIO/**/*.swift", "Source/SocketIO/*.swift"
s.dependency "Starscream", "~> 4.0.8"
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
end

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "0720"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -15,8 +15,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO"
BuildableName = "SocketIOClientSwift.framework"
BlueprintName = "SocketIO-Mac"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@ -29,8 +29,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2411B51F18A00EEBB58"
BuildableName = "SocketIO-Tests.xctest"
BlueprintName = "SocketIO-Tests"
BuildableName = "SocketIO-MacTests.xctest"
BlueprintName = "SocketIO-MacTests"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@ -47,8 +47,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2411B51F18A00EEBB58"
BuildableName = "SocketIO-Tests.xctest"
BlueprintName = "SocketIO-Tests"
BuildableName = "SocketIO-MacTests.xctest"
BlueprintName = "SocketIO-MacTests"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</TestableReference>
@ -57,8 +57,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO"
BuildableName = "SocketIOClientSwift.framework"
BlueprintName = "SocketIO-Mac"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
@ -79,8 +79,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO"
BuildableName = "SocketIOClientSwift.framework"
BlueprintName = "SocketIO-Mac"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
@ -97,8 +97,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO"
BuildableName = "SocketIOClientSwift.framework"
BlueprintName = "SocketIO-Mac"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
BuildableName = "SocketIOClientSwift.framework"
BlueprintName = "SocketIO-iOS"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2231B51F16C00EEBB58"
BuildableName = "SocketIO-iOSTests.xctest"
BlueprintName = "SocketIO-iOSTests"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2231B51F16C00EEBB58"
BuildableName = "SocketIO-iOSTests.xctest"
BlueprintName = "SocketIO-iOSTests"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
BuildableName = "SocketIOClientSwift.framework"
BlueprintName = "SocketIO-iOS"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
BuildableName = "SocketIOClientSwift.framework"
BlueprintName = "SocketIO-iOS"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
BuildableName = "SocketIOClientSwift.framework"
BlueprintName = "SocketIO-iOS"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "576349FA1BD9B46A00E19CD7"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO-tvOS"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "57634A181BD9B46D00E19CD7"
BuildableName = "SocketIO-tvOSTests.xctest"
BlueprintName = "SocketIO-tvOSTests"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "57634A181BD9B46D00E19CD7"
BuildableName = "SocketIO-tvOSTests.xctest"
BlueprintName = "SocketIO-tvOSTests"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "576349FA1BD9B46A00E19CD7"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO-tvOS"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "576349FA1BD9B46A00E19CD7"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO-tvOS"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "576349FA1BD9B46A00E19CD7"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO-tvOS"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,95 @@
var assert = require("assert")
module.exports = {
basicTest: {
assert: function(inputData) {
},
returnData: []
},
testNull: {
assert: function(inputData) {
assert(!inputData)
},
returnData: [null]
},
testBinary: {
assert: function(inputData) {
assert.equal(inputData.toString(), "gakgakgak2")
},
returnData: [new Buffer("gakgakgak2", "utf-8")]
},
testArray: {
assert: function(inputData) {
assert.equal(inputData.length, 2)
assert.equal(inputData[0], "test1")
assert.equal(inputData[1], "test2")
},
returnData: [["test3", "test4"]]
},
testString: {
assert: function(inputData) {
assert.equal(inputData, "marco")
},
returnData: ["polo"]
},
testBool: {
assert: function(inputData) {
assert(!inputData)
},
returnData: [true]
},
testInteger: {
assert: function(inputData) {
assert.equal(inputData, 10)
},
returnData: [20]
},
testDouble: {
assert: function(inputData) {
assert.equal(inputData, 1.1)
},
returnData: [1.2]
},
testJSON: {
assert: function(inputData) {
assert.equal(inputData.name, "test")
assert.equal(inputData.nestedTest.test, "test")
assert.equal(inputData.testArray.length, 1)
},
returnData: [{testString: "test", testNumber: 15, nestedTest: {test: "test"}, testArray: [1, 1]}]
},
testJSONWithBuffer: {
assert: function(inputData) {
assert.equal(inputData.name, "test")
assert.equal(inputData.nestedTest.test, "test")
assert.equal(inputData.testArray.length, 1)
},
returnData: [{testString: "test", testNumber: 15, nestedTest: {test: "test"}, testArray: [new Buffer("gakgakgak2", "utf-8"), 1]}]
},testUnicode: {
assert: function(inputData) {
assert.equal(inputData, "🚀")
},
returnData: ["🚄"]
},testMultipleItems: {
assert: function(array, object, number, string, bool) {
assert.equal(array.length, 2)
assert.equal(array[0], "test1")
assert.equal(array[1], "test2")
assert.equal(number, 15)
assert.equal(string, "marco")
assert.equal(bool, false)
},
returnData: [[1, 2], {test: "bob"}, 25, "polo", false]
},testMultipleItemsWithBuffer: {
assert: function(array, object, number, string, binary) {
assert.equal(array.length, 2)
assert.equal(array[0], "test1")
assert.equal(array[1], "test2")
assert.equal(number, 15)
assert.equal(string, "marco")
assert.equal(binary.toString(), "gakgakgak2")
},
returnData: [[1, 2], {test: "bob"}, 25, "polo", new Buffer("gakgakgak2")]
}
}

View File

@ -0,0 +1,10 @@
function socketCallback(testKey, socket, testCase) {
return function() {
testCase.assert.apply(undefined , arguments)
var emitArguments = testCase.returnData;
var ack = arguments[arguments.length - 1]
ack.apply(socket, emitArguments)
}
}
module.exports.socketCallback = socketCallback

View File

@ -0,0 +1,20 @@
function socketCallback(testKey, socket, testCase) {
return function() {
testCase.assert.apply(undefined , arguments)
var emitArguments = addArrays([testKey + "EmitReturn"], testCase.returnData)
socket.emit.apply(socket, emitArguments)
}
}
function addArrays(firstArray, secondArray) {
var length = secondArray.length
var i;
for(i = 0; i < length; i++) {
firstArray.push(secondArray[i])
}
return firstArray;
}
module.exports.socketCallback = socketCallback

View File

@ -0,0 +1,15 @@
var app = require('http').createServer()
var io = require('socket.io')(app);
app.listen(6979)
var acknowledgementsEvents = require("./acknowledgementEvents.js")
var emitEvents = require("./emitEvents.js")
var socketEventRegister = require("./socketEventRegister.js")
socketEventRegister.register(io, emitEvents.socketCallback, "Emit")
socketEventRegister.register(io, acknowledgementsEvents.socketCallback, "Acknowledgement")
var nsp = io.of("/swift")
socketEventRegister.register(nsp, emitEvents.socketCallback, "Emit")
socketEventRegister.register(nsp, acknowledgementsEvents.socketCallback, "Acknowledgement")

View File

@ -0,0 +1,14 @@
{
"name": "socket.io-client-swift-test-server",
"version": "0.0.1",
"description": "A simple server to test aginst",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Lukas Schmidt",
"license": "MIT",
"dependencies": {
"socket.io": "^1.3.6"
}
}

View File

@ -0,0 +1,13 @@
var testCases = require("./TestCases.js")
function registerSocketForEvents(ioSocket, socketCallback, testKind) {
ioSocket.on('connection', function(socket) {
var testCase;
for(testKey in testCases) {
testCase = testCases[testKey]
socket.on((testKey + testKind), socketCallback(testKey, socket, testCase))
}
})
}
module.exports.register = registerSocketForEvents

View File

@ -6,7 +6,7 @@
//
//
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
//! Project version number for SocketIO-Mac.
FOUNDATION_EXPORT double SocketIO_MacVersionNumber;

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,26 @@
//
// SocketAckManagerTest.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 04.09.15.
//
//
import XCTest
@testable import SocketIOClientSwift
class SocketAckManagerTest: XCTestCase {
var ackManager = SocketAckManager()
func testAddAcks() {
let callbackExpection = self.expectationWithDescription("callbackExpection")
let itemsArray = ["Hi", "ho"]
func callback(items: [AnyObject]) {
callbackExpection.fulfill()
}
ackManager.addAck(1, callback: callback)
ackManager.executeAck(1, items: itemsArray)
waitForExpectationsWithTimeout(3.0, handler: nil)
}
}

View File

@ -0,0 +1,140 @@
//
// SocketBasicPacketTest.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/7/15.
//
//
import XCTest
@testable import SocketIOClientSwift
class SocketBasicPacketTest: XCTestCase {
let data = "test".dataUsingEncoding(NSUTF8StringEncoding)!
let data2 = "test2".dataUsingEncoding(NSUTF8StringEncoding)!
func testEmpyEmit() {
let expectedSendString = "2[\"test\"]"
let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testNullEmit() {
let expectedSendString = "2[\"test\",null]"
let sendData = ["test", NSNull()]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testStringEmit() {
let expectedSendString = "2[\"test\",\"foo bar\"]"
let sendData = ["test", "foo bar"]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testJSONEmit() {
let expectedSendString = "2[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testArrayEmit() {
let expectedSendString = "2[\"test\",[\"hello\",1,{\"test\":\"test\"}]]"
let sendData = ["test", ["hello", 1, ["test": "test"]]]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testBinaryEmit() {
let expectedSendString = "51-[\"test\",{\"num\":0,\"_placeholder\":true}]"
let sendData = ["test", data]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data])
}
func testMultipleBinaryEmit() {
let expectedSendString = "52-[\"test\",{\"data1\":{\"num\":0,\"_placeholder\":true},\"data2\":{\"num\":1,\"_placeholder\":true}}]"
let sendData = ["test", ["data1": data, "data2": data2]]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data, data2])
}
func testEmitWithAck() {
let expectedSendString = "20[\"test\"]"
let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testEmitDataWithAck() {
let expectedSendString = "51-0[\"test\",{\"num\":0,\"_placeholder\":true}]"
let sendData = ["test", data]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data])
}
// Acks
func testEmptyAck() {
let expectedSendString = "30[]"
let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testNullAck() {
let expectedSendString = "30[null]"
let sendData = [NSNull()]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testStringAck() {
let expectedSendString = "30[\"test\"]"
let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testJSONAck() {
let expectedSendString = "30[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testBinaryAck() {
let expectedSendString = "61-0[{\"num\":0,\"_placeholder\":true}]"
let sendData = [data]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data])
}
func testMultipleBinaryAck() {
let expectedSendString = "62-0[{\"data2\":{\"num\":0,\"_placeholder\":true},\"data1\":{\"num\":1,\"_placeholder\":true}}]"
let sendData = [["data1": data, "data2": data2]]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data2, data])
}
}

View File

@ -0,0 +1,89 @@
//
// SocketEngineTest.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/15/15.
//
//
import XCTest
@testable import SocketIOClientSwift
class SocketEngineTest: XCTestCase {
var client: SocketIOClient!
var engine: SocketEngine!
override func setUp() {
super.setUp()
client = SocketIOClient(socketURL: NSURL(string: "http://localhost")!)
engine = SocketEngine(client: client, url: NSURL(string: "http://localhost")!, options: nil)
client.setTestable()
}
func testBasicPollingMessage() {
let expectation = expectationWithDescription("Basic polling test")
client.on("blankTest") {data, ack in
expectation.fulfill()
}
engine.parsePollingMessage("15:42[\"blankTest\"]")
waitForExpectationsWithTimeout(3, handler: nil)
}
func testTwoPacketsInOnePollTest() {
let finalExpectation = expectationWithDescription("Final packet in poll test")
var gotBlank = false
client.on("blankTest") {data, ack in
gotBlank = true
}
client.on("stringTest") {data, ack in
if let str = data[0] as? String where gotBlank {
if str == "hello" {
finalExpectation.fulfill()
}
}
}
engine.parsePollingMessage("15:42[\"blankTest\"]24:42[\"stringTest\",\"hello\"]")
waitForExpectationsWithTimeout(3, handler: nil)
}
func testEngineDoesErrorOnUnknownTransport() {
let finalExpectation = expectationWithDescription("Unknown Transport")
client.on("error") {data, ack in
if let error = data[0] as? String where error == "Unknown transport" {
finalExpectation.fulfill()
}
}
engine.parseEngineMessage("{\"code\": 0, \"message\": \"Unknown transport\"}", fromPolling: false)
waitForExpectationsWithTimeout(3, handler: nil)
}
func testEngineDoesErrorOnUnknownMessage() {
let finalExpectation = expectationWithDescription("Engine Errors")
client.on("error") {data, ack in
finalExpectation.fulfill()
}
engine.parseEngineMessage("afafafda", fromPolling: false)
waitForExpectationsWithTimeout(3, handler: nil)
}
func testEngineDecodesUTF8Properly() {
let expectation = expectationWithDescription("Engine Decodes utf8")
client.on("stringTest") {data, ack in
XCTAssertEqual(data[0] as? String, "lïne one\nlīne \rtwo", "Failed string test")
expectation.fulfill()
}
engine.parsePollingMessage("41:42[\"stringTest\",\"lïne one\\nlīne \\rtwo\"]")
waitForExpectationsWithTimeout(3, handler: nil)
}
}

View File

@ -0,0 +1,140 @@
//
// SocketNamespacePacketTest.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/11/15.
//
//
import XCTest
@testable import SocketIOClientSwift
class SocketNamespacePacketTest: XCTestCase {
let data = "test".dataUsingEncoding(NSUTF8StringEncoding)!
let data2 = "test2".dataUsingEncoding(NSUTF8StringEncoding)!
func testEmpyEmit() {
let expectedSendString = "2/swift,[\"test\"]"
let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testNullEmit() {
let expectedSendString = "2/swift,[\"test\",null]"
let sendData = ["test", NSNull()]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testStringEmit() {
let expectedSendString = "2/swift,[\"test\",\"foo bar\"]"
let sendData = ["test", "foo bar"]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testJSONEmit() {
let expectedSendString = "2/swift,[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testArrayEmit() {
let expectedSendString = "2/swift,[\"test\",[\"hello\",1,{\"test\":\"test\"}]]"
let sendData = ["test", ["hello", 1, ["test": "test"]]]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testBinaryEmit() {
let expectedSendString = "51-/swift,[\"test\",{\"num\":0,\"_placeholder\":true}]"
let sendData = ["test", data]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data])
}
func testMultipleBinaryEmit() {
let expectedSendString = "52-/swift,[\"test\",{\"data1\":{\"num\":0,\"_placeholder\":true},\"data2\":{\"num\":1,\"_placeholder\":true}}]"
let sendData = ["test", ["data1": data, "data2": data2]]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data, data2])
}
func testEmitWithAck() {
let expectedSendString = "2/swift,0[\"test\"]"
let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testEmitDataWithAck() {
let expectedSendString = "51-/swift,0[\"test\",{\"num\":0,\"_placeholder\":true}]"
let sendData = ["test", data]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data])
}
// Acks
func testEmptyAck() {
let expectedSendString = "3/swift,0[]"
let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/swift", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testNullAck() {
let expectedSendString = "3/swift,0[null]"
let sendData = [NSNull()]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testStringAck() {
let expectedSendString = "3/swift,0[\"test\"]"
let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testJSONAck() {
let expectedSendString = "3/swift,0[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
}
func testBinaryAck() {
let expectedSendString = "61-/swift,0[{\"num\":0,\"_placeholder\":true}]"
let sendData = [data]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data])
}
func testMultipleBinaryAck() {
let expectedSendString = "62-/swift,0[{\"data2\":{\"num\":0,\"_placeholder\":true},\"data1\":{\"num\":1,\"_placeholder\":true}}]"
let sendData = [["data1": data, "data2": data2]]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data2, data])
}
}

View File

@ -7,9 +7,26 @@
//
import XCTest
@testable import SocketIO
@testable import SocketIOClientSwift
class SocketParserTest: XCTestCase {
let testSocket = SocketIOClient(socketURL: NSURL())
//Format key: message; namespace-data-binary-id
static let packetTypes: Dictionary<String, (String, [AnyObject], [NSData], Int)> = [
"0": ("/", [], [], -1), "1": ("/", [], [], -1),
"25[\"test\"]": ("/", ["test"], [], 5),
"2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1),
"2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]": ("/swift", ["testArrayEmitReturn", ["test3", "test4"]], [], -1),
"51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", ["testMultipleItemsWithBufferEmitReturn", [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], -1),
"3/swift,0[[\"test3\",\"test4\"]]": ("/swift", [["test3", "test4"]], [], 0),
"61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", [ [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], 19),
"4/swift,": ("/swift", [], [], -1),
"0/swift": ("/swift", [], [], -1),
"1/swift": ("/swift", [], [], -1),
"4\"ERROR\"": ("/", ["ERROR"], [], -1),
"41": ("/", [1], [], -1)]
func testDisconnect() {
let message = "1"
validateParseResult(message)
@ -70,78 +87,50 @@ class SocketParserTest: XCTestCase {
validateParseResult(message)
}
func testErrorTypeDictionary() {
let message = "4{\"test\":2}"
validateParseResult(message)
}
func testErrorTypeInt() {
let message = "41"
validateParseResult(message)
}
func testErrorTypeArray() {
let message = "4[1, \"hello\"]"
validateParseResult(message)
}
func testInvalidInput() {
let message = "8"
do {
let _ = try testManager.parseString(message)
XCTFail()
} catch {
switch testSocket.parseString(message) {
case .Left(_):
return
case .Right(_):
XCTFail("Created packet when shouldn't have")
}
}
func testGenericParser() {
var parser = SocketStringReader(message: "61-/swift,")
XCTAssertEqual(parser.read(count: 1), "6")
XCTAssertEqual(parser.read(1), "6")
XCTAssertEqual(parser.currentCharacter, "1")
XCTAssertEqual(parser.readUntilOccurence(of: "-"), "1")
XCTAssertEqual(parser.readUntilStringOccurence("-"), "1")
XCTAssertEqual(parser.currentCharacter, "/")
}
func validateParseResult(_ message: String) {
func validateParseResult(message: String) {
let validValues = SocketParserTest.packetTypes[message]!
let packet = try! testManager.parseString(message)
let type = String(message.prefix(1))
XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
XCTAssertEqual(packet.nsp, validValues.0)
XCTAssertTrue((packet.data as NSArray).isEqual(to: validValues.1), "\(packet.data)")
XCTAssertTrue((packet.binary as NSArray).isEqual(to: validValues.2), "\(packet.binary)")
XCTAssertEqual(packet.id, validValues.3)
let packet = testSocket.parseString(message)
let type = message.substringWithRange(Range<String.Index>(start: message.startIndex, end: message.startIndex.advancedBy(1)))
if case let .Right(packet) = packet {
XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
XCTAssertEqual(packet.nsp, validValues.0)
XCTAssertTrue((packet.data as NSArray).isEqualToArray(validValues.1))
XCTAssertTrue((packet.binary as NSArray).isEqualToArray(validValues.2))
XCTAssertEqual(packet.id, validValues.3)
} else {
XCTFail()
}
}
func testParsePerformance() {
let keys = Array(SocketParserTest.packetTypes.keys)
measure {
for item in keys.enumerated() {
_ = try! self.testManager.parseString(item.element)
measureBlock({
for item in keys.enumerate() {
self.testSocket.parseString(item.element)
}
}
})
}
let testManager = SocketManager(socketURL: URL(string: "http://localhost/")!)
//Format key: message; namespace-data-binary-id
static let packetTypes: [String: (String, [Any], [Data], Int)] = [
"0": ("/", [], [], -1), "1": ("/", [], [], -1),
"25[\"test\"]": ("/", ["test"], [], 5),
"2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1),
"2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]": ("/swift", ["testArrayEmitReturn", ["test3", "test4"] as NSArray], [], -1),
"51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", ["testMultipleItemsWithBufferEmitReturn", [1, 2] as NSArray, ["test": "bob"] as NSDictionary, 25, "polo", ["_placeholder": true, "num": 0] as NSDictionary], [], -1),
"3/swift,0[[\"test3\",\"test4\"]]": ("/swift", [["test3", "test4"] as NSArray], [], 0),
"61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]":
("/swift", [ [1, 2] as NSArray, ["test": "bob"] as NSDictionary, 25, "polo", ["_placeholder": true, "num": 0] as NSDictionary], [], 19),
"4/swift,": ("/swift", [], [], -1),
"0/swift": ("/swift", [], [], -1),
"1/swift": ("/swift", [], [], -1),
"4\"ERROR\"": ("/", ["ERROR"], [], -1),
"4{\"test\":2}": ("/", [["test": 2]], [], -1),
"41": ("/", [1], [], -1),
"4[1, \"hello\"]": ("/", [1, "hello"], [], -1)
]
}

View File

@ -0,0 +1,145 @@
//
// SocketSideEffectTest.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/11/15.
//
//
import XCTest
@testable import SocketIOClientSwift
class SocketSideEffectTest: XCTestCase {
let data = "test".dataUsingEncoding(NSUTF8StringEncoding)!
let data2 = "test2".dataUsingEncoding(NSUTF8StringEncoding)!
private var socket: SocketIOClient!
override func setUp() {
super.setUp()
socket = SocketIOClient(socketURL: NSURL())
socket.setTestable()
}
func testInitialCurrentAck() {
XCTAssertEqual(socket.currentAck, -1)
}
func testFirstAck() {
socket.emitWithAck("test")(timeoutAfter: 0) {data in}
XCTAssertEqual(socket.currentAck, 0)
}
func testSecondAck() {
socket.emitWithAck("test")(timeoutAfter: 0) {data in}
socket.emitWithAck("test")(timeoutAfter: 0) {data in}
XCTAssertEqual(socket.currentAck, 1)
}
func testHandleAck() {
let expectation = expectationWithDescription("handled ack")
socket.emitWithAck("test")(timeoutAfter: 0) {data in
XCTAssertEqual(data[0] as? String, "hello world")
expectation.fulfill()
}
socket.parseSocketMessage("30[\"hello world\"]")
waitForExpectationsWithTimeout(3, handler: nil)
}
func testHandleAck2() {
let expectation = expectationWithDescription("handled ack2")
socket.emitWithAck("test")(timeoutAfter: 0) {data in
XCTAssertTrue(data.count == 2, "Wrong number of ack items")
expectation.fulfill()
}
socket.parseSocketMessage("61-0[{\"_placeholder\":true,\"num\":0},{\"test\":true}]")
socket.parseBinaryData(NSData())
waitForExpectationsWithTimeout(3, handler: nil)
}
func testHandleEvent() {
let expectation = expectationWithDescription("handled event")
socket.on("test") {data, ack in
XCTAssertEqual(data[0] as? String, "hello world")
expectation.fulfill()
}
socket.parseSocketMessage("2[\"test\",\"hello world\"]")
waitForExpectationsWithTimeout(3, handler: nil)
}
func testHandleOnceEvent() {
let expectation = expectationWithDescription("handled event")
socket.once("test") {data, ack in
XCTAssertEqual(data[0] as? String, "hello world")
XCTAssertEqual(self.socket.testHandlers.count, 0)
expectation.fulfill()
}
socket.parseSocketMessage("2[\"test\",\"hello world\"]")
waitForExpectationsWithTimeout(3, handler: nil)
}
func testOffWithEvent() {
socket.on("test") {data, ack in }
XCTAssertEqual(socket.testHandlers.count, 1)
socket.on("test") {data, ack in }
XCTAssertEqual(socket.testHandlers.count, 2)
socket.off("test")
XCTAssertEqual(socket.testHandlers.count, 0)
}
func testOffWithId() {
let handler = socket.on("test") {data, ack in }
XCTAssertEqual(socket.testHandlers.count, 1)
socket.on("test") {data, ack in }
XCTAssertEqual(socket.testHandlers.count, 2)
socket.off(id: handler)
XCTAssertEqual(socket.testHandlers.count, 1)
}
func testHandlesErrorPacket() {
let expectation = expectationWithDescription("Handled error")
socket.on("error") {data, ack in
if let error = data[0] as? String where error == "test error" {
expectation.fulfill()
}
}
socket.parseSocketMessage("4\"test error\"")
waitForExpectationsWithTimeout(3, handler: nil)
}
func testHandleBinaryEvent() {
let expectation = expectationWithDescription("handled binary event")
socket.on("test") {data, ack in
if let dict = data[0] as? NSDictionary, data = dict["test"] as? NSData {
XCTAssertEqual(data, self.data)
expectation.fulfill()
}
}
socket.parseSocketMessage("51-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]")
socket.parseBinaryData(data)
waitForExpectationsWithTimeout(3, handler: nil)
}
func testHandleMultipleBinaryEvent() {
let expectation = expectationWithDescription("handled multiple binary event")
socket.on("test") {data, ack in
if let dict = data[0] as? NSDictionary, data = dict["test"] as? NSData,
data2 = dict["test2"] as? NSData {
XCTAssertEqual(data, self.data)
XCTAssertEqual(data2, self.data2)
expectation.fulfill()
}
}
socket.parseSocketMessage("52-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0},\"test2\":{\"_placeholder\":true,\"num\":1}}]")
socket.parseBinaryData(data)
socket.parseBinaryData(data2)
waitForExpectationsWithTimeout(3, handler: nil)
}
}

26
SocketIO-iOS/Info.plist Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,19 @@
//
// SocketIO-iOS.h
// SocketIO-iOS
//
// Created by Nacho Soto on 7/11/15.
//
//
#import <UIKit/UIKit.h>
//! Project version number for SocketIO-iOS.
FOUNDATION_EXPORT double SocketIO_iOSVersionNumber;
//! Project version string for SocketIO-iOS.
FOUNDATION_EXPORT const unsigned char SocketIO_iOSVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <SocketIO_iOS/PublicHeader.h>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,47 @@
//
// SocketAckEmitter.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 9/16/15.
//
// 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
public final class SocketAckEmitter: NSObject {
let socket: SocketIOClient
let ackNum: Int
init(socket: SocketIOClient, ackNum: Int) {
self.socket = socket
self.ackNum = ackNum
}
public func with(items: AnyObject...) {
guard ackNum != -1 else { return }
socket.emitAck(ackNum, withItems: items)
}
public func with(items: [AnyObject]) {
guard ackNum != -1 else { return }
socket.emitAck(ackNum, withItems: items)
}
}

View File

@ -22,67 +22,53 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Dispatch
import Foundation
/// The status of an ack.
public enum SocketAckStatus : String {
// MARK: Cases
/// The ack timed out.
case noAck = "NO ACK"
/// Tests whether a string is equal to a given SocketAckStatus
public static func == (lhs: String, rhs: SocketAckStatus) -> Bool {
return lhs == rhs.rawValue
}
/// Tests whether a string is equal to a given SocketAckStatus
public static func == (lhs: SocketAckStatus, rhs: String) -> Bool {
return rhs == lhs
}
}
private struct SocketAck : Hashable {
private struct SocketAck: Hashable, Equatable {
let ack: Int
var callback: AckCallback!
var hashValue: Int {
return ack.hashValue
}
init(ack: Int) {
self.ack = ack
}
init(ack: Int, callback: @escaping AckCallback) {
init(ack: Int, callback: AckCallback) {
self.ack = ack
self.callback = callback
}
func hash(into hasher: inout Hasher) {
ack.hash(into: &hasher)
}
fileprivate static func <(lhs: SocketAck, rhs: SocketAck) -> Bool {
return lhs.ack < rhs.ack
}
fileprivate static func ==(lhs: SocketAck, rhs: SocketAck) -> Bool {
return lhs.ack == rhs.ack
}
}
class SocketAckManager {
private func <(lhs: SocketAck, rhs: SocketAck) -> Bool {
return lhs.ack < rhs.ack
}
private func ==(lhs: SocketAck, rhs: SocketAck) -> Bool {
return lhs.ack == rhs.ack
}
struct SocketAckManager {
private var acks = Set<SocketAck>(minimumCapacity: 1)
func addAck(_ ack: Int, callback: @escaping AckCallback) {
mutating func addAck(ack: Int, callback: AckCallback) {
acks.insert(SocketAck(ack: ack, callback: callback))
}
/// Should be called on handle queue
func executeAck(_ ack: Int, with items: [Any]) {
acks.remove(SocketAck(ack: ack))?.callback(items)
mutating func executeAck(ack: Int, items: [AnyObject]) {
let callback = acks.remove(SocketAck(ack: ack))
dispatch_async(dispatch_get_main_queue()) {
callback?.callback(items)
}
}
/// Should be called on handle queue
func timeoutAck(_ ack: Int) {
acks.remove(SocketAck(ack: ack))?.callback?([SocketAckStatus.noAck.rawValue])
mutating func timeoutAck(ack: Int) {
let callback = acks.remove(SocketAck(ack: ack))
dispatch_async(dispatch_get_main_queue()) {
callback?.callback(["NO ACK"])
}
}
}

View File

@ -24,24 +24,14 @@
import Foundation
/// Represents some event that was received.
public final class SocketAnyEvent : NSObject {
// MARK: Properties
/// The event name.
@objc
public final class SocketAnyEvent: NSObject {
public let event: String
/// The data items for this event.
@objc
public let items: [Any]?
/// The description of this event.
public let items: NSArray?
override public var description: String {
return "SocketAnyEvent: Event: \(event) items: \(String(describing: items))"
return "SocketAnyEvent: Event: \(event) items: \(items ?? nil)"
}
init(event: String, items: [Any]?) {
init(event: String, items: NSArray?) {
self.event = event
self.items = items
}

View File

@ -0,0 +1,43 @@
//
// SocketClientSpec.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 1/3/16.
//
// 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.
protocol SocketClientSpec: class {
var nsp: String { get set }
var waitingData: [SocketPacket] { get set }
func didConnect()
func didDisconnect(reason: String)
func didError(reason: String)
func handleAck(ack: Int, data: [AnyObject])
func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int)
func joinNamespace(namespace: String)
}
extension SocketClientSpec {
func didError(reason: String) {
DefaultSocketLogger.Logger.error("%@", type: "SocketIOClient", args: reason)
handleEvent("error", data: [reason], isInternalMessage: true, withAck: -1)
}
}

563
Source/SocketEngine.swift Normal file
View File

@ -0,0 +1,563 @@
//
// SocketEngine.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/3/15.
//
// 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
public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWebsocket {
public let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL)
public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL)
public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL)
public var connectParams: [String: AnyObject]? {
didSet {
(urlPolling, urlWebSocket) = createURLs()
}
}
public var postWait = [String]()
public var waitingForPoll = false
public var waitingForPost = false
public private(set) var closed = false
public private(set) var connected = false
public private(set) var cookies: [NSHTTPCookie]?
public private(set) var extraHeaders: [String: String]?
public private(set) var fastUpgrade = false
public private(set) var forcePolling = false
public private(set) var forceWebsockets = false
public private(set) var invalidated = false
public private(set) var pingTimer: NSTimer?
public private(set) var polling = true
public private(set) var probing = false
public private(set) var session: NSURLSession?
public private(set) var sid = ""
public private(set) var socketPath = "/engine.io/"
public private(set) var urlPolling = NSURL()
public private(set) var urlWebSocket = NSURL()
public private(set) var websocket = false
public private(set) var ws: WebSocket?
public weak var client: SocketEngineClient?
private weak var sessionDelegate: NSURLSessionDelegate?
private typealias Probe = (msg: String, type: SocketEnginePacketType, data: [NSData])
private typealias ProbeWaitQueue = [Probe]
private let logType = "SocketEngine"
private let url: NSURL
private var pingInterval: Double?
private var pingTimeout = 0.0 {
didSet {
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25))
}
}
private var pongsMissed = 0
private var pongsMissedMax = 0
private var probeWait = ProbeWaitQueue()
private var secure = false
private var selfSigned = false
private var voipEnabled = false
public init(client: SocketEngineClient, url: NSURL, options: Set<SocketIOClientOption>) {
self.client = client
self.url = url
for option in options {
switch option {
case let .ConnectParams(params):
connectParams = params
case let .SessionDelegate(delegate):
sessionDelegate = delegate
case let .ForcePolling(force):
forcePolling = force
case let .ForceWebsockets(force):
forceWebsockets = force
case let .Cookies(cookies):
self.cookies = cookies
case let .Path(path):
socketPath = path
case let .ExtraHeaders(headers):
extraHeaders = headers
case let .VoipEnabled(enable):
voipEnabled = enable
case let .Secure(secure):
self.secure = secure
case let .SelfSigned(selfSigned):
self.selfSigned = selfSigned
default:
continue
}
}
super.init()
(urlPolling, urlWebSocket) = createURLs()
}
public convenience init(client: SocketEngineClient, url: NSURL, options: NSDictionary?) {
self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? [])
}
@available(*, deprecated=5.3)
public convenience init(client: SocketEngineClient, urlString: String, options: Set<SocketIOClientOption>) {
guard let url = NSURL(string: urlString) else { fatalError("Incorrect url") }
self.init(client: client, url: url, options: options)
}
@available(*, deprecated=5.3)
public convenience init(client: SocketEngineClient, urlString: String, options: NSDictionary?) {
guard let url = NSURL(string: urlString) else { fatalError("Incorrect url") }
self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? [])
}
deinit {
DefaultSocketLogger.Logger.log("Engine is being released", type: logType)
closed = true
stopPolling()
}
private func checkAndHandleEngineError(msg: String) {
guard let stringData = msg.dataUsingEncoding(NSUTF8StringEncoding,
allowLossyConversion: false) else { return }
do {
if let dict = try NSJSONSerialization.JSONObjectWithData(stringData,
options: NSJSONReadingOptions.MutableContainers) as? NSDictionary {
guard let code = dict["code"] as? Int else { return }
guard let error = dict["message"] as? String else { return }
switch code {
case 0: // Unknown transport
didError(error)
case 1: // Unknown sid.
didError(error)
case 2: // Bad handshake request
didError(error)
case 3: // Bad request
didError(error)
default:
didError(error)
}
}
} catch {
didError("Got unknown error from server \(msg)")
}
}
private func checkIfMessageIsBase64Binary(message: String) -> Bool {
if message.hasPrefix("b4") {
// binary in base64 string
let noPrefix = message[message.startIndex.advancedBy(2)..<message.endIndex]
if let data = NSData(base64EncodedString: noPrefix,
options: .IgnoreUnknownCharacters) {
client?.parseEngineBinaryData(data)
}
return true
} else {
return false
}
}
public func close(reason: String) {
func postSendClose(data: NSData?, _ res: NSURLResponse?, _ err: NSError?) {
sid = ""
closed = true
invalidated = true
connected = false
pingTimer?.invalidate()
ws?.disconnect()
stopPolling()
client?.engineDidClose(reason)
}
DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType)
if websocket {
sendWebSocketMessage("", withType: .Close, withData: [])
postSendClose(nil, nil, nil)
} else {
// We need to take special care when we're polling that we send it ASAP
postWait.append(String(SocketEnginePacketType.Close.rawValue))
let req = createRequestForPostWithPostWait()
doRequest(req, withCallback: postSendClose)
}
}
private func createURLs() -> (NSURL, NSURL) {
if client == nil {
return (NSURL(), NSURL())
}
let urlPolling = NSURLComponents(string: url.absoluteString)!
let urlWebSocket = NSURLComponents(string: url.absoluteString)!
var queryString = ""
urlWebSocket.path = socketPath
urlPolling.path = socketPath
urlWebSocket.query = "transport=websocket"
urlPolling.query = "transport=polling&b64=1"
if secure {
urlPolling.scheme = "https"
urlWebSocket.scheme = "wss"
} else {
urlPolling.scheme = "http"
urlWebSocket.scheme = "ws"
}
if connectParams != nil {
for (key, value) in connectParams! {
queryString += "&\(key)=\(value)"
}
}
urlWebSocket.query = urlWebSocket.query! + queryString
urlPolling.query = urlPolling.query! + queryString
return (urlPolling.URL!, urlWebSocket.URL!)
}
private func createWebsocketAndConnect() {
ws = WebSocket(url: urlWebSocketWithSid)
if cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
for (key, value) in headers {
ws?.headers[key] = value
}
}
if extraHeaders != nil {
for (headerName, value) in extraHeaders! {
ws?.headers[headerName] = value
}
}
ws?.queue = handleQueue
ws?.voipEnabled = voipEnabled
ws?.delegate = self
ws?.selfSignedSSL = selfSigned
ws?.connect()
}
public func didError(error: String) {
DefaultSocketLogger.Logger.error(error, type: logType)
client?.engineDidError(error)
close(error)
}
public func doFastUpgrade() {
if waitingForPoll {
DefaultSocketLogger.Logger.error("Outstanding poll when switched to WebSockets," +
"we'll probably disconnect soon. You should report this.", type: logType)
}
sendWebSocketMessage("", withType: .Upgrade, withData: [])
websocket = true
polling = false
fastUpgrade = false
probing = false
flushProbeWait()
}
private func flushProbeWait() {
DefaultSocketLogger.Logger.log("Flushing probe wait", type: logType)
dispatch_async(emitQueue) {
for waiter in self.probeWait {
self.write(waiter.msg, withType: waiter.type, withData: waiter.data)
}
self.probeWait.removeAll(keepCapacity: false)
if self.postWait.count != 0 {
self.flushWaitingForPostToWebSocket()
}
}
}
// We had packets waiting for send when we upgraded
// Send them raw
public func flushWaitingForPostToWebSocket() {
guard let ws = self.ws else { return }
for msg in postWait {
ws.writeString(fixDoubleUTF8(msg))
}
postWait.removeAll(keepCapacity: true)
}
private func handleClose(reason: String) {
client?.engineDidClose(reason)
}
private func handleMessage(message: String) {
client?.parseEngineMessage(message)
}
private func handleNOOP() {
doPoll()
}
private func handleOpen(openData: String) {
let mesData = openData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(mesData,
options: NSJSONReadingOptions.AllowFragments) as? NSDictionary
if let sid = json?["sid"] as? String {
let upgradeWs: Bool
self.sid = sid
connected = true
if let upgrades = json?["upgrades"] as? [String] {
upgradeWs = upgrades.contains("websocket")
} else {
upgradeWs = false
}
if let pingInterval = json?["pingInterval"] as? Double, pingTimeout = json?["pingTimeout"] as? Double {
self.pingInterval = pingInterval / 1000.0
self.pingTimeout = pingTimeout / 1000.0
}
if !forcePolling && !forceWebsockets && upgradeWs {
createWebsocketAndConnect()
}
startPingTimer()
if !forceWebsockets {
doPoll()
}
client?.engineDidOpen?("Connect")
}
} catch {
didError("Error parsing open packet")
return
}
}
private func handlePong(pongMessage: String) {
pongsMissed = 0
// We should upgrade
if pongMessage == "3probe" {
upgradeTransport()
}
}
public func open() {
if connected {
DefaultSocketLogger.Logger.error("Engine tried opening while connected. This is probably a programming error. "
+ "Abandoning open attempt", type: logType)
return
}
DefaultSocketLogger.Logger.log("Starting engine", type: logType)
DefaultSocketLogger.Logger.log("Handshaking", type: logType)
resetEngine()
if forceWebsockets {
polling = false
websocket = true
createWebsocketAndConnect()
return
}
let reqPolling = NSMutableURLRequest(URL: urlPolling)
if cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
reqPolling.allHTTPHeaderFields = headers
}
if let extraHeaders = extraHeaders {
for (headerName, value) in extraHeaders {
reqPolling.setValue(value, forHTTPHeaderField: headerName)
}
}
doLongPoll(reqPolling)
}
public func parseEngineData(data: NSData) {
DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data)
client?.parseEngineBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
}
public func parseEngineMessage(message: String, fromPolling: Bool) {
DefaultSocketLogger.Logger.log("Got message: %@", type: logType, args: message)
let reader = SocketStringReader(message: message)
let fixedString: String
guard let type = SocketEnginePacketType(rawValue: Int(reader.currentCharacter) ?? -1) else {
if !checkIfMessageIsBase64Binary(message) {
checkAndHandleEngineError(message)
}
return
}
if fromPolling && type != .Noop {
fixedString = fixDoubleUTF8(message)
} else {
fixedString = message
}
switch type {
case .Message:
handleMessage(fixedString[fixedString.startIndex.successor()..<fixedString.endIndex])
case .Noop:
handleNOOP()
case .Pong:
handlePong(fixedString)
case .Open:
handleOpen(fixedString[fixedString.startIndex.successor()..<fixedString.endIndex])
case .Close:
handleClose(fixedString)
default:
DefaultSocketLogger.Logger.log("Got unknown packet type", type: logType)
}
}
private func resetEngine() {
closed = false
connected = false
fastUpgrade = false
polling = true
probing = false
invalidated = false
session = NSURLSession(configuration: .defaultSessionConfiguration(),
delegate: sessionDelegate,
delegateQueue: NSOperationQueue())
sid = ""
waitingForPoll = false
waitingForPost = false
websocket = false
}
@objc private func sendPing() {
//Server is not responding
if pongsMissed > pongsMissedMax {
pingTimer?.invalidate()
client?.engineDidClose("Ping timeout")
return
}
pongsMissed += 1
write("", withType: .Ping, withData: [])
}
// Starts the ping timer
private func startPingTimer() {
if let pingInterval = pingInterval {
pingTimer?.invalidate()
pingTimer = nil
dispatch_async(dispatch_get_main_queue()) {
self.pingTimer = NSTimer.scheduledTimerWithTimeInterval(pingInterval, target: self,
selector: Selector("sendPing"), userInfo: nil, repeats: true)
}
}
}
private func upgradeTransport() {
if ws?.isConnected ?? false {
DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: logType)
fastUpgrade = true
sendPollMessage("", withType: .Noop, withData: [])
// After this point, we should not send anymore polling messages
}
}
/**
Write a message, independent of transport.
*/
public func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData]) {
dispatch_async(emitQueue) {
guard self.connected else { return }
if self.websocket {
DefaultSocketLogger.Logger.log("Writing ws: %@ has data: %@",
type: self.logType, args: msg, data.count != 0)
self.sendWebSocketMessage(msg, withType: type, withData: data)
} else if !self.probing {
DefaultSocketLogger.Logger.log("Writing poll: %@ has data: %@",
type: self.logType, args: msg, data.count != 0)
self.sendPollMessage(msg, withType: type, withData: data)
} else {
self.probeWait.append((msg, type, data))
}
}
}
// Delegate methods
public func websocketDidConnect(socket: WebSocket) {
if !forceWebsockets {
probing = true
probeWebSocket()
} else {
connected = true
probing = false
polling = false
}
}
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
probing = false
if closed {
client?.engineDidClose("Disconnect")
return
}
if websocket {
pingTimer?.invalidate()
connected = false
websocket = false
let reason = error?.localizedDescription ?? "Socket Disconnected"
if error != nil {
didError(reason)
}
client?.engineDidClose(reason)
} else {
flushProbeWait()
}
}
}

View File

@ -0,0 +1,34 @@
//
// SocketEngineClient.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/19/15.
//
// 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
@objc public protocol SocketEngineClient {
func engineDidError(reason: String)
func engineDidClose(reason: String)
optional func engineDidOpen(reason: String)
func parseEngineMessage(msg: String)
func parseEngineBinaryData(data: NSData)
}

View File

@ -25,26 +25,6 @@
import Foundation
/// Represents the type of engine.io packet types.
@objc public enum SocketEnginePacketType: Int {
/// Open message.
case open
/// Close message.
case close
/// Ping message.
case ping
/// Pong message.
case pong
/// Regular message.
case message
/// Upgrade message.
case upgrade
/// NOOP.
case noop
case Open, Close, Ping, Pong, Message, Upgrade, Noop
}

View File

@ -0,0 +1,231 @@
//
// SocketEnginePollable.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 1/15/16.
//
// 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
/// Protocol that is used to implement socket.io polling support
public protocol SocketEnginePollable: SocketEngineSpec {
var invalidated: Bool { get }
/// Holds strings waiting to be sent over polling.
/// You shouldn't need to mess with this.
var postWait: [String] { get set }
var session: NSURLSession? { get }
/// Because socket.io doesn't let you send two polling request at the same time
/// we have to keep track if there's an outstanding poll
var waitingForPoll: Bool { get set }
/// Because socket.io doesn't let you send two post request at the same time
/// we have to keep track if there's an outstanding post
var waitingForPost: Bool { get set }
func doPoll()
func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData])
func stopPolling()
}
// Default polling methods
extension SocketEnginePollable {
private func addHeaders(req: NSMutableURLRequest) {
if cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
req.allHTTPHeaderFields = headers
}
if extraHeaders != nil {
for (headerName, value) in extraHeaders! {
req.setValue(value, forHTTPHeaderField: headerName)
}
}
}
func createRequestForPostWithPostWait() -> NSURLRequest {
var postStr = ""
for packet in postWait {
let len = packet.characters.count
postStr += "\(len):\(packet)"
}
DefaultSocketLogger.Logger.log("Created POST string: %@", type: "SocketEnginePolling", args: postStr)
postWait.removeAll(keepCapacity: false)
let req = NSMutableURLRequest(URL: urlPollingWithSid)
addHeaders(req)
req.HTTPMethod = "POST"
req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type")
let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding,
allowLossyConversion: false)!
req.HTTPBody = postData
req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length")
return req
}
public func doPoll() {
if websocket || waitingForPoll || !connected || closed {
return
}
waitingForPoll = true
let req = NSMutableURLRequest(URL: urlPollingWithSid)
addHeaders(req)
doLongPoll(req)
}
func doRequest(req: NSURLRequest, withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) {
if !polling || closed || invalidated {
DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEnginePolling")
return
}
DefaultSocketLogger.Logger.log("Doing polling request", type: "SocketEnginePolling")
session?.dataTaskWithRequest(req, completionHandler: callback).resume()
}
func doLongPoll(req: NSURLRequest) {
doRequest(req) {[weak self] data, res, err in
guard let this = self else { return }
if err != nil || data == nil {
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
if this.polling {
this.didError(err?.localizedDescription ?? "Error")
}
return
}
DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling")
if let str = String(data: data!, encoding: NSUTF8StringEncoding) {
dispatch_async(this.parseQueue) {
this.parsePollingMessage(str)
}
}
this.waitingForPoll = false
if this.fastUpgrade {
this.doFastUpgrade()
} else if !this.closed && this.polling {
this.doPoll()
}
}
}
private func flushWaitingForPost() {
if postWait.count == 0 || !connected {
return
} else if websocket {
flushWaitingForPostToWebSocket()
return
}
let req = createRequestForPostWithPostWait()
waitingForPost = true
DefaultSocketLogger.Logger.log("POSTing", type: "SocketEnginePolling")
doRequest(req) {[weak self] data, res, err in
guard let this = self else { return }
if err != nil {
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
if this.polling {
this.didError(err?.localizedDescription ?? "Error")
}
return
}
this.waitingForPost = false
dispatch_async(this.emitQueue) {
if !this.fastUpgrade {
this.flushWaitingForPost()
this.doPoll()
}
}
}
}
func parsePollingMessage(str: String) {
guard str.characters.count != 1 else {
return
}
var reader = SocketStringReader(message: str)
while reader.hasNext {
if let n = Int(reader.readUntilStringOccurence(":")) {
let str = reader.read(n)
dispatch_async(handleQueue) {
self.parseEngineMessage(str, fromPolling: true)
}
} else {
dispatch_async(handleQueue) {
self.parseEngineMessage(str, fromPolling: true)
}
break
}
}
}
/// Send polling message.
/// Only call on emitQueue
public func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) {
DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEnginePolling", args: message, type.rawValue)
let fixedMessage = doubleEncodeUTF8(message)
let strMsg = "\(type.rawValue)\(fixedMessage)"
postWait.append(strMsg)
for data in datas {
if case let .Right(bin) = createBinaryDataForSend(data) {
postWait.append(bin)
}
}
if !waitingForPost {
flushWaitingForPost()
}
}
public func stopPolling() {
waitingForPoll = false
waitingForPost = false
session?.finishTasksAndInvalidate()
}
}

View File

@ -0,0 +1,96 @@
//
// SocketEngineSpec.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/7/15.
//
// 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
@objc public protocol SocketEngineSpec {
weak var client: SocketEngineClient? { get set }
var closed: Bool { get }
var connected: Bool { get }
var connectParams: [String: AnyObject]? { get set }
var cookies: [NSHTTPCookie]? { get }
var extraHeaders: [String: String]? { get }
var fastUpgrade: Bool { get }
var forcePolling: Bool { get }
var forceWebsockets: Bool { get }
var parseQueue: dispatch_queue_t! { get }
var pingTimer: NSTimer? { get }
var polling: Bool { get }
var probing: Bool { get }
var emitQueue: dispatch_queue_t! { get }
var handleQueue: dispatch_queue_t! { get }
var sid: String { get }
var socketPath: String { get }
var urlPolling: NSURL { get }
var urlWebSocket: NSURL { get }
var websocket: Bool { get }
init(client: SocketEngineClient, url: NSURL, options: NSDictionary?)
func close(reason: String)
func didError(error: String)
func doFastUpgrade()
func flushWaitingForPostToWebSocket()
func open()
func parseEngineData(data: NSData)
func parseEngineMessage(message: String, fromPolling: Bool)
func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData])
}
extension SocketEngineSpec {
var urlPollingWithSid: NSURL {
let com = NSURLComponents(URL: urlPolling, resolvingAgainstBaseURL: false)!
com.query = com.query! + "&sid=\(sid)"
return com.URL!
}
var urlWebSocketWithSid: NSURL {
let com = NSURLComponents(URL: urlWebSocket, resolvingAgainstBaseURL: false)!
com.query = com.query! + (sid == "" ? "" : "&sid=\(sid)")
return com.URL!
}
func createBinaryDataForSend(data: NSData) -> Either<NSData, String> {
if websocket {
var byteArray = [UInt8](count: 1, repeatedValue: 0x4)
let mutData = NSMutableData(bytes: &byteArray, length: 1)
mutData.appendData(data)
return .Left(mutData)
} else {
let str = "b4" + data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
return .Right(str)
}
}
/// Send an engine message (4)
func send(msg: String, withData datas: [NSData]) {
write(msg, withType: .Message, withData: datas)
}
}

View File

@ -0,0 +1,64 @@
//
// SocketEngineWebsocket.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 1/15/16.
//
// 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
/// Protocol that is used to implement socket.io WebSocket support
public protocol SocketEngineWebsocket: SocketEngineSpec, WebSocketDelegate {
var ws: WebSocket? { get }
func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData])
}
// WebSocket methods
extension SocketEngineWebsocket {
func probeWebSocket() {
if ws?.isConnected ?? false {
sendWebSocketMessage("probe", withType: .Ping, withData: [])
}
}
/// Send message on WebSockets
/// Only call on emitQueue
public func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) {
DefaultSocketLogger.Logger.log("Sending ws: %@ as type: %@", type: "SocketEngine", args: str, type.rawValue)
ws?.writeString("\(type.rawValue)\(str)")
for data in datas {
if case let .Left(bin) = createBinaryDataForSend(data) {
ws?.writeData(bin)
}
}
}
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
parseEngineMessage(text, fromPolling: false)
}
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
parseEngineData(data)
}
}

View File

@ -24,27 +24,12 @@
import Foundation
/// A wrapper around a handler.
public struct SocketEventHandler {
// MARK: Properties
struct SocketEventHandler {
let event: String
let id: NSUUID
let callback: NormalCallback
/// The event for this handler.
public let event: String
/// A unique identifier for this handler.
public let id: UUID
/// The actual handler function.
public let callback: NormalCallback
// MARK: Methods
/// Causes this handler to be executed.
///
/// - parameter with: The data that this handler should be called with.
/// - parameter withAck: The ack number that this event expects. Pass -1 to say this event doesn't expect an ack.
/// - parameter withSocket: The socket that is calling this event.
public func executeCallback(with items: [Any], withAck ack: Int, withSocket socket: SocketIOClient) {
func executeCallback(items: [AnyObject], withAck ack: Int, withSocket socket: SocketIOClient) {
callback(items, SocketAckEmitter(socket: socket, ackNum: ack))
}
}

View File

@ -0,0 +1,44 @@
//
// SocketFixUTF8.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/16/15.
//
// 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
func fixDoubleUTF8(string: String) -> String {
if let utf8 = string.dataUsingEncoding(NSISOLatin1StringEncoding),
latin1 = NSString(data: utf8, encoding: NSUTF8StringEncoding) {
return latin1 as String
} else {
return string
}
}
func doubleEncodeUTF8(string: String) -> String {
if let latin1 = string.dataUsingEncoding(NSUTF8StringEncoding),
utf8 = NSString(data: latin1, encoding: NSISOLatin1StringEncoding) {
return utf8 as String
} else {
return string
}
}

View File

@ -1,146 +0,0 @@
//
// SocketAckEmitter.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 9/16/15.
//
// 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 Dispatch
import Foundation
/// A class that represents a waiting ack call.
///
/// **NOTE**: You should not store this beyond the life of the event handler.
public final class SocketAckEmitter: NSObject {
private unowned let socket: SocketIOClient
private let ackNum: Int
/// A view into this emitter where emits do not check for binary data.
///
/// Usage:
///
/// ```swift
/// ack.rawEmitView.with(myObject)
/// ```
///
/// **NOTE**: It is not safe to hold on to this view beyond the life of the socket.
@objc
public private(set) lazy var rawEmitView = SocketRawAckView(socket: socket, ackNum: ackNum)
// MARK: Properties
/// If true, this handler is expecting to be acked. Call `with(_: SocketData...)` to ack.
public var expected: Bool {
return ackNum != -1
}
// MARK: Initializers
/// Creates a new `SocketAckEmitter`.
///
/// - parameter socket: The socket for this emitter.
/// - parameter ackNum: The ack number for this emitter.
public init(socket: SocketIOClient, ackNum: Int) {
self.socket = socket
self.ackNum = ackNum
}
// MARK: Methods
/// Call to ack receiving this event.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[ackNum, items, theError]`
///
/// - parameter items: A variable number of items to send when acking.
public func with(_ items: SocketData...) {
guard ackNum != -1 else { return }
do {
socket.emitAck(ackNum, with: try items.map({ try $0.socketRepresentation() }))
} catch {
socket.handleClientEvent(.error, data: [ackNum, items, error])
}
}
/// Call to ack receiving this event.
///
/// - parameter items: An array of items to send when acking. Use `[]` to send nothing.
@objc
public func with(_ items: [Any]) {
guard ackNum != -1 else { return }
socket.emitAck(ackNum, with: items)
}
}
/// A class that represents an emit that will request an ack that has not yet been sent.
/// Call `timingOut(after:callback:)` to complete the emit
/// Example:
///
/// ```swift
/// socket.emitWithAck("myEvent").timingOut(after: 1) {data in
/// ...
/// }
/// ```
public final class OnAckCallback: NSObject {
private let ackNumber: Int
private let binary: Bool
private let items: [Any]
private weak var socket: SocketIOClient?
init(ackNumber: Int, items: [Any], socket: SocketIOClient, binary: Bool = true) {
self.ackNumber = ackNumber
self.items = items
self.socket = socket
self.binary = binary
}
/// :nodoc:
deinit {
DefaultSocketLogger.Logger.log("OnAckCallback for \(ackNumber) being released", type: "OnAckCallback")
}
// MARK: Methods
/// Completes an emitWithAck. If this isn't called, the emit never happens.
///
/// - parameter seconds: The number of seconds before this emit times out if an ack hasn't been received.
/// - parameter callback: The callback called when an ack is received, or when a timeout happens.
/// To check for timeout, use `SocketAckStatus`'s `noAck` case.
@objc
public func timingOut(after seconds: Double, callback: @escaping AckCallback) {
guard let socket = self.socket, ackNumber != -1 else { return }
socket.ackHandlers.addAck(ackNumber, callback: callback)
socket.emit(items, ack: ackNumber, binary: binary)
guard seconds != 0 else { return }
socket.manager?.handleQueue.asyncAfter(deadline: DispatchTime.now() + seconds) {[weak socket] in
guard let socket = socket else { return }
socket.ackHandlers.timeoutAck(self.ackNumber)
}
}
}

View File

@ -1,549 +0,0 @@
//
// SocketIOClient.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 11/23/14.
//
// 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 Dispatch
import Foundation
/// Represents a socket.io-client.
///
/// Clients are created through a `SocketManager`, which owns the `SocketEngineSpec` that controls the connection to the server.
///
/// For example:
///
/// ```swift
/// // Create a socket for the /swift namespace
/// let socket = manager.socket(forNamespace: "/swift")
///
/// // Add some handlers and connect
/// ```
///
/// **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 {
// MARK: Properties
/// The namespace that this socket is currently connected to.
///
/// **Must** start with a `/`.
public let nsp: String
/// A handler that will be called on any event.
public private(set) var anyHandler: ((SocketAnyEvent) -> ())?
/// The array of handlers for this socket.
public private(set) var handlers = [SocketEventHandler]()
/// The manager for this socket.
public private(set) weak var manager: SocketManagerSpec?
/// A view into this socket where emits do not check for binary data.
///
/// Usage:
///
/// ```swift
/// socket.rawEmitView.emit("myEvent", myObject)
/// ```
///
/// **NOTE**: It is not safe to hold on to this view beyond the life of the socket.
public private(set) lazy var rawEmitView = SocketRawView(socket: self)
/// The status of this client.
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()
var connectPayload: [String: Any]?
private(set) var currentAck = -1
private lazy var logType = "SocketIOClient{\(nsp)}"
// MARK: Initializers
/// Type safe way to create a new SocketIOClient. `opts` can be omitted.
///
/// - parameter manager: The manager for this socket.
/// - parameter nsp: The namespace of the socket.
public init(manager: SocketManagerSpec, nsp: String) {
self.manager = manager
self.nsp = nsp
super.init()
}
/// :nodoc:
deinit {
DefaultSocketLogger.Logger.log("Client is being released", type: logType)
}
// MARK: Methods
/// 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.
///
/// - parameter withPayload: An optional payload sent on connect
open func connect(withPayload payload: [String: Any]? = nil) {
connect(withPayload: payload, timeoutAfter: 0, withHandler: nil)
}
/// Connect to the server. If we aren't connected after `timeoutAfter` seconds, then `withHandler` is called.
///
/// Only call after adding your event listeners, unless you know what you're doing.
///
/// - parameter withPayload: An optional payload sent on connect
/// - 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.
open func connect(withPayload payload: [String: Any]? = nil, timeoutAfter: Double, withHandler handler: (() -> ())?) {
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
guard let manager = self.manager, status != .connected else {
DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket", type: logType)
return
}
status = .connecting
joinNamespace(withPayload: payload)
switch manager.version {
case .three:
break
case .two where manager.status == .connected && nsp == "/":
// We might not get a connect event for the default nsp, fire immediately
didConnect(toNamespace: nsp, payload: nil)
return
case _:
break
}
guard timeoutAfter != 0 else { return }
manager.handleQueue.asyncAfter(deadline: DispatchTime.now() + timeoutAfter) {[weak self] in
guard let this = self, this.status == .connecting || this.status == .notConnected else { return }
DefaultSocketLogger.Logger.log("Timeout: Socket not connected, so setting to disconnected", type: this.logType)
this.status = .disconnected
this.leaveNamespace()
handler?()
}
}
func createOnAck(_ items: [Any], binary: Bool = true) -> OnAckCallback {
currentAck += 1
return OnAckCallback(ackNumber: currentAck, items: items, socket: self)
}
/// Called when the client connects to a namespace. If the client was created with a namespace upfront,
/// 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, 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: payload == nil ? [namespace] : [namespace, payload!])
}
/// Called when the client has disconnected from socket.io.
///
/// - parameter reason: The reason for the disconnection.
open func didDisconnect(reason: String) {
guard status != .disconnected else { return }
DefaultSocketLogger.Logger.log("Disconnected: \(reason)", type: logType)
status = .disconnected
sid = ""
handleClientEvent(.disconnect, data: [reason])
}
/// Disconnects the socket.
///
/// This will cause the socket to leave the namespace it is associated to, as well as remove itself from the
/// `manager`.
open func disconnect() {
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
leaveNamespace()
}
/// Send an event to the server, with optional data items and optional write completion handler.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
/// - parameter completion: Callback called on transport write completion.
open func emit(_ event: String, _ items: SocketData..., completion: (() -> ())? = nil) {
emit(event, with: items, completion: completion)
}
/// Send an event to the server, with optional data items and optional write completion handler.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
/// - parameter completion: Callback called on transport write completion.
open func emit(_ event: String, with items: [SocketData], completion: (() -> ())?) {
do {
emit([event] + (try items.map({ try $0.socketRepresentation() })), completion: completion)
} catch {
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
type: logType)
handleClientEvent(.error, data: [event, items, error])
}
}
/// 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.
/// Check that your server's api will ack the event being sent.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// Example:
///
/// ```swift
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
/// ...
/// }
/// ```
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
emitWithAck(event, with: items)
}
/// 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.
/// Check that your server's api will ack the event being sent.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// Example:
///
/// ```swift
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
/// ...
/// }
/// ```
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
open func emitWithAck(_ event: String, with items: [SocketData]) -> OnAckCallback {
do {
return createOnAck([event] + (try items.map({ try $0.socketRepresentation() })))
} catch {
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
type: logType)
handleClientEvent(.error, data: [event, items, error])
return OnAckCallback(ackNumber: -1, items: [], socket: self)
}
}
func emit(_ data: [Any],
ack: Int? = nil,
binary: Bool = true,
isAck: Bool = false,
completion: (() -> ())? = nil
) {
// wrap the completion handler so it always runs async via handlerQueue
let wrappedCompletion: (() -> ())? = (completion == nil) ? nil : {[weak self] in
guard let this = self else { return }
this.manager?.handleQueue.async {
completion!()
}
}
guard status == .connected else {
wrappedCompletion?()
handleClientEvent(.error, data: ["Tried emitting when not connected"])
return
}
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: isAck, checkForBinary: binary)
let str = packet.packetString
DefaultSocketLogger.Logger.log("Emitting: \(str), Ack: \(isAck)", type: logType)
manager?.engine?.send(str, withData: packet.binary, completion: wrappedCompletion)
}
/// Call when you wish to tell the server that you've received the event for `ack`.
///
/// **You shouldn't need to call this directly.** Instead use an `SocketAckEmitter` that comes in an event callback.
///
/// - parameter ack: The ack number.
/// - parameter with: The data for this ack.
open func emitAck(_ ack: Int, with items: [Any]) {
emit(items, ack: ack, binary: true, isAck: true)
}
/// Called when socket.io has acked one of our emits. Causes the corresponding ack callback to be called.
///
/// - parameter ack: The number for this ack.
/// - parameter data: The data sent back with this ack.
open func handleAck(_ ack: Int, data: [Any]) {
guard status == .connected else { return }
DefaultSocketLogger.Logger.log("Handling ack: \(ack) with data: \(data)", type: logType)
ackHandlers.executeAck(ack, with: data)
}
/// Called on socket.io specific events.
///
/// - parameter event: The `SocketClientEvent`.
/// - parameter data: The data for this event.
open func handleClientEvent(_ event: SocketClientEvent, data: [Any]) {
handleEvent(event.rawValue, data: data, isInternalMessage: true)
}
/// Called when we get an event from socket.io.
///
/// - parameter event: The name of the 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 ack: If > 0 then this event expects to get an ack back from the client.
open func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int = -1) {
guard status == .connected || isInternalMessage else { return }
DefaultSocketLogger.Logger.log("Handling event: \(event) with data: \(data)", type: logType)
anyHandler?(SocketAnyEvent(event: event, items: data))
for handler in handlers where handler.event == event {
handler.executeCallback(with: data, withAck: ack, withSocket: self)
}
}
/// Causes a client to handle a socket.io packet. The namespace for the packet must match the namespace of the
/// socket.
///
/// - parameter packet: The packet to handle.
open func handlePacket(_ packet: SocketPacket) {
guard packet.nsp == nsp else { return }
switch packet.type {
case .event, .binaryEvent:
handleEvent(packet.event, data: packet.args, isInternalMessage: false, withAck: packet.id)
case .ack, .binaryAck:
handleAck(packet.id, data: packet.data)
case .connect:
didConnect(toNamespace: nsp, payload: packet.data.isEmpty ? nil : packet.data[0] as? [String: Any])
case .disconnect:
didDisconnect(reason: "Got Disconnect")
case .error:
handleEvent("error", data: packet.data, isInternalMessage: true, withAck: packet.id)
}
}
/// Call when you wish to leave a namespace and disconnect this socket.
open func leaveNamespace() {
manager?.disconnectSocket(self)
}
/// Joins `nsp`. You shouldn't need to call this directly, instead call `connect`.
///
/// - parameter withPayload: An optional payload sent on connect
open func joinNamespace(withPayload payload: [String: Any]? = nil) {
DefaultSocketLogger.Logger.log("Joining namespace \(nsp)", type: logType)
connectPayload = payload
manager?.connectSocket(self, withPayload: connectPayload)
}
/// Removes handler(s) for a client event.
///
/// If you wish to remove a client event handler, call the `off(id:)` with the UUID received from its `on` call.
///
/// - parameter clientEvent: The event to remove handlers for.
open func off(clientEvent event: SocketClientEvent) {
off(event.rawValue)
}
/// Removes handler(s) based on an event name.
///
/// 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.
open func off(_ event: String) {
DefaultSocketLogger.Logger.log("Removing handler for event: \(event)", type: logType)
handlers = handlers.filter({ $0.event != event })
}
/// Removes a handler with the specified UUID gotten from an `on` or `once`
///
/// 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.
open func off(id: UUID) {
DefaultSocketLogger.Logger.log("Removing handler with id: \(id)", type: logType)
handlers = handlers.filter({ $0.id != id })
}
/// Adds a handler for an event.
///
/// - 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.
@discardableResult
open func on(_ event: String, callback: @escaping NormalCallback) -> UUID {
DefaultSocketLogger.Logger.log("Adding handler for event: \(event)", type: logType)
let handler = SocketEventHandler(event: event, id: UUID(), callback: callback)
handlers.append(handler)
return handler.id
}
/// Adds a handler for a client event.
///
/// Example:
///
/// ```swift
/// socket.on(clientEvent: .connect) {data, ack in
/// ...
/// }
/// ```
///
/// - parameter event: The event 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.
@discardableResult
open func on(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID {
return on(event.rawValue, callback: callback)
}
/// Adds a single-use handler for a client event.
///
/// - parameter clientEvent: The event 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.
@discardableResult
open func once(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID {
return once(event.rawValue, callback: callback)
}
/// Adds a single-use handler for an event.
///
/// - 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.
@discardableResult
open func once(_ event: String, callback: @escaping NormalCallback) -> UUID {
DefaultSocketLogger.Logger.log("Adding once handler for event: \(event)", type: logType)
let id = UUID()
let handler = SocketEventHandler(event: event, id: id) {[weak self] data, ack in
guard let this = self else { return }
this.off(id: id)
callback(data, ack)
}
handlers.append(handler)
return handler.id
}
/// Adds a handler that will be called on every event.
///
/// - parameter handler: The callback that will execute whenever an event is received.
open func onAny(_ handler: @escaping (SocketAnyEvent) -> ()) {
anyHandler = handler
}
/// Tries to reconnect to the server.
@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.
open func removeAllHandlers() {
handlers.removeAll(keepingCapacity: false)
}
/// Puts the socket back into the connecting state.
/// Called when the manager detects a broken connection, or when a manual reconnect is triggered.
///
/// - parameter reason: The reason this socket is reconnecting.
open func setReconnecting(reason: String) {
status = .connecting
handleClientEvent(.reconnect, data: [reason])
}
// Test properties
var testHandlers: [SocketEventHandler] {
return handlers
}
func setTestable() {
status = .connected
}
func setTestStatus(_ status: SocketIOStatus) {
self.status = status
}
func emitTest(event: String, _ data: Any...) {
emit([event] + data)
}
}

View File

@ -1,138 +0,0 @@
//
// SocketIOClientConfiguration.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 8/13/16.
//
// 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.
/// An array-like type that holds `SocketIOClientOption`s
public struct SocketIOClientConfiguration : ExpressibleByArrayLiteral, Collection, MutableCollection {
// MARK: Typealiases
/// Type of element stored.
public typealias Element = SocketIOClientOption
/// Index type.
public typealias Index = Array<SocketIOClientOption>.Index
/// Iterator type.
public typealias Iterator = Array<SocketIOClientOption>.Iterator
/// SubSequence type.
public typealias SubSequence = Array<SocketIOClientOption>.SubSequence
// MARK: Properties
private var backingArray = [SocketIOClientOption]()
/// The start index of this collection.
public var startIndex: Index {
return backingArray.startIndex
}
/// The end index of this collection.
public var endIndex: Index {
return backingArray.endIndex
}
/// Whether this collection is empty.
public var isEmpty: Bool {
return backingArray.isEmpty
}
/// The number of elements stored in this collection.
public var count: Index.Stride {
return backingArray.count
}
/// The first element in this collection.
public var first: Element? {
return backingArray.first
}
public subscript(position: Index) -> Element {
get {
return backingArray[position]
}
set {
backingArray[position] = newValue
}
}
public subscript(bounds: Range<Index>) -> SubSequence {
get {
return backingArray[bounds]
}
set {
backingArray[bounds] = newValue
}
}
// MARK: Initializers
/// Creates a new `SocketIOClientConfiguration` from an array literal.
///
/// - parameter arrayLiteral: The elements.
public init(arrayLiteral elements: Element...) {
backingArray = elements
}
// MARK: Methods
/// Creates an iterator for this collection.
///
/// - returns: An iterator over this collection.
public func makeIterator() -> Iterator {
return backingArray.makeIterator()
}
/// - returns: The index after index.
public func index(after i: Index) -> Index {
return backingArray.index(after: i)
}
/// Special method that inserts `element` into the collection, replacing any other instances of `element`.
///
/// - parameter element: The element to insert.
/// - parameter replacing: Whether to replace any occurrences of element to the new item. Default is `true`.
public mutating func insert(_ element: Element, replacing replace: Bool = true) {
for i in 0..<backingArray.count where backingArray[i] == element {
guard replace else { return }
backingArray[i] = element
return
}
backingArray.append(element)
}
}
/// Declares that a type can set configs from a `SocketIOClientConfiguration`.
public protocol ConfigSettable {
// MARK: Methods
/// Called when an `ConfigSettable` should set/update its configs from a given configuration.
///
/// - parameter config: The `SocketIOClientConfiguration` that should be used to set/update configs.
mutating func setConfigs(_ config: SocketIOClientConfiguration)
}

View File

@ -1,241 +0,0 @@
//
// SocketIOClientOption .swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/17/15.
//
// 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
/// The socket.io version being used.
public enum SocketIOVersion: Int {
/// socket.io 2, engine.io 3
case two = 2
/// socket.io 3, engine.io 4
case three = 3
}
protocol ClientOption : CustomStringConvertible, Equatable {
func getSocketIOOptionValue() -> Any
}
/// The options for a client.
public enum SocketIOClientOption : ClientOption {
/// If given, the WebSocket transport will attempt to use compression.
case compress
/// A dictionary of GET parameters that will be included in the connect url.
case connectParams([String: Any])
/// An array of cookies that will be sent during the initial connection.
case cookies([HTTPCookie])
/// Any extra HTTP headers that should be sent during the initial connection.
case extraHeaders([String: String])
/// If passed `true`, will cause the client to always create a new engine. Useful for debugging,
/// or when you want to be sure no state from previous engines is being carried over.
case forceNew(Bool)
/// If passed `true`, the only transport that will be used will be HTTP long-polling.
case forcePolling(Bool)
/// If passed `true`, the only transport that will be used will be WebSockets.
case forceWebsockets(Bool)
/// If passed `true`, the WebSocket stream will be configured with the enableSOCKSProxy `true`.
case enableSOCKSProxy(Bool)
/// The queue that all interaction with the client should occur on. This is the queue that event handlers are
/// called on.
///
/// **This should be a serial queue! Concurrent queues are not supported and might cause crashes and races**.
case handleQueue(DispatchQueue)
/// If passed `true`, the client will log debug information. This should be turned off in production code.
case log(Bool)
/// Used to pass in a custom logger.
case logger(SocketLogger)
/// A custom path to socket.io. Only use this if the socket.io server is configured to look for this path.
case path(String)
/// If passed `false`, the client will not reconnect when it loses connection. Useful if you want full control
/// over when reconnects happen.
case reconnects(Bool)
/// The number of times to try and reconnect before giving up. Pass `-1` to [never give up](https://www.youtube.com/watch?v=dQw4w9WgXcQ).
case reconnectAttempts(Int)
/// The minimum number of seconds to wait before reconnect attempts.
case reconnectWait(Int)
/// The maximum number of seconds to wait before reconnect attempts.
case reconnectWaitMax(Int)
/// The randomization factor for calculating reconnect jitter.
case randomizationFactor(Double)
/// Set `true` if your server is using secure transports.
case secure(Bool)
/// Allows you to set which certs are valid. Useful for SSL pinning.
case security(CertificatePinning)
/// If you're using a self-signed set. Only use for development.
case selfSigned(Bool)
/// Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs.
case sessionDelegate(URLSessionDelegate)
/// If passed `false`, the WebSocket stream will be configured with the useCustomEngine `false`.
case useCustomEngine(Bool)
/// The version of socket.io being used. This should match the server version. Default is 3.
case version(SocketIOVersion)
// MARK: Properties
/// The description of this option.
public var description: String {
let description: String
switch self {
case .compress:
description = "compress"
case .connectParams:
description = "connectParams"
case .cookies:
description = "cookies"
case .extraHeaders:
description = "extraHeaders"
case .forceNew:
description = "forceNew"
case .forcePolling:
description = "forcePolling"
case .forceWebsockets:
description = "forceWebsockets"
case .handleQueue:
description = "handleQueue"
case .log:
description = "log"
case .logger:
description = "logger"
case .path:
description = "path"
case .reconnects:
description = "reconnects"
case .reconnectAttempts:
description = "reconnectAttempts"
case .reconnectWait:
description = "reconnectWait"
case .reconnectWaitMax:
description = "reconnectWaitMax"
case .randomizationFactor:
description = "randomizationFactor"
case .secure:
description = "secure"
case .selfSigned:
description = "selfSigned"
case .security:
description = "security"
case .sessionDelegate:
description = "sessionDelegate"
case .enableSOCKSProxy:
description = "enableSOCKSProxy"
case .useCustomEngine:
description = "customEngine"
case .version:
description = "version"
}
return description
}
func getSocketIOOptionValue() -> Any {
let value: Any
switch self {
case .compress:
value = true
case let .connectParams(params):
value = params
case let .cookies(cookies):
value = cookies
case let .extraHeaders(headers):
value = headers
case let .forceNew(force):
value = force
case let .forcePolling(force):
value = force
case let .forceWebsockets(force):
value = force
case let .handleQueue(queue):
value = queue
case let .log(log):
value = log
case let .logger(logger):
value = logger
case let .path(path):
value = path
case let .reconnects(reconnects):
value = reconnects
case let .reconnectAttempts(attempts):
value = attempts
case let .reconnectWait(wait):
value = wait
case let .reconnectWaitMax(wait):
value = wait
case let .randomizationFactor(factor):
value = factor
case let .secure(secure):
value = secure
case let .security(security):
value = security
case let .selfSigned(signed):
value = signed
case let .sessionDelegate(delegate):
value = delegate
case let .enableSOCKSProxy(enable):
value = enable
case let .useCustomEngine(enable):
value = enable
case let.version(versionNum):
value = versionNum
}
return value
}
// MARK: Operators
/// Compares whether two options are the same.
///
/// - parameter lhs: Left operand to compare.
/// - parameter rhs: Right operand to compare.
/// - returns: `true` if the two are the same option.
public static func ==(lhs: SocketIOClientOption, rhs: SocketIOClientOption) -> Bool {
return lhs.description == rhs.description
}
}

View File

@ -1,392 +0,0 @@
//
// SocketIOClientSpec.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 1/3/16.
//
// 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 Dispatch
import Foundation
/// Defines the interface for a SocketIOClient.
public protocol SocketIOClientSpec : AnyObject {
// MARK: Properties
/// A handler that will be called on any event.
var anyHandler: ((SocketAnyEvent) -> ())? { get }
/// The array of handlers for this socket.
var handlers: [SocketEventHandler] { get }
/// The manager for this socket.
var manager: SocketManagerSpec? { get }
/// The namespace that this socket is currently connected to.
///
/// **Must** start with a `/`.
var nsp: String { get }
/// A view into this socket where emits do not check for binary data.
///
/// Usage:
///
/// ```swift
/// socket.rawEmitView.emit("myEvent", myObject)
/// ```
///
/// **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 }
// MARK: Methods
/// 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.
///
/// - parameter payload: An optional payload sent on connect
func connect(withPayload payload: [String: Any]?)
/// Connect to the server. If we aren't connected after `timeoutAfter` seconds, then `withHandler` is called.
///
/// Only call after adding your event listeners, unless you know what you're doing.
///
/// - parameter withPayload: An optional payload sent on connect
/// - 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.
func connect(withPayload payload: [String: Any]?, timeoutAfter: Double, withHandler handler: (() -> ())?)
/// Called when the client connects to a namespace. If the client was created with a namespace upfront,
/// 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, payload: [String: Any]?)
/// Called when the client has disconnected from socket.io.
///
/// - parameter reason: The reason for the disconnection.
func didDisconnect(reason: String)
/// Called when the client encounters an error.
///
/// - parameter reason: The reason for the disconnection.
func didError(reason: String)
/// Disconnects the socket.
func disconnect()
/// Send an event to the server, with optional data items and optional write completion handler.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
/// - parameter completion: Callback called on transport write completion.
func emit(_ event: String, _ items: SocketData..., completion: (() -> ())?)
/// Send an event to the server, with optional data items and optional write completion handler.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
/// - parameter completion: Callback called on transport write completion.
func emit(_ event: String, with items: [SocketData], completion: (() -> ())?)
/// Call when you wish to tell the server that you've received the event for `ack`.
///
/// - parameter ack: The ack number.
/// - parameter with: The data for this ack.
func emitAck(_ ack: Int, with items: [Any])
/// 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.
/// Check that your server's api will ack the event being sent.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// Example:
///
/// ```swift
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
/// ...
/// }
/// ```
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback
/// 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.
/// Check that your server's api will ack the event being sent.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// Example:
///
/// ```swift
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
/// ...
/// }
/// ```
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
func emitWithAck(_ event: String, with items: [SocketData]) -> OnAckCallback
/// Called when socket.io has acked one of our emits. Causes the corresponding ack callback to be called.
///
/// - parameter ack: The number for this ack.
/// - parameter data: The data sent back with this ack.
func handleAck(_ ack: Int, data: [Any])
/// Called on socket.io specific events.
///
/// - parameter event: The `SocketClientEvent`.
/// - parameter data: The data for this event.
func handleClientEvent(_ event: SocketClientEvent, data: [Any])
/// Called when we get an event from socket.io.
///
/// - parameter event: The name of the 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 ack: If > 0 then this event expects to get an ack back from the client.
func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int)
/// Causes a client to handle a socket.io packet. The namespace for the packet must match the namespace of the
/// socket.
///
/// - parameter packet: The packet to handle.
func handlePacket(_ packet: SocketPacket)
/// Call when you wish to leave a namespace and disconnect this socket.
func leaveNamespace()
/// Joins `nsp`. You shouldn't need to call this directly, instead call `connect`.
///
/// - Parameter withPayload: The payload to connect when joining this namespace
func joinNamespace(withPayload payload: [String: Any]?)
/// Removes handler(s) for a client event.
///
/// If you wish to remove a client event handler, call the `off(id:)` with the UUID received from its `on` call.
///
/// - parameter clientEvent: The event to remove handlers for.
func off(clientEvent event: SocketClientEvent)
/// Removes handler(s) based on an event name.
///
/// 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.
func off(_ event: String)
/// Removes a handler with the specified UUID gotten from an `on` or `once`
///
/// 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.
func off(id: UUID)
/// Adds a handler for an event.
///
/// - 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.
func on(_ event: String, callback: @escaping NormalCallback) -> UUID
/// Adds a handler for a client event.
///
/// Example:
///
/// ```swift
/// socket.on(clientEvent: .connect) {data, ack in
/// ...
/// }
/// ```
///
/// - parameter event: The event 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.
func on(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID
/// Adds a single-use handler for a client event.
///
/// - parameter clientEvent: The event 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.
func once(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID
/// Adds a single-use handler for an event.
///
/// - 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.
func once(_ event: String, callback: @escaping NormalCallback) -> UUID
/// Adds a handler that will be called on every event.
///
/// - parameter handler: The callback that will execute whenever an event is received.
func onAny(_ handler: @escaping (SocketAnyEvent) -> ())
/// Removes all handlers.
///
/// Can be used after disconnecting to break any potential remaining retain cycles.
func removeAllHandlers()
/// Puts the socket back into the connecting state.
/// Called when the manager detects a broken connection, or when a manual reconnect is triggered.
///
/// parameter reason: The reason this socket is going reconnecting.
func setReconnecting(reason: String)
}
public extension SocketIOClientSpec {
/// Default implementation.
func didError(reason: String) {
DefaultSocketLogger.Logger.error("\(reason)", type: "SocketIOClient")
handleClientEvent(.error, data: [reason])
}
}
/// The set of events that are generated by the client.
public enum SocketClientEvent : String {
// MARK: Cases
/// Emitted when the client connects. This is also called on a successful reconnection. A connect event gets one
/// data item: the namespace that was connected to.
///
/// ```swift
/// socket.on(clientEvent: .connect) {data, ack in
/// guard let nsp = data[0] as? String else { return }
/// // Some logic using the nsp
/// }
/// ```
case connect
/// Emitted when the socket has disconnected and will not attempt to try to reconnect.
///
/// Usage:
///
/// ```swift
/// socket.on(clientEvent: .disconnect) {data, ack in
/// // Some cleanup logic
/// }
/// ```
case disconnect
/// Emitted when an error occurs.
///
/// Usage:
///
/// ```swift
/// socket.on(clientEvent: .error) {data, ack in
/// // Some logging
/// }
/// ```
case error
/// Emitted whenever the engine sends a ping.
///
/// Usage:
///
/// ```swift
/// socket.on(clientEvent: .ping) {_, _ in
/// // Maybe keep track of latency?
/// }
/// ```
case ping
/// Emitted whenever the engine gets a pong.
///
/// Usage:
///
/// ```swift
/// socket.on(clientEvent: .pong) {_, _ in
/// // Maybe keep track of latency?
/// }
/// ```
case pong
/// Emitted when the client begins the reconnection process.
///
/// Usage:
///
/// ```swift
/// socket.on(clientEvent: .reconnect) {data, ack in
/// // Some reconnect event logic
/// }
/// ```
case reconnect
/// Emitted each time the client tries to reconnect to the server.
///
/// Usage:
///
/// ```swift
/// socket.on(clientEvent: .reconnectAttempt) {data, ack in
/// // Some reconnect attempt logging
/// }
/// ```
case reconnectAttempt
/// Emitted every time there is a change in the client's status.
///
/// The payload for data is [SocketIOClientStatus, Int]. Where the second item is the raw value. Use the second one
/// if you are working in Objective-C.
///
/// Usage:
///
/// ```swift
/// socket.on(clientEvent: .statusChange) {data, ack in
/// // Some status changing logging
/// }
/// ```
case statusChange
/// Emitted when when upgrading the http connection to a websocket connection.
///
/// Usage:
///
/// ```swift
/// socket.on(clientEvent: .websocketUpgrade) {data, ack in
/// let headers = (data as [Any])[0]
/// // Some header logic
/// }
/// ```
case websocketUpgrade
}

View File

@ -1,163 +0,0 @@
//
// SocketRawView.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/30/18.
//
// 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
/// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.
///
/// Usage:
///
/// ```swift
/// socket.rawEmitView.emit("myEvent", myObject)
/// ```
public final class SocketRawView : NSObject {
private unowned let socket: SocketIOClient
init(socket: SocketIOClient) {
self.socket = socket
}
/// Send an event to the server, with optional data items.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
public func emit(_ event: String, _ items: SocketData...) {
do {
try emit(event, with: items.map({ try $0.socketRepresentation() }))
} catch {
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
type: "SocketIOClient")
socket.handleClientEvent(.error, data: [event, items, error])
}
}
/// 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
public func emit(_ event: String, with items: [Any]) {
socket.emit([event] + items, binary: false)
}
/// 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.
/// Check that your server's api will ack the event being sent.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
///
/// Example:
///
/// ```swift
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
/// ...
/// }
/// ```
///
/// - parameter event: The event to send.
/// - parameter items: The items to send with this event. May be left out.
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
public func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
do {
return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() }))
} catch {
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
type: "SocketIOClient")
socket.handleClientEvent(.error, data: [event, items, error])
return OnAckCallback(ackNumber: -1, items: [], socket: socket)
}
}
/// 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
public func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback {
return socket.createOnAck([event] + items, binary: false)
}
}
/// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.
///
/// Usage:
///
/// ```swift
/// ack.rawEmitView.with(myObject)
/// ```
public final class SocketRawAckView : NSObject {
private unowned let socket: SocketIOClient
private let ackNum: Int
init(socket: SocketIOClient, ackNum: Int) {
self.socket = socket
self.ackNum = ackNum
}
/// Call to ack receiving this event.
///
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
/// will be emitted. The structure of the error data is `[ackNum, items, theError]`
///
/// - parameter items: A variable number of items to send when acking.
public func with(_ items: SocketData...) {
guard ackNum != -1 else { return }
do {
socket.emit(try items.map({ try $0.socketRepresentation() }), ack: ackNum, binary: false, isAck: true)
} catch {
socket.handleClientEvent(.error, data: [ackNum, items, error])
}
}
/// Call to ack receiving this event.
///
/// - parameter items: An array of items to send when acking. Use `[]` to send nothing.
@objc
public func with(_ items: [Any]) {
guard ackNum != -1 else { return }
socket.emit(items, ack: ackNum, binary: false, isAck: true)
}
}

View File

@ -1,778 +0,0 @@
//
// SocketEngine.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/3/15.
//
// 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 Dispatch
import Foundation
import Starscream
/// The class that handles the engine.io protocol and transports.
/// See `SocketEnginePollable` and `SocketEngineWebsocket` for transport specific methods.
open class SocketEngine: NSObject, WebSocketDelegate, URLSessionDelegate,
SocketEnginePollable, SocketEngineWebsocket, ConfigSettable {
// MARK: Properties
private static let logType = "SocketEngine"
/// The queue that all engine actions take place on.
public let engineQueue = DispatchQueue(label: "com.socketio.engineHandleQueue")
/// The connect parameters sent during a connect.
public var connectParams: [String: Any]? {
didSet {
(urlPolling, urlWebSocket) = createURLs()
}
}
/// A dictionary of extra http headers that will be set during connection.
public var extraHeaders: [String: String]?
/// A queue of engine.io messages waiting for POSTing
///
/// **You should not touch this directly**
public var postWait = [Post]()
/// `true` if there is an outstanding poll. Trying to poll before the first is done will cause socket.io to
/// disconnect us.
///
/// **Do not touch this directly**
public var waitingForPoll = false
/// `true` if there is an outstanding post. Trying to post before the first is done will cause socket.io to
/// disconnect us.
///
/// **Do not touch this directly**
public var waitingForPost = false
/// `true` if this engine is closed.
public private(set) var closed = false
/// If `true` the engine will attempt to use WebSocket compression.
public private(set) var compress = false
/// `true` if this engine is connected. Connected means that the initial poll connect has succeeded.
public private(set) var connected = false
/// An array of HTTPCookies that are sent during the connection.
public private(set) var cookies: [HTTPCookie]?
/// When `true`, the engine is in the process of switching to WebSockets.
///
/// **Do not touch this directly**
public private(set) var fastUpgrade = false
/// When `true`, the engine will only use HTTP long-polling as a transport.
public private(set) var forcePolling = false
/// When `true`, the engine will only use WebSockets as a transport.
public private(set) var forceWebsockets = false
/// `true` If engine's session has been invalidated.
public private(set) var invalidated = false
/// If `true`, the engine is currently in HTTP long-polling mode.
public private(set) var polling = true
/// If `true`, the engine is currently seeing whether it can upgrade to WebSockets.
public private(set) var probing = false
/// The URLSession that will be used for polling.
public private(set) var session: URLSession?
/// The session id for this engine.
public private(set) var sid = ""
/// The path to engine.io.
public private(set) var socketPath = "/engine.io/"
/// The url for polling.
public private(set) var urlPolling = URL(string: "http://localhost/")!
/// The url for WebSockets.
public private(set) var urlWebSocket = URL(string: "http://localhost/")!
/// When `false`, the WebSocket `stream` will be configured with the useCustomEngine `false`.
public private(set) var useCustomEngine = true
/// The version of engine.io being used. Default is three.
public private(set) var version: SocketIOVersion = .three
/// If `true`, then the engine is currently in WebSockets mode.
@available(*, deprecated, message: "No longer needed, if we're not polling, then we must be doing websockets")
public private(set) var websocket = false
/// When `true`, the WebSocket `stream` will be configured with the enableSOCKSProxy `true`.
public private(set) var enableSOCKSProxy = false
/// 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?
private weak var sessionDelegate: URLSessionDelegate?
private let url: URL
private var lastCommunication: Date?
private var pingInterval: Int?
private var pingTimeout = 0 {
didSet {
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25000))
}
}
private var pongsMissed = 0
private var pongsMissedMax = 0
private var probeWait = ProbeWaitQueue()
private var secure = false
private var certPinner: CertificatePinning?
private var selfSigned = false
// MARK: Initializers
/// Creates a new engine.
///
/// - parameter client: The client for this engine.
/// - parameter url: The url for this engine.
/// - parameter config: An array of configuration options for this engine.
public init(client: SocketEngineClient, url: URL, config: SocketIOClientConfiguration) {
self.client = client
self.url = url
super.init()
setConfigs(config)
sessionDelegate = sessionDelegate ?? self
(urlPolling, urlWebSocket) = createURLs()
}
/// Creates a new engine.
///
/// - parameter client: The client for this engine.
/// - parameter url: The url for this engine.
/// - parameter options: The options for this engine.
public required convenience init(client: SocketEngineClient, url: URL, options: [String: Any]?) {
self.init(client: client, url: url, config: options?.toSocketConfiguration() ?? [])
}
/// :nodoc:
deinit {
DefaultSocketLogger.Logger.log("Engine is being released", type: SocketEngine.logType)
closed = true
stopPolling()
}
// MARK: Methods
private func checkAndHandleEngineError(_ msg: String) {
do {
let dict = try msg.toDictionary()
guard let error = dict["message"] as? String else { return }
/*
0: Unknown transport
1: Unknown sid
2: Bad handshake request
3: Bad request
*/
didError(reason: error)
} catch {
client?.engineDidError(reason: "Got unknown error from server \(msg)")
}
}
private func handleBase64(message: String) {
let offset = version.rawValue >= 3 ? 1 : 2
// binary in base64 string
let noPrefix = String(message[message.index(message.startIndex, offsetBy: offset)..<message.endIndex])
if let data = Data(base64Encoded: noPrefix, options: .ignoreUnknownCharacters) {
client?.parseEngineBinaryData(data)
}
}
private func closeOutEngine(reason: String) {
sid = ""
closed = true
invalidated = true
connected = false
ws?.disconnect()
stopPolling()
client?.engineDidClose(reason: reason)
}
/// Starts the connection to the server.
open func connect() {
engineQueue.async {
self._connect()
}
}
private func _connect() {
if connected {
DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect",
type: SocketEngine.logType)
_disconnect(reason: "reconnect")
}
DefaultSocketLogger.Logger.log("Starting engine. Server: \(url)", type: SocketEngine.logType)
DefaultSocketLogger.Logger.log("Handshaking", type: SocketEngine.logType)
resetEngine()
if forceWebsockets {
polling = false
createWebSocketAndConnect()
return
}
var reqPolling = URLRequest(url: urlPolling, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0)
addHeaders(to: &reqPolling)
doLongPoll(for: reqPolling)
}
private func createURLs() -> (URL, URL) {
if client == nil {
return (URL(string: "http://localhost/")!, URL(string: "http://localhost/")!)
}
var urlPolling = URLComponents(string: url.absoluteString)!
var urlWebSocket = URLComponents(string: url.absoluteString)!
var queryString = ""
urlWebSocket.path = socketPath
urlPolling.path = socketPath
if secure {
urlPolling.scheme = "https"
urlWebSocket.scheme = "wss"
} else {
urlPolling.scheme = "http"
urlWebSocket.scheme = "ws"
}
if let connectParams = self.connectParams {
for (key, value) in connectParams {
let keyEsc = key.urlEncode()!
let valueEsc = "\(value)".urlEncode()!
queryString += "&\(keyEsc)=\(valueEsc)"
}
}
urlWebSocket.percentEncodedQuery = "transport=websocket" + queryString
urlPolling.percentEncodedQuery = "transport=polling&b64=1" + queryString
if !urlWebSocket.percentEncodedQuery!.contains("EIO") {
urlWebSocket.percentEncodedQuery = urlWebSocket.percentEncodedQuery! + engineIOParam
}
if !urlPolling.percentEncodedQuery!.contains("EIO") {
urlPolling.percentEncodedQuery = urlPolling.percentEncodedQuery! + engineIOParam
}
return (urlPolling.url!, urlWebSocket.url!)
}
private func createWebSocketAndConnect() {
var req = URLRequest(url: urlWebSocketWithSid)
addHeaders(
to: &req,
includingCookies: session?.configuration.httpCookieStorage?.cookies(for: urlPollingWithSid)
)
ws = WebSocket(request: req, certPinner: certPinner, compressionHandler: compress ? WSCompression() : nil, useCustomEngine: useCustomEngine)
ws?.callbackQueue = engineQueue
ws?.delegate = self
ws?.connect()
}
/// Called when an error happens during execution. Causes a disconnection.
open func didError(reason: String) {
DefaultSocketLogger.Logger.error("\(reason)", type: SocketEngine.logType)
client?.engineDidError(reason: reason)
disconnect(reason: reason)
}
/// Disconnects from the server.
///
/// - parameter reason: The reason for the disconnection. This is communicated up to the client.
open func disconnect(reason: String) {
engineQueue.async {
self._disconnect(reason: reason)
}
}
private func _disconnect(reason: String) {
guard connected && !closed else { return closeOutEngine(reason: reason) }
DefaultSocketLogger.Logger.log("Engine is being closed.", type: SocketEngine.logType)
if polling {
disconnectPolling(reason: reason)
} else {
sendWebSocketMessage("", withType: .close, withData: [], completion: nil)
closeOutEngine(reason: reason)
}
}
// We need to take special care when we're polling that we send it ASAP
// Also make sure we're on the emitQueue since we're touching postWait
private func disconnectPolling(reason: String) {
postWait.append((String(SocketEnginePacketType.close.rawValue), {}))
doRequest(for: createRequestForPostWithPostWait()) {_, _, _ in }
closeOutEngine(reason: reason)
}
/// Called to switch from HTTP long-polling to WebSockets. After calling this method the engine will be in
/// WebSocket mode.
///
/// **You shouldn't call this directly**
open func doFastUpgrade() {
if waitingForPoll {
DefaultSocketLogger.Logger.error("Outstanding poll when switched to WebSockets," +
"we'll probably disconnect soon. You should report this.", type: SocketEngine.logType)
}
DefaultSocketLogger.Logger.log("Switching to WebSockets", type: SocketEngine.logType)
sendWebSocketMessage("", withType: .upgrade, withData: [], completion: nil)
polling = false
fastUpgrade = false
probing = false
flushProbeWait()
// Need to flush postWait to socket since it connected successfully
// moved from flushProbeWait() since it is also called on connected failure, and we don't want to try and send
// packets through WebSockets when WebSockets has failed!
if !postWait.isEmpty {
flushWaitingForPostToWebSocket()
}
}
private func flushProbeWait() {
DefaultSocketLogger.Logger.log("Flushing probe wait", type: SocketEngine.logType)
for waiter in probeWait {
write(waiter.msg, withType: waiter.type, withData: waiter.data, completion: waiter.completion)
}
probeWait.removeAll(keepingCapacity: false)
}
/// Causes any packets that were waiting for POSTing to be sent through the WebSocket. This happens because when
/// the engine is attempting to upgrade to WebSocket it does not do any POSTing.
///
/// **You shouldn't call this directly**
open func flushWaitingForPostToWebSocket() {
guard let ws = self.ws else { return }
for msg in postWait {
ws.write(string: msg.msg, completion: msg.completion)
}
postWait.removeAll(keepingCapacity: false)
}
private func handleClose(_ reason: String) {
client?.engineDidClose(reason: reason)
}
private func handleMessage(_ message: String) {
client?.parseEngineMessage(message)
}
private func handleNOOP() {
doPoll()
}
private func handleOpen(openData: String) {
guard let json = try? openData.toDictionary() else {
didError(reason: "Error parsing open packet")
return
}
guard let sid = json["sid"] as? String else {
didError(reason: "Open packet contained no sid")
return
}
let upgradeWs: Bool
self.sid = sid
connected = true
pongsMissed = 0
if let upgrades = json["upgrades"] as? [String] {
upgradeWs = upgrades.contains("websocket")
} else {
upgradeWs = false
}
if let pingInterval = json["pingInterval"] as? Int, let pingTimeout = json["pingTimeout"] as? Int {
self.pingInterval = pingInterval
self.pingTimeout = pingTimeout
}
if !forcePolling && !forceWebsockets && upgradeWs {
createWebSocketAndConnect()
}
if version.rawValue >= 3 {
checkPings()
} else {
sendPing()
}
if !forceWebsockets {
doPoll()
}
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",
type: SocketEngine.logType)
upgradeTransport()
}
client?.engineDidReceivePong()
}
private func handlePing(with message: String) {
if version.rawValue >= 3 {
write("", withType: .pong, withData: [])
}
client?.engineDidReceivePing()
}
private func checkPings() {
let pingInterval = self.pingInterval ?? 25_000
let deadlineMs = Double(pingInterval + pingTimeout) / 1000
let timeoutDeadline = DispatchTime.now() + .milliseconds(pingInterval + pingTimeout)
engineQueue.asyncAfter(deadline: timeoutDeadline) {[weak self, id = self.sid] in
// Make sure not to ping old connections
guard let this = self, this.sid == id else { return }
if abs(this.lastCommunication?.timeIntervalSinceNow ?? deadlineMs) >= deadlineMs {
this.closeOutEngine(reason: "Ping timeout")
} else {
this.checkPings()
}
}
}
/// Parses raw binary received from engine.io.
///
/// - parameter data: The data to parse.
open func parseEngineData(_ data: Data) {
DefaultSocketLogger.Logger.log("Got binary data: \(data)", type: SocketEngine.logType)
lastCommunication = Date()
client?.parseEngineBinaryData(version.rawValue >= 3 ? data : data.subdata(in: 1..<data.endIndex))
}
/// Parses a raw engine.io packet.
///
/// - parameter message: The message to parse.
open func parseEngineMessage(_ message: String) {
lastCommunication = Date()
DefaultSocketLogger.Logger.log("Got message: \(message)", type: SocketEngine.logType)
if message.hasPrefix(version.rawValue >= 3 ? "b" : "b4") {
return handleBase64(message: message)
}
guard let type = SocketEnginePacketType(rawValue: message.first?.wholeNumberValue ?? -1) else {
checkAndHandleEngineError(message)
return
}
switch type {
case .message:
handleMessage(String(message.dropFirst()))
case .noop:
handleNOOP()
case .ping:
handlePing(with: message)
case .pong:
handlePong(with: message)
case .open:
handleOpen(openData: String(message.dropFirst()))
case .close:
handleClose(message)
default:
DefaultSocketLogger.Logger.log("Got unknown packet type", type: SocketEngine.logType)
}
}
// Puts the engine back in its default state
private func resetEngine() {
let queue = OperationQueue()
queue.underlyingQueue = engineQueue
closed = false
connected = false
fastUpgrade = false
polling = true
probing = false
invalidated = false
session = Foundation.URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: queue)
sid = ""
waitingForPoll = false
waitingForPost = false
}
private func sendPing() {
guard connected, let pingInterval = pingInterval else {
return
}
// Server is not responding
if pongsMissed > pongsMissedMax {
closeOutEngine(reason: "Ping timeout")
return
}
pongsMissed += 1
write("", withType: .ping, withData: [], completion: nil)
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
}
this.sendPing()
}
client?.engineDidSendPing()
}
/// Called when the engine should set/update its configs from a given configuration.
///
/// parameter config: The `SocketIOClientConfiguration` that should be used to set/update configs.
open func setConfigs(_ config: SocketIOClientConfiguration) {
for option in config {
switch option {
case let .connectParams(params):
connectParams = params
case let .cookies(cookies):
self.cookies = cookies
case let .extraHeaders(headers):
extraHeaders = headers
case let .sessionDelegate(delegate):
sessionDelegate = delegate
case let .forcePolling(force):
forcePolling = force
case let .forceWebsockets(force):
forceWebsockets = force
case let .path(path):
socketPath = path
if !socketPath.hasSuffix("/") {
socketPath += "/"
}
case let .secure(secure):
self.secure = secure
case let .selfSigned(selfSigned):
self.selfSigned = selfSigned
case let .security(pinner):
self.certPinner = pinner
case .compress:
self.compress = true
case .enableSOCKSProxy:
self.enableSOCKSProxy = true
case let .useCustomEngine(enable):
self.useCustomEngine = enable
case let .version(num):
version = num
default:
continue
}
}
}
// Moves from long-polling to websockets
private func upgradeTransport() {
if wsConnected {
DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: SocketEngine.logType)
fastUpgrade = true
sendPollMessage("", withType: .noop, withData: [], completion: nil)
// After this point, we should not send anymore polling messages
}
}
/// Writes a message to engine.io, independent of transport.
///
/// - parameter msg: The message to send.
/// - parameter type: The type of this message.
/// - parameter data: Any data that this message has.
/// - parameter completion: Callback called on transport write completion.
open func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data], completion: (() -> ())? = nil) {
engineQueue.async {
guard self.connected else {
completion?()
return
}
guard !self.probing else {
self.probeWait.append((msg, type, data, completion))
return
}
if self.polling {
DefaultSocketLogger.Logger.log("Writing poll: \(msg) has data: \(data.count != 0)",
type: SocketEngine.logType)
self.sendPollMessage(msg, withType: type, withData: data, completion: completion)
} else {
DefaultSocketLogger.Logger.log("Writing ws: \(msg) has data: \(data.count != 0)",
type: SocketEngine.logType)
self.sendWebSocketMessage(msg, withType: type, withData: data, completion: completion)
}
}
}
// WebSocket Methods
private func websocketDidConnect() {
if !forceWebsockets {
probing = true
probeWebSocket()
} else {
connected = true
probing = false
polling = false
}
}
private func websocketDidDisconnect(error: Error?) {
probing = false
if closed {
client?.engineDidClose(reason: "Disconnect")
return
}
guard !polling else {
flushProbeWait()
return
}
connected = false
polling = true
if let error = error as? WSError {
didError(reason: "\(error.message). code=\(error.code), type=\(error.type)")
} else if let reason = error?.localizedDescription {
didError(reason: reason)
} else {
client?.engineDidClose(reason: "Socket Disconnected")
}
}
// Test Properties
func setConnected(_ value: Bool) {
connected = value
}
}
extension SocketEngine {
// MARK: URLSessionDelegate methods
/// Delegate called when the session becomes invalid.
public func URLSession(session: URLSession, didBecomeInvalidWithError error: NSError?) {
DefaultSocketLogger.Logger.error("Engine URLSession became invalid", type: "SocketEngine")
didError(reason: "Engine URLSession became invalid")
}
}
enum EngineError: Error {
case canceled
}
extension SocketEngine {
/// Delegate method for WebSocketDelegate.
///
/// - Parameters:
/// - event: WS Event
/// - _:
public func didReceive(event: Starscream.WebSocketEvent, client: Starscream.WebSocketClient) {
switch event {
case let .connected(headers):
wsConnected = true
self.client?.engineDidWebsocketUpgrade(headers: headers)
websocketDidConnect()
case .cancelled:
wsConnected = false
websocketDidDisconnect(error: EngineError.canceled)
case .disconnected(_, _):
wsConnected = false
websocketDidDisconnect(error: nil)
case .viabilityChanged(false):
wsConnected = false
websocketDidDisconnect(error: nil)
case .peerClosed:
wsConnected = false
websocketDidDisconnect(error: nil)
case let .text(msg):
parseEngineMessage(msg)
case let .binary(data):
parseEngineData(data)
case _:
break
}
}
}

View File

@ -1,73 +0,0 @@
//
// SocketEngineClient.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/19/15.
//
// 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
/// Declares that a type will be a delegate to an engine.
@objc public protocol SocketEngineClient {
// MARK: Methods
/// Called when the engine errors.
///
/// - parameter reason: The reason the engine errored.
func engineDidError(reason: String)
/// Called when the engine closes.
///
/// - parameter reason: The reason that the engine closed.
func engineDidClose(reason: String)
/// Called when the engine opens.
///
/// - parameter reason: The reason the engine opened.
func engineDidOpen(reason: String)
/// Called when the engine receives a ping message. Only called in socket.io >3.
func engineDidReceivePing()
/// Called when the engine receives a pong message. Only called in socket.io 2.
func engineDidReceivePong()
/// Called when the engine sends a ping to the server. Only called in socket.io 2.
func engineDidSendPing()
/// Called when the engine sends a pong to the server. Only called in socket.io >3.
func engineDidSendPong()
/// Called when the engine has a message that must be parsed.
///
/// - parameter msg: The message that needs parsing.
func parseEngineMessage(_ msg: String)
/// Called when the engine receives binary data.
///
/// - parameter data: The data the engine received.
func parseEngineBinaryData(_ data: Data)
/// Called when when upgrading the http connection to a websocket connection.
///
/// - parameter headers: The http headers.
func engineDidWebsocketUpgrade(headers: [String: String])
}

View File

@ -1,262 +0,0 @@
//
// SocketEnginePollable.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 1/15/16.
//
// 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
/// Protocol that is used to implement socket.io polling support
public protocol SocketEnginePollable: SocketEngineSpec {
// MARK: Properties
/// `true` If engine's session has been invalidated.
var invalidated: Bool { get }
/// A queue of engine.io messages waiting for POSTing
///
/// **You should not touch this directly**
var postWait: [Post] { get set }
/// The URLSession that will be used for polling.
var session: URLSession? { get }
/// `true` if there is an outstanding poll. Trying to poll before the first is done will cause socket.io to
/// disconnect us.
///
/// **Do not touch this directly**
var waitingForPoll: Bool { get set }
/// `true` if there is an outstanding post. Trying to post before the first is done will cause socket.io to
/// disconnect us.
///
/// **Do not touch this directly**
var waitingForPost: Bool { get set }
// MARK: Methods
/// Call to send a long-polling request.
///
/// You shouldn't need to call this directly, the engine should automatically maintain a long-poll request.
func doPoll()
/// Sends an engine.io message through the polling transport.
///
/// You shouldn't call this directly, instead call the `write` method on `SocketEngine`.
///
/// - parameter message: The message to send.
/// - parameter withType: The type of message to send.
/// - parameter withData: The data associated with this message.
func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data], completion: (() -> ())?)
/// Call to stop polling and invalidate the URLSession.
func stopPolling()
}
// Default polling methods
extension SocketEnginePollable {
func createRequestForPostWithPostWait() -> URLRequest {
defer {
for packet in postWait { packet.completion?() }
postWait.removeAll(keepingCapacity: true)
}
var postStr = ""
if version.rawValue >= 3 {
postStr = postWait.lazy.map({ $0.msg }).joined(separator: "\u{1e}")
} else {
for packet in postWait {
postStr += "\(packet.msg.utf16.count):\(packet.msg)"
}
}
DefaultSocketLogger.Logger.log("Created POST string: \(postStr)", type: "SocketEnginePolling")
var req = URLRequest(url: urlPollingWithSid)
let postData = postStr.data(using: .utf8, allowLossyConversion: false)!
addHeaders(to: &req)
req.httpMethod = "POST"
req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type")
req.httpBody = postData
req.setValue(String(postData.count), forHTTPHeaderField: "Content-Length")
return req
}
/// Call to send a long-polling request.
///
/// You shouldn't need to call this directly, the engine should automatically maintain a long-poll request.
public func doPoll() {
guard polling && !waitingForPoll && connected && !closed else { return }
var req = URLRequest(url: urlPollingWithSid)
addHeaders(to: &req)
doLongPoll(for: req)
}
func doRequest(for req: URLRequest, callbackWith callback: @escaping (Data?, URLResponse?, Error?) -> ()) {
guard polling && !closed && !invalidated && !fastUpgrade else { return }
DefaultSocketLogger.Logger.log("Doing polling \(req.httpMethod ?? "") \(req)", type: "SocketEnginePolling")
session?.dataTask(with: req, completionHandler: callback).resume()
}
func doLongPoll(for req: URLRequest) {
waitingForPoll = true
doRequest(for: req) {[weak self] data, res, err in
guard let this = self, this.polling else { return }
guard let data = data, let res = res as? HTTPURLResponse, res.statusCode == 200 else {
if let err = err {
DefaultSocketLogger.Logger.error(err.localizedDescription, type: "SocketEnginePolling")
} else {
DefaultSocketLogger.Logger.error("Error during long poll request", type: "SocketEnginePolling")
}
if this.polling {
this.didError(reason: err?.localizedDescription ?? "Error")
}
return
}
DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling")
if let str = String(data: data, encoding: .utf8) {
this.parsePollingMessage(str)
}
this.waitingForPoll = false
if this.fastUpgrade {
this.doFastUpgrade()
} else if !this.closed && this.polling {
this.doPoll()
}
}
}
private func flushWaitingForPost() {
guard postWait.count != 0 && connected else { return }
guard polling else {
flushWaitingForPostToWebSocket()
return
}
let req = createRequestForPostWithPostWait()
waitingForPost = true
DefaultSocketLogger.Logger.log("POSTing", type: "SocketEnginePolling")
doRequest(for: req) {[weak self] _, res, err in
guard let this = self else { return }
guard let res = res as? HTTPURLResponse, res.statusCode == 200 else {
if let err = err {
DefaultSocketLogger.Logger.error(err.localizedDescription, type: "SocketEnginePolling")
} else {
DefaultSocketLogger.Logger.error("Error flushing waiting posts", type: "SocketEnginePolling")
}
if this.polling {
this.didError(reason: err?.localizedDescription ?? "Error")
}
return
}
this.waitingForPost = false
if !this.fastUpgrade {
this.flushWaitingForPost()
this.doPoll()
}
}
}
func parsePollingMessage(_ str: String) {
guard !str.isEmpty else { return }
DefaultSocketLogger.Logger.log("Got poll message: \(str)", type: "SocketEnginePolling")
if version.rawValue >= 3 {
let records = str.components(separatedBy: "\u{1e}")
for record in records {
parseEngineMessage(record)
}
} else {
guard str.count != 1 else {
parseEngineMessage(str)
return
}
var reader = SocketStringReader(message: str)
while reader.hasNext {
if let n = Int(reader.readUntilOccurence(of: ":")) {
parseEngineMessage(reader.read(count: n))
} else {
parseEngineMessage(str)
break
}
}
}
}
/// Sends an engine.io message through the polling transport.
///
/// You shouldn't call this directly, instead call the `write` method on `SocketEngine`.
///
/// - parameter message: The message to send.
/// - parameter withType: The type of message to send.
/// - parameter withData: The data associated with this message.
/// - parameter completion: Callback called on transport write completion.
public func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data], completion: (() -> ())? = nil) {
DefaultSocketLogger.Logger.log("Sending poll: \(message) as type: \(type.rawValue)", type: "SocketEnginePolling")
postWait.append((String(type.rawValue) + message, completion))
for data in datas {
if case let .right(bin) = createBinaryDataForSend(using: data) {
postWait.append((bin, {}))
}
}
if !waitingForPost {
flushWaitingForPost()
}
}
/// Call to stop polling and invalidate the URLSession.
public func stopPolling() {
waitingForPoll = false
waitingForPost = false
session?.finishTasksAndInvalidate()
}
}

View File

@ -1,209 +0,0 @@
//
// SocketEngineSpec.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/7/15.
//
// 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
/// Specifies a SocketEngine.
public protocol SocketEngineSpec: AnyObject {
// MARK: Properties
/// The client for this engine.
var client: SocketEngineClient? { get set }
/// `true` if this engine is closed.
var closed: Bool { get }
/// If `true` the engine will attempt to use WebSocket compression.
var compress: Bool { get }
/// `true` if this engine is connected. Connected means that the initial poll connect has succeeded.
var connected: Bool { get }
/// The connect parameters sent during a connect.
var connectParams: [String: Any]? { get set }
/// An array of HTTPCookies that are sent during the connection.
var cookies: [HTTPCookie]? { get }
/// The queue that all engine actions take place on.
var engineQueue: DispatchQueue { get }
/// A dictionary of extra http headers that will be set during connection.
var extraHeaders: [String: String]? { get set }
/// When `true`, the engine is in the process of switching to WebSockets.
var fastUpgrade: Bool { get }
/// When `true`, the engine will only use HTTP long-polling as a transport.
var forcePolling: Bool { get }
/// When `true`, the engine will only use WebSockets as a transport.
var forceWebsockets: Bool { get }
/// If `true`, the engine is currently in HTTP long-polling mode.
var polling: Bool { get }
/// If `true`, the engine is currently seeing whether it can upgrade to WebSockets.
var probing: Bool { get }
/// The session id for this engine.
var sid: String { get }
/// The path to engine.io.
var socketPath: String { get }
/// The url for polling.
var urlPolling: URL { get }
/// The url for WebSockets.
var urlWebSocket: URL { get }
/// The version of engine.io being used. Default is three.
var version: SocketIOVersion { get }
/// If `true`, then the engine is currently in WebSockets mode.
@available(*, deprecated, message: "No longer needed, if we're not polling, then we must be doing websockets")
var websocket: Bool { get }
/// The WebSocket for this engine.
var ws: WebSocket? { get }
// MARK: Initializers
/// Creates a new engine.
///
/// - parameter client: The client for this engine.
/// - parameter url: The url for this engine.
/// - parameter options: The options for this engine.
init(client: SocketEngineClient, url: URL, options: [String: Any]?)
// MARK: Methods
/// Starts the connection to the server.
func connect()
/// Called when an error happens during execution. Causes a disconnection.
func didError(reason: String)
/// Disconnects from the server.
///
/// - parameter reason: The reason for the disconnection. This is communicated up to the client.
func disconnect(reason: String)
/// Called to switch from HTTP long-polling to WebSockets. After calling this method the engine will be in
/// WebSocket mode.
///
/// **You shouldn't call this directly**
func doFastUpgrade()
/// Causes any packets that were waiting for POSTing to be sent through the WebSocket. This happens because when
/// the engine is attempting to upgrade to WebSocket it does not do any POSTing.
///
/// **You shouldn't call this directly**
func flushWaitingForPostToWebSocket()
/// Parses raw binary received from engine.io.
///
/// - parameter data: The data to parse.
func parseEngineData(_ data: Data)
/// Parses a raw engine.io packet.
///
/// - parameter message: The message to parse.
func parseEngineMessage(_ message: String)
/// Writes a message to engine.io, independent of transport.
///
/// - parameter msg: The message to send.
/// - parameter type: The type of this message.
/// - parameter data: Any data that this message has.
/// - parameter completion: Callback called on transport write completion.
func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data], completion: (() -> ())?)
}
extension SocketEngineSpec {
var engineIOParam: String {
switch version {
case .two:
return "&EIO=3"
case .three:
return "&EIO=4"
}
}
var urlPollingWithSid: URL {
var com = URLComponents(url: urlPolling, resolvingAgainstBaseURL: false)!
com.percentEncodedQuery = com.percentEncodedQuery! + "&sid=\(sid.urlEncode()!)"
if !com.percentEncodedQuery!.contains("EIO") {
com.percentEncodedQuery = com.percentEncodedQuery! + engineIOParam
}
return com.url!
}
var urlWebSocketWithSid: URL {
var com = URLComponents(url: urlWebSocket, resolvingAgainstBaseURL: false)!
com.percentEncodedQuery = com.percentEncodedQuery! + (sid == "" ? "" : "&sid=\(sid.urlEncode()!)")
if !com.percentEncodedQuery!.contains("EIO") {
com.percentEncodedQuery = com.percentEncodedQuery! + engineIOParam
}
return com.url!
}
func addHeaders(to req: inout URLRequest, includingCookies additionalCookies: [HTTPCookie]? = nil) {
var cookiesToAdd: [HTTPCookie] = cookies ?? []
cookiesToAdd += additionalCookies ?? []
if !cookiesToAdd.isEmpty {
req.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: cookiesToAdd)
}
if let extraHeaders = extraHeaders {
for (headerName, value) in extraHeaders {
req.setValue(value, forHTTPHeaderField: headerName)
}
}
}
func createBinaryDataForSend(using data: Data) -> Either<Data, String> {
let prefixB64 = version.rawValue >= 3 ? "b" : "b4"
if polling {
return .right(prefixB64 + data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)))
} else {
return .left(version.rawValue >= 3 ? data : Data([0x4]) + data)
}
}
/// Send an engine message (4)
func send(_ msg: String, withData datas: [Data], completion: (() -> ())? = nil) {
write(msg, withType: .message, withData: datas, completion: completion)
}
}

View File

@ -1,87 +0,0 @@
//
// SocketEngineWebsocket.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 1/15/16.
//
// 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
/// Protocol that is used to implement socket.io WebSocket support
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.
///
/// You shouldn't call this directly, instead call the `write` method on `SocketEngine`.
///
/// - parameter message: The message to send.
/// - parameter withType: The type of message to send.
/// - parameter withData: The data associated with this message.
/// - parameter completion: Callback called on transport write completion.
func sendWebSocketMessage(_ str: String,
withType type: SocketEnginePacketType,
withData datas: [Data],
completion: (() -> ())?)
}
// WebSocket methods
extension SocketEngineWebsocket {
func probeWebSocket() {
if wsConnected {
sendWebSocketMessage("probe", withType: .ping, withData: [], completion: nil)
}
}
/// Sends an engine.io message through the WebSocket transport.
///
/// You shouldn't call this directly, instead call the `write` method on `SocketEngine`.
///
/// - parameter message: The message to send.
/// - parameter withType: The type of message to send.
/// - parameter withData: The data associated with this message.
/// - parameter completion: Callback called on transport write completion.
public func sendWebSocketMessage(_ str: String,
withType type: SocketEnginePacketType,
withData data: [Data],
completion: (() -> ())?
) {
DefaultSocketLogger.Logger.log("Sending ws: \(str) as type: \(type.rawValue)", type: "SocketEngineWebSocket")
ws?.write(string: "\(type.rawValue)\(str)")
for item in data {
if case let .left(bin) = createBinaryDataForSend(using: item) {
ws?.write(data: bin, completion: completion)
}
}
if data.count == 0 {
completion?()
}
}
}

View File

@ -1,613 +0,0 @@
//
// Created by Erik Little on 10/14/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 Dispatch
import Foundation
///
/// A manager for a socket.io connection.
///
/// A `SocketManager` is responsible for multiplexing multiple namespaces through a single `SocketEngineSpec`.
///
/// Example:
///
/// ```swift
/// let manager = SocketManager(socketURL: URL(string:"http://localhost:8080/")!)
/// let defaultNamespaceSocket = manager.defaultSocket
/// let swiftSocket = manager.socket(forNamespace: "/swift")
///
/// // defaultNamespaceSocket and swiftSocket both share a single connection to the server
/// ```
///
/// Sockets created through the manager are retained by the manager. So at the very least, a single strong reference
/// to the manager must be maintained to keep sockets alive.
///
/// 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.
///
/// **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 {
private static let logType = "SocketManager"
// MARK: Properties
/// The socket associated with the default namespace ("/").
public var defaultSocket: SocketIOClient {
return socket(forNamespace: "/")
}
/// The URL of the socket.io server.
///
/// If changed after calling `init`, `forceNew` must be set to `true`, or it will only connect to the url set in the
/// init.
public let socketURL: URL
/// The configuration for this client.
///
/// **Some configs will not take affect until after a reconnect if set after calling a connect method**.
public var config: SocketIOClientConfiguration {
get {
return _config
}
set {
if status.active {
DefaultSocketLogger.Logger.log("Setting configs on active manager. Some configs may not be applied until reconnect",
type: SocketManager.logType)
}
setConfigs(newValue)
}
}
/// The engine for this manager.
public var engine: SocketEngineSpec?
/// If `true` then every time `connect` is called, a new engine will be created.
public var forceNew = false
/// The queue that all interaction with the client should occur on. This is the queue that event handlers are
/// called on.
///
/// **This should be a serial queue! Concurrent queues are not supported and might cause crashes and races**.
public var handleQueue = DispatchQueue.main
/// The sockets in this manager indexed by namespace.
public var nsps = [String: SocketIOClient]()
/// If `true`, this client will try and reconnect on any disconnects.
public var reconnects = true
/// The minimum number of seconds to wait before attempting to reconnect.
public var reconnectWait = 10
/// The maximum number of seconds to wait before attempting to reconnect.
public var reconnectWaitMax = 30
/// The randomization factor for calculating reconnect jitter.
public var randomizationFactor = 0.5
/// The status of this manager.
public private(set) var status: SocketIOStatus = .notConnected {
didSet {
switch status {
case .connected:
reconnecting = false
currentReconnectAttempt = 0
default:
break
}
}
}
public private(set) var version = SocketIOVersion.three
/// A list of packets that are waiting for binary data.
///
/// The way that socket.io works all data should be sent directly after each packet.
/// So this should ideally be an array of one packet waiting for data.
///
/// **This should not be modified directly.**
public var waitingPackets = [SocketPacket]()
private(set) var reconnectAttempts = -1
private var _config: SocketIOClientConfiguration
internal var currentReconnectAttempt = 0
private var reconnecting = false
// MARK: Initializers
/// Type safe way to create a new SocketIOClient. `opts` can be omitted.
///
/// - parameter socketURL: The url of the socket.io server.
/// - parameter config: The config for this socket.
public init(socketURL: URL, config: SocketIOClientConfiguration = []) {
self._config = config
self.socketURL = socketURL
super.init()
setConfigs(_config)
}
/// Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
/// If using Swift it's recommended to use `init(socketURL: NSURL, options: Set<SocketIOClientOption>)`
///
/// - parameter socketURL: The url of the socket.io server.
/// - parameter config: The config for this socket.
@objc
public convenience init(socketURL: URL, config: [String: Any]?) {
self.init(socketURL: socketURL, config: config?.toSocketConfiguration() ?? [])
}
/// :nodoc:
deinit {
DefaultSocketLogger.Logger.log("Manager is being released", type: SocketManager.logType)
engine?.disconnect(reason: "Manager Deinit")
}
// MARK: Methods
private func addEngine() {
DefaultSocketLogger.Logger.log("Adding engine", type: SocketManager.logType)
engine?.engineQueue.sync {
self.engine?.client = nil
// Close old engine so it will not leak because of URLSession if in polling mode
self.engine?.disconnect(reason: "Adding new engine")
}
engine = SocketEngine(client: self, url: socketURL, config: config)
}
/// Connects the underlying transport and the default namespace socket.
///
/// Override if you wish to attach a custom `SocketEngineSpec`.
open func connect() {
if status == .connected || (status == .connecting && currentReconnectAttempt == 0) {
DefaultSocketLogger.Logger.log("Tried connecting an already active socket", type: SocketManager.logType)
return
}
if engine == nil || forceNew {
addEngine()
}
status = .connecting
engine?.connect()
}
/// Connects a socket through this manager's engine.
///
/// - parameter socket: The socket who we should connect through this manager.
/// - parameter withPayload: Optional payload to send on connect
open func connectSocket(_ socket: SocketIOClient, withPayload payload: [String: Any]? = nil) {
guard status == .connected else {
DefaultSocketLogger.Logger.log("Tried connecting socket when engine isn't open. Connecting",
type: SocketManager.logType)
connect()
return
}
var payloadStr = ""
if version.rawValue >= 3 && payload != nil,
let payloadData = try? JSONSerialization.data(withJSONObject: payload!, options: .fragmentsAllowed),
let jsonString = String(data: payloadData, encoding: .utf8) {
payloadStr = jsonString
}
engine?.send("0\(socket.nsp),\(payloadStr)", withData: [])
}
/// Called when the manager has disconnected from socket.io.
///
/// - parameter reason: The reason for the disconnection.
open func didDisconnect(reason: String) {
forAll {socket in
socket.didDisconnect(reason: reason)
}
}
/// Disconnects the manager and all associated sockets.
open func disconnect() {
DefaultSocketLogger.Logger.log("Manager closing", type: SocketManager.logType)
status = .disconnected
engine?.disconnect(reason: "Disconnect")
}
/// Disconnects the given socket.
///
/// This will remove the socket for the manager's control, and make the socket instance useless and ready for
/// releasing.
///
/// - parameter socket: The socket to disconnect.
open func disconnectSocket(_ socket: SocketIOClient) {
engine?.send("1\(socket.nsp),", withData: [])
socket.didDisconnect(reason: "Namespace leave")
}
/// Disconnects the socket associated with `forNamespace`.
///
/// This will remove the socket for the manager's control, and make the socket instance useless and ready for
/// releasing.
///
/// - parameter nsp: The namespace to disconnect from.
open func disconnectSocket(forNamespace nsp: String) {
guard let socket = nsps.removeValue(forKey: nsp) else {
DefaultSocketLogger.Logger.log("Could not find socket for \(nsp) to disconnect",
type: SocketManager.logType)
return
}
disconnectSocket(socket)
}
/// Sends a client event to all sockets in `nsps`
///
/// - parameter clientEvent: The event to emit.
open func emitAll(clientEvent event: SocketClientEvent, data: [Any]) {
forAll {socket in
socket.handleClientEvent(event, data: data)
}
}
/// Sends an event to the server on all namespaces in this manager.
///
/// - parameter event: The event to send.
/// - parameter items: The data to send with this event.
open func emitAll(_ event: String, _ items: SocketData...) {
guard let emitData = try? items.map({ try $0.socketRepresentation() }) else {
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
type: SocketManager.logType)
return
}
forAll {socket in
socket.emit([event] + emitData)
}
}
/// Called when the engine closes.
///
/// - parameter reason: The reason that the engine closed.
open func engineDidClose(reason: String) {
handleQueue.async {
self._engineDidClose(reason: reason)
}
}
private func _engineDidClose(reason: String) {
waitingPackets.removeAll()
if status != .disconnected {
status = .notConnected
}
if status == .disconnected || !reconnects {
didDisconnect(reason: reason)
} else if !reconnecting {
reconnecting = true
tryReconnect(reason: reason)
}
}
/// Called when the engine errors.
///
/// - parameter reason: The reason the engine errored.
open func engineDidError(reason: String) {
handleQueue.async {
self._engineDidError(reason: reason)
}
}
private func _engineDidError(reason: String) {
DefaultSocketLogger.Logger.error("\(reason)", type: SocketManager.logType)
emitAll(clientEvent: .error, data: [reason])
}
/// Called when the engine opens.
///
/// - parameter reason: The reason the engine opened.
open func engineDidOpen(reason: String) {
handleQueue.async {
self._engineDidOpen(reason: reason)
}
}
private func _engineDidOpen(reason: String) {
DefaultSocketLogger.Logger.log("Engine opened \(reason)", type: SocketManager.logType)
status = .connected
if version.rawValue < 3 {
nsps["/"]?.didConnect(toNamespace: "/", payload: nil)
}
for (nsp, socket) in nsps where socket.status == .connecting {
if version.rawValue < 3 && nsp == "/" {
continue
}
connectSocket(socket, withPayload: socket.connectPayload)
}
}
/// Called when the engine receives a ping message.
open func engineDidReceivePing() {
handleQueue.async {
self._engineDidReceivePing()
}
}
private func _engineDidReceivePing() {
emitAll(clientEvent: .ping, data: [])
}
/// Called when the sends a ping to the server.
open func engineDidSendPing() {
handleQueue.async {
self._engineDidSendPing()
}
}
private func _engineDidSendPing() {
emitAll(clientEvent: .ping, data: [])
}
/// Called when the engine receives a pong message.
open func engineDidReceivePong() {
handleQueue.async {
self._engineDidReceivePong()
}
}
private func _engineDidReceivePong() {
emitAll(clientEvent: .pong, data: [])
}
/// Called when the sends a pong to the server.
open func engineDidSendPong() {
handleQueue.async {
self._engineDidSendPong()
}
}
private func _engineDidSendPong() {
emitAll(clientEvent: .pong, data: [])
}
private func forAll(do: (SocketIOClient) throws -> ()) rethrows {
for (_, socket) in nsps {
try `do`(socket)
}
}
/// Called when when upgrading the http connection to a websocket connection.
///
/// - parameter headers: The http headers.
open func engineDidWebsocketUpgrade(headers: [String: String]) {
handleQueue.async {
self._engineDidWebsocketUpgrade(headers: headers)
}
}
private func _engineDidWebsocketUpgrade(headers: [String: String]) {
emitAll(clientEvent: .websocketUpgrade, data: [headers])
}
/// Called when the engine has a message that must be parsed.
///
/// - parameter msg: The message that needs parsing.
open func parseEngineMessage(_ msg: String) {
handleQueue.async {
self._parseEngineMessage(msg)
}
}
private func _parseEngineMessage(_ msg: String) {
guard let packet = parseSocketMessage(msg) else { return }
guard !packet.type.isBinary else {
waitingPackets.append(packet)
return
}
nsps[packet.nsp]?.handlePacket(packet)
}
/// Called when the engine receives binary data.
///
/// - parameter data: The data the engine received.
open func parseEngineBinaryData(_ data: Data) {
handleQueue.async {
self._parseEngineBinaryData(data)
}
}
private func _parseEngineBinaryData(_ data: Data) {
guard let packet = parseBinaryData(data) else { return }
nsps[packet.nsp]?.handlePacket(packet)
}
/// Tries to reconnect to the server.
///
/// This will cause a `SocketClientEvent.reconnect` event to be emitted, as well as
/// `SocketClientEvent.reconnectAttempt` events.
open func reconnect() {
guard !reconnecting else { return }
engine?.disconnect(reason: "manual reconnect")
}
/// Removes the socket from the manager's control. One of the disconnect methods should be called before calling this
/// method.
///
/// After calling this method the socket should no longer be considered usable.
///
/// - parameter socket: The socket to remove.
/// - returns: The socket removed, if it was owned by the manager.
@discardableResult
open func removeSocket(_ socket: SocketIOClient) -> SocketIOClient? {
return nsps.removeValue(forKey: socket.nsp)
}
private func tryReconnect(reason: String) {
guard reconnecting else { return }
DefaultSocketLogger.Logger.log("Starting reconnect", type: SocketManager.logType)
// Set status to connecting and emit reconnect for all sockets
forAll {socket in
guard socket.status == .connected else { return }
socket.setReconnecting(reason: reason)
}
_tryReconnect()
}
private func _tryReconnect() {
guard reconnects && reconnecting && status != .disconnected else { return }
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts {
return didDisconnect(reason: "Reconnect Failed")
}
DefaultSocketLogger.Logger.log("Trying to reconnect", type: SocketManager.logType)
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: .now() + interval, execute: _tryReconnect)
}
func reconnectInterval(attempts: Int) -> Double {
// apply exponential factor
let backoffFactor = pow(1.5, attempts)
let interval = Double(reconnectWait) * Double(truncating: backoffFactor as NSNumber)
// add in a random factor smooth thundering herds
let rand = Double.random(in: 0 ..< 1)
let randomFactor = rand * randomizationFactor * Double(truncating: interval as NSNumber)
// add in random factor, and clamp to min and max values
let combined = interval + randomFactor
return Double(fmax(Double(reconnectWait), fmin(combined, Double(reconnectWaitMax))))
}
/// Sets manager specific configs.
///
/// parameter config: The configs that should be set.
open func setConfigs(_ config: SocketIOClientConfiguration) {
for option in config {
switch option {
case let .forceNew(new):
forceNew = new
case let .handleQueue(queue):
handleQueue = queue
case let .reconnects(reconnects):
self.reconnects = reconnects
case let .reconnectAttempts(attempts):
reconnectAttempts = attempts
case let .reconnectWait(wait):
reconnectWait = abs(wait)
case let .reconnectWaitMax(wait):
reconnectWaitMax = abs(wait)
case let .randomizationFactor(factor):
randomizationFactor = factor
case let .log(log):
DefaultSocketLogger.Logger.log = log
case let .logger(logger):
DefaultSocketLogger.Logger = logger
case let .version(num):
version = num
case _:
continue
}
}
_config = config
if socketURL.absoluteString.hasPrefix("https://") {
_config.insert(.secure(true))
}
_config.insert(.path("/socket.io/"), replacing: false)
// If `ConfigSettable` & `SocketEngineSpec`, update its configs.
if var settableEngine = engine as? ConfigSettable & SocketEngineSpec {
settableEngine.engineQueue.sync {
settableEngine.setConfigs(self._config)
}
engine = settableEngine
}
}
/// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager.
///
/// Calling multiple times returns the same socket.
///
/// Sockets created from this method are retained by the manager.
/// Call one of the `disconnectSocket` methods on this class to remove the socket from manager control.
/// Or call `SocketIOClient.disconnect()` on the client.
///
/// - parameter nsp: The namespace for the socket.
/// - returns: A `SocketIOClient` for the given namespace.
open func socket(forNamespace nsp: String) -> SocketIOClient {
assert(nsp.hasPrefix("/"), "forNamespace must have a leading /")
if let socket = nsps[nsp] {
return socket
}
let client = SocketIOClient(manager: self, nsp: nsp)
nsps[nsp] = client
return client
}
// Test properties
func setTestStatus(_ status: SocketIOStatus) {
self.status = status
}
}

View File

@ -1,148 +0,0 @@
//
// Created by Erik Little on 10/18/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 Dispatch
import Foundation
// TODO Fix the types so that we aren't using concrete types
///
/// A manager for a socket.io connection.
///
/// A `SocketManagerSpec` is responsible for multiplexing multiple namespaces through a single `SocketEngineSpec`.
///
/// Example with `SocketManager`:
///
/// ```swift
/// let manager = SocketManager(socketURL: URL(string:"http://localhost:8080/")!)
/// let defaultNamespaceSocket = manager.defaultSocket
/// let swiftSocket = manager.socket(forNamespace: "/swift")
///
/// // defaultNamespaceSocket and swiftSocket both share a single connection to the server
/// ```
///
/// Sockets created through the manager are retained by the manager. So at the very least, a single strong reference
/// to the manager must be maintained to keep sockets alive.
///
/// 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.
///
public protocol SocketManagerSpec : SocketEngineClient {
// MARK: Properties
/// Returns the socket associated with the default namespace ("/").
var defaultSocket: SocketIOClient { get }
/// The engine for this manager.
var engine: SocketEngineSpec? { get set }
/// If `true` then every time `connect` is called, a new engine will be created.
var forceNew: Bool { get set }
// TODO Per socket queues?
/// The queue that all interaction with the client should occur on. This is the queue that event handlers are
/// called on.
var handleQueue: DispatchQueue { get set }
/// The sockets in this manager indexed by namespace.
var nsps: [String: SocketIOClient] { get set }
/// If `true`, this manager will try and reconnect on any disconnects.
var reconnects: Bool { get set }
/// The minimum number of seconds to wait before attempting to reconnect.
var reconnectWait: Int { get set }
/// The maximum number of seconds to wait before attempting to reconnect.
var reconnectWaitMax: Int { get set }
/// The randomization factor for calculating reconnect jitter.
var randomizationFactor: Double { get set }
/// The URL of the socket.io server.
var socketURL: URL { get }
/// The status of this manager.
var status: SocketIOStatus { get }
/// The version of socket.io in use.
var version: SocketIOVersion { get }
// MARK: Methods
/// Connects the underlying transport.
func connect()
/// Connects a socket through this manager's engine.
///
/// - parameter socket: The socket who we should connect through this manager.
/// - parameter withPayload: Optional payload to send on connect
func connectSocket(_ socket: SocketIOClient, withPayload: [String: Any]?)
/// Called when the manager has disconnected from socket.io.
///
/// - parameter reason: The reason for the disconnection.
func didDisconnect(reason: String)
/// Disconnects the manager and all associated sockets.
func disconnect()
/// Disconnects the given socket.
///
/// - parameter socket: The socket to disconnect.
func disconnectSocket(_ socket: SocketIOClient)
/// Disconnects the socket associated with `forNamespace`.
///
/// - parameter nsp: The namespace to disconnect from.
func disconnectSocket(forNamespace nsp: String)
/// Sends an event to the server on all namespaces in this manager.
///
/// - parameter event: The event to send.
/// - parameter items: The data to send with this event.
func emitAll(_ event: String, _ items: SocketData...)
/// Tries to reconnect to the server.
///
/// This will cause a `disconnect` event to be emitted, as well as an `reconnectAttempt` event.
func reconnect()
/// Removes the socket from the manager's control.
/// After calling this method the socket should no longer be considered usable.
///
/// - parameter socket: The socket to remove.
/// - returns: The socket removed, if it was owned by the manager.
@discardableResult
func removeSocket(_ socket: SocketIOClient) -> SocketIOClient?
/// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager.
///
/// Calling multiple times returns the same socket.
///
/// Sockets created from this method are retained by the manager.
/// Call one of the `disconnectSocket` methods on the implementing class to remove the socket from manager control.
/// Or call `SocketIOClient.disconnect()` on the client.
///
/// - parameter nsp: The namespace for the socket.
/// - returns: A `SocketIOClient` for the given namespace.
func socket(forNamespace nsp: String) -> SocketIOClient
}

View File

@ -1,250 +0,0 @@
//
// SocketPacket.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 1/18/15.
//
// 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
/// A struct that represents a socket.io packet.
public struct SocketPacket : CustomStringConvertible {
// MARK: Properties
private static let logType = "SocketPacket"
/// The namespace for this packet.
public let nsp: String
/// If > 0 then this packet is using acking.
public let id: Int
/// The type of this packet.
public let type: PacketType
/// An array of binary data for this packet.
public internal(set) var binary: [Data]
/// The data for this event.
///
/// Note: This includes all data inside of the socket.io packet payload array, which includes the event name for
/// event type packets.
public internal(set) var data: [Any]
/// Returns the payload for this packet, minus the event name if this is an event or binaryEvent type packet.
public var args: [Any] {
if type == .event || type == .binaryEvent && data.count != 0 {
return Array(data.dropFirst())
} else {
return data
}
}
private let placeholders: Int
/// A string representation of this packet.
public var description: String {
return "SocketPacket {type: \(String(type.rawValue)); data: " +
"\(String(describing: data)); id: \(id); placeholders: \(placeholders); nsp: \(nsp)}"
}
/// The event name for this packet.
public var event: String {
return String(describing: data[0])
}
/// A string representation of this packet.
public var packetString: String {
return createPacketString()
}
init(type: PacketType, data: [Any] = [Any](), id: Int = -1, nsp: String, placeholders: Int = 0,
binary: [Data] = [Data]()) {
self.data = data
self.id = id
self.nsp = nsp
self.type = type
self.placeholders = placeholders
self.binary = binary
}
mutating func addData(_ data: Data) -> Bool {
if placeholders == binary.count {
return true
}
binary.append(data)
if placeholders == binary.count {
fillInPlaceholders()
return true
} else {
return false
}
}
private func completeMessage(_ message: String) -> String {
guard data.count != 0 else { return message + "[]" }
guard let jsonSend = try? data.toJSON(), let jsonString = String(data: jsonSend, encoding: .utf8) else {
DefaultSocketLogger.Logger.error("Error creating JSON object in SocketPacket.completeMessage",
type: SocketPacket.logType)
return message + "[]"
}
return message + jsonString
}
private func createPacketString() -> String {
let typeString = String(type.rawValue)
// Binary count?
let binaryCountString = typeString + (type.isBinary ? "\(String(binary.count))-" : "")
// Namespace?
let nspString = binaryCountString + (nsp != "/" ? "\(nsp)," : "")
// Ack number?
let idString = nspString + (id != -1 ? String(id) : "")
return completeMessage(idString)
}
// Called when we have all the binary data for a packet
// calls _fillInPlaceholders, which replaces placeholders with the
// corresponding binary
private mutating func fillInPlaceholders() {
data = data.map(_fillInPlaceholders)
}
// Helper method that looks for placeholders
// If object is a collection it will recurse
// Returns the object if it is not a placeholder or the corresponding
// binary data
private func _fillInPlaceholders(_ object: Any) -> Any {
switch object {
case let dict as JSON:
if dict["_placeholder"] as? Bool ?? false {
return binary[dict["num"] as! Int]
} else {
return dict.reduce(into: JSON(), {cur, keyValue in
cur[keyValue.0] = _fillInPlaceholders(keyValue.1)
})
}
case let arr as [Any]:
return arr.map(_fillInPlaceholders)
default:
return object
}
}
}
public extension SocketPacket {
// MARK: PacketType enum
/// The type of packets.
enum PacketType: Int {
// MARK: Cases
/// Connect: 0
case connect
/// Disconnect: 1
case disconnect
/// Event: 2
case event
/// Ack: 3
case ack
/// Error: 4
case error
/// Binary Event: 5
case binaryEvent
/// Binary Ack: 6
case binaryAck
// MARK: Properties
/// Whether or not this type is binary
public var isBinary: Bool {
return self == .binaryAck || self == .binaryEvent
}
}
}
extension SocketPacket {
private static func findType(_ binCount: Int, ack: Bool) -> PacketType {
switch binCount {
case 0 where !ack:
return .event
case 0 where ack:
return .ack
case _ where !ack:
return .binaryEvent
case _ where ack:
return .binaryAck
default:
return .error
}
}
static func packetFromEmit(_ items: [Any], id: Int, nsp: String, ack: Bool, checkForBinary: Bool = true) -> SocketPacket {
if checkForBinary {
let (parsedData, binary) = deconstructData(items)
return SocketPacket(type: findType(binary.count, ack: ack), data: parsedData, id: id, nsp: nsp,
binary: binary)
} else {
return SocketPacket(type: findType(0, ack: ack), data: items, id: id, nsp: nsp)
}
}
}
private extension SocketPacket {
// Recursive function that looks for NSData in collections
static func shred(_ data: Any, binary: inout [Data]) -> Any {
let placeholder = ["_placeholder": true, "num": binary.count] as JSON
switch data {
case let bin as Data:
binary.append(bin)
return placeholder
case let arr as [Any]:
return arr.map({shred($0, binary: &binary)})
case let dict as JSON:
return dict.reduce(into: JSON(), {cur, keyValue in
cur[keyValue.0] = shred(keyValue.1, binary: &binary)
})
default:
return data
}
}
// Removes binary data from emit data
// Returns a type containing the de-binaryed data and the binary
static func deconstructData(_ data: [Any]) -> ([Any], [Data]) {
var binary = [Data]()
return (data.map({ shred($0, binary: &binary) }), binary)
}
}

View File

@ -1,181 +0,0 @@
//
// SocketParsable.swift
// Socket.IO-Client-Swift
//
// 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
/// Defines that a type will be able to parse socket.io-protocol messages.
public protocol SocketParsable : AnyObject {
// MARK: Methods
/// Called when the engine has received some binary data that should be attached to a packet.
///
/// Packets binary data should be sent directly after the packet that expects it, so there's confusion over
/// where the data should go. Data should be received in the order it is sent, so that the correct data is put
/// into the correct placeholder.
///
/// - parameter data: The data that should be attached to a packet.
func parseBinaryData(_ data: Data) -> SocketPacket?
/// Called when the engine has received a string that should be parsed into a socket.io packet.
///
/// - parameter message: The string that needs parsing.
/// - returns: A completed socket packet if there is no more data left to collect.
func parseSocketMessage(_ message: String) -> SocketPacket?
}
/// Errors that can be thrown during parsing.
public enum SocketParsableError : Error {
// MARK: Cases
/// Thrown when a packet received has an invalid data array, or is missing the data array.
case invalidDataArray
/// Thrown when an malformed packet is received.
case invalidPacket
/// Thrown when the parser receives an unknown packet type.
case invalidPacketType
}
/// Says that a type will be able to buffer binary data before all data for an event has come in.
public protocol SocketDataBufferable : AnyObject {
// MARK: Properties
/// A list of packets that are waiting for binary data.
///
/// The way that socket.io works all data should be sent directly after each packet.
/// So this should ideally be an array of one packet waiting for data.
///
/// **This should not be modified directly.**
var waitingPackets: [SocketPacket] { get set }
}
public extension SocketParsable where Self: SocketManagerSpec & SocketDataBufferable {
/// Parses a message from the engine, returning a complete SocketPacket or throwing.
///
/// - parameter message: The message to parse.
/// - returns: A completed packet, or throwing.
internal func parseString(_ message: String) throws -> SocketPacket {
var reader = SocketStringReader(message: message)
guard let type = Int(reader.read(count: 1)).flatMap({ SocketPacket.PacketType(rawValue: $0) }) else {
throw SocketParsableError.invalidPacketType
}
if !reader.hasNext {
return SocketPacket(type: type, nsp: "/")
}
var namespace = "/"
var placeholders = -1
if type.isBinary {
if let holders = Int(reader.readUntilOccurence(of: "-")) {
placeholders = holders
} else {
throw SocketParsableError.invalidPacket
}
}
if reader.currentCharacter == "/" {
namespace = reader.readUntilOccurence(of: ",")
}
if !reader.hasNext {
return SocketPacket(type: type, nsp: namespace, placeholders: placeholders)
}
var idString = ""
if type == .error {
reader.advance(by: -1)
} else {
while let int = Int(reader.read(count: 1)) {
idString += String(int)
}
reader.advance(by: -2)
}
var dataArray = String(message.utf16[message.utf16.index(reader.currentIndex, offsetBy: 1)...])!
if (type == .error || type == .connect) && !dataArray.hasPrefix("[") && !dataArray.hasSuffix("]") {
dataArray = "[" + dataArray + "]"
}
let data = try parseData(dataArray)
return SocketPacket(type: type, data: data, id: Int(idString) ?? -1, nsp: namespace, placeholders: placeholders)
}
// Parses data for events
private func parseData(_ data: String) throws -> [Any] {
do {
return try data.toArray()
} catch {
throw SocketParsableError.invalidDataArray
}
}
/// Called when the engine has received a string that should be parsed into a socket.io packet.
///
/// - parameter message: The string that needs parsing.
/// - returns: A completed socket packet or nil if the packet is invalid.
func parseSocketMessage(_ message: String) -> SocketPacket? {
guard !message.isEmpty else { return nil }
DefaultSocketLogger.Logger.log("Parsing \(message)", type: "SocketParser")
do {
let packet = try parseString(message)
DefaultSocketLogger.Logger.log("Decoded packet as: \(packet.description)", type: "SocketParser")
return packet
} catch {
DefaultSocketLogger.Logger.error("\(error): \(message)", type: "SocketParser")
return nil
}
}
/// Called when the engine has received some binary data that should be attached to a packet.
///
/// Packets binary data should be sent directly after the packet that expects it, so there's confusion over
/// where the data should go. Data should be received in the order it is sent, so that the correct data is put
/// into the correct placeholder.
///
/// - parameter data: The data that should be attached to a packet.
/// - returns: A completed socket packet if there is no more data left to collect.
func parseBinaryData(_ data: Data) -> SocketPacket? {
guard !waitingPackets.isEmpty else {
DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser")
return nil
}
// Should execute event?
guard waitingPackets[waitingPackets.count - 1].addData(data) else { return nil }
return waitingPackets.removeLast()
}
}

View File

@ -1,132 +0,0 @@
//
// SocketExtensions.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 7/1/2016.
//
// 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
enum JSONError : Error {
case notArray
case notNSDictionary
}
extension Array {
func toJSON() throws -> Data {
return try JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions(rawValue: 0))
}
}
extension CharacterSet {
static var allowedURLCharacterSet: CharacterSet {
return CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]\" {}^|").inverted
}
}
extension Dictionary where Key == String, Value == Any {
private static func keyValueToSocketIOClientOption(key: String, value: Any) -> SocketIOClientOption? {
switch (key, value) {
case let ("connectParams", params as [String: Any]):
return .connectParams(params)
case let ("cookies", cookies as [HTTPCookie]):
return .cookies(cookies)
case let ("extraHeaders", headers as [String: String]):
return .extraHeaders(headers)
case let ("forceNew", force as Bool):
return .forceNew(force)
case let ("forcePolling", force as Bool):
return .forcePolling(force)
case let ("forceWebsockets", force as Bool):
return .forceWebsockets(force)
case let ("handleQueue", queue as DispatchQueue):
return .handleQueue(queue)
case let ("log", log as Bool):
return .log(log)
case let ("logger", logger as SocketLogger):
return .logger(logger)
case let ("path", path as String):
return .path(path)
case let ("reconnects", reconnects as Bool):
return .reconnects(reconnects)
case let ("reconnectAttempts", attempts as Int):
return .reconnectAttempts(attempts)
case let ("reconnectWait", wait as Int):
return .reconnectWait(wait)
case let ("reconnectWaitMax", wait as Int):
return .reconnectWaitMax(wait)
case let ("randomizationFactor", factor as Double):
return .randomizationFactor(factor)
case let ("secure", secure as Bool):
return .secure(secure)
case let ("security", security as CertificatePinning):
return .security(security)
case let ("selfSigned", selfSigned as Bool):
return .selfSigned(selfSigned)
case let ("sessionDelegate", delegate as URLSessionDelegate):
return .sessionDelegate(delegate)
case let ("compress", compress as Bool):
return compress ? .compress : nil
case let ("enableSOCKSProxy", enable as Bool):
return .enableSOCKSProxy(enable)
case let ("version", version as Int):
return .version(SocketIOVersion(rawValue: version) ?? .three)
case _:
return nil
}
}
func toSocketConfiguration() -> SocketIOClientConfiguration {
var options = [] as SocketIOClientConfiguration
for (rawKey, value) in self {
if let opt = Dictionary.keyValueToSocketIOClientOption(key: rawKey, value: value) {
options.insert(opt)
}
}
return options
}
}
extension String {
func toArray() throws -> [Any] {
guard let stringData = data(using: .utf16, allowLossyConversion: false) else { return [] }
guard let array = try JSONSerialization.jsonObject(with: stringData, options: .mutableContainers) as? [Any] else {
throw JSONError.notArray
}
return array
}
func toDictionary() throws -> [String: Any] {
guard let binData = data(using: .utf16, allowLossyConversion: false) else { return [:] }
guard let json = try JSONSerialization.jsonObject(with: binData, options: .allowFragments) as? [String: Any] else {
throw JSONError.notNSDictionary
}
return json
}
func urlEncode() -> String? {
return addingPercentEncoding(withAllowedCharacters: .allowedURLCharacterSet)
}
}

View File

@ -1,86 +0,0 @@
//
// SocketTypes.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 4/8/15.
//
// 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
/// A marking protocol that says a type can be represented in a socket.io packet.
///
/// Example:
///
/// ```swift
/// struct CustomData : SocketData {
/// let name: String
/// let age: Int
///
/// func socketRepresentation() -> SocketData {
/// return ["name": name, "age": age]
/// }
/// }
///
/// socket.emit("myEvent", CustomData(name: "Erik", age: 24))
/// ```
public protocol SocketData {
// MARK: Methods
/// A representation of self that can sent over socket.io.
func socketRepresentation() throws -> SocketData
}
public extension SocketData {
/// Default implementation. Only works for native Swift types and a few Foundation types.
func socketRepresentation() -> SocketData {
return self
}
}
extension Array : SocketData { }
extension Bool : SocketData { }
extension Dictionary : SocketData { }
extension Double : SocketData { }
extension Int : SocketData { }
extension NSArray : SocketData { }
extension Data : SocketData { }
extension NSData : SocketData { }
extension NSDictionary : SocketData { }
extension NSString : SocketData { }
extension NSNull : SocketData { }
extension String : SocketData { }
/// A typealias for an ack callback.
public typealias AckCallback = ([Any]) -> ()
/// A typealias for a normal callback.
public typealias NormalCallback = ([Any], SocketAckEmitter) -> ()
/// A typealias for a queued POST
public typealias Post = (msg: String, completion: (() -> ())?)
typealias JSON = [String: Any]
typealias Probe = (msg: String, type: SocketEnginePacketType, data: [Data], completion: (() -> ())?)
typealias ProbeWaitQueue = [Probe]
enum Either<E, V> {
case left(E)
case right(V)
}

523
Source/SocketIOClient.swift Normal file
View File

@ -0,0 +1,523 @@
//
// SocketIOClient.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 11/23/14.
//
// 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
public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable {
public let socketURL: NSURL
public private(set) var engine: SocketEngineSpec?
public private(set) var status = SocketIOClientStatus.NotConnected
public var forceNew = false
public var nsp = "/"
public var options: Set<SocketIOClientOption>
public var reconnects = true
public var reconnectWait = 10
public var sid: String? {
return engine?.sid
}
private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL)
private let logType = "SocketIOClient"
private let parseQueue = dispatch_queue_create("com.socketio.parseQueue", DISPATCH_QUEUE_SERIAL)
private var anyHandler: ((SocketAnyEvent) -> Void)?
private var currentReconnectAttempt = 0
private var handlers = [SocketEventHandler]()
private var reconnectTimer: NSTimer?
private var ackHandlers = SocketAckManager()
private(set) var currentAck = -1
private(set) var handleQueue = dispatch_get_main_queue()
private(set) var reconnectAttempts = -1
var waitingData = [SocketPacket]()
/**
Type safe way to create a new SocketIOClient. opts can be omitted
*/
public init(socketURL: NSURL, options: Set<SocketIOClientOption> = []) {
self.options = options
self.socketURL = socketURL
if socketURL.absoluteString.hasPrefix("https://") {
self.options.insertIgnore(.Secure(true))
}
for option in options {
switch option {
case let .Reconnects(reconnects):
self.reconnects = reconnects
case let .ReconnectAttempts(attempts):
reconnectAttempts = attempts
case let .ReconnectWait(wait):
reconnectWait = abs(wait)
case let .Nsp(nsp):
self.nsp = nsp
case let .Log(log):
DefaultSocketLogger.Logger.log = log
case let .Logger(logger):
DefaultSocketLogger.Logger = logger
case let .HandleQueue(queue):
handleQueue = queue
case let .ForceNew(force):
forceNew = force
default:
continue
}
}
self.options.insertIgnore(.Path("/socket.io/"))
super.init()
}
/**
Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
If using Swift it's recommended to use `init(socketURL: NSURL, options: Set<SocketIOClientOption>)`
*/
public convenience init(socketURL: NSURL, options: NSDictionary?) {
self.init(socketURL: socketURL, options: options?.toSocketOptionsSet() ?? [])
}
/// Please use the NSURL based init
@available(*, deprecated=5.3)
public convenience init(socketURLString: String, options: Set<SocketIOClientOption> = []) {
guard let url = NSURL(string: socketURLString) else { fatalError("Incorrect url") }
self.init(socketURL: url, options: options)
}
/// Please use the NSURL based init
@available(*, deprecated=5.3)
public convenience init(socketURLString: String, options: NSDictionary?) {
guard let url = NSURL(string: socketURLString) else { fatalError("Incorrect url") }
self.init(socketURL: url, options: options?.toSocketOptionsSet() ?? [])
}
deinit {
DefaultSocketLogger.Logger.log("Client is being released", type: logType)
engine?.close("Client Deinit")
}
private func addEngine() -> SocketEngineSpec {
DefaultSocketLogger.Logger.log("Adding engine", type: logType)
engine = SocketEngine(client: self, url: socketURL, options: options)
return engine!
}
private func clearReconnectTimer() {
reconnectTimer?.invalidate()
reconnectTimer = nil
}
@available(*, deprecated=5.3)
public func close() {
disconnect()
}
/**
Connect to the server.
*/
public func connect() {
connect(timeoutAfter: 0, withTimeoutHandler: nil)
}
/**
Connect to the server. If we aren't connected after timeoutAfter, call handler
*/
public func connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?) {
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
guard status != .Connected else {
DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket",
type: logType)
return
}
status = .Connecting
if engine == nil || forceNew {
addEngine().open()
} else {
engine?.open()
}
guard timeoutAfter != 0 else { return }
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
dispatch_after(time, handleQueue) {[weak self] in
if let this = self where this.status != .Connected {
this.status = .Closed
this.engine?.close("Connect timeout")
handler?()
}
}
}
private func createOnAck(items: [AnyObject]) -> OnAckCallback {
currentAck += 1
return {[weak self, ack = currentAck] timeout, callback in
if let this = self {
this.ackHandlers.addAck(ack, callback: callback)
dispatch_async(this.emitQueue) {
this._emit(items, ack: ack)
}
if timeout != 0 {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC))
dispatch_after(time, this.handleQueue) {
this.ackHandlers.timeoutAck(ack)
}
}
}
}
}
func didConnect() {
DefaultSocketLogger.Logger.log("Socket connected", type: logType)
status = .Connected
currentReconnectAttempt = 0
clearReconnectTimer()
// Don't handle as internal because something crazy could happen where
// we disconnect before it's handled
handleEvent("connect", data: [], isInternalMessage: false)
}
func didDisconnect(reason: String) {
guard status != .Closed else {
return
}
DefaultSocketLogger.Logger.log("Disconnected: %@", type: logType, args: reason)
status = .Closed
reconnects = false
// Make sure the engine is actually dead.
engine?.close(reason)
handleEvent("disconnect", data: [reason], isInternalMessage: true)
}
/**
Disconnects the socket. Only reconnect the same socket if you know what you're doing.
Will turn off automatic reconnects.
*/
public func disconnect() {
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
reconnects = false
didDisconnect("Disconnect")
}
/**
Send a message to the server
*/
public func emit(event: String, _ items: AnyObject...) {
emit(event, withItems: items)
}
/**
Same as emit, but meant for Objective-C
*/
public func emit(event: String, withItems items: [AnyObject]) {
guard status == .Connected else {
handleEvent("error", data: ["Tried emitting \(event) when not connected"], isInternalMessage: true)
return
}
dispatch_async(emitQueue) {
self._emit([event] + items)
}
}
/**
Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
an ack.
*/
public func emitWithAck(event: String, _ items: AnyObject...) -> OnAckCallback {
return emitWithAck(event, withItems: items)
}
/**
Same as emitWithAck, but for Objective-C
*/
public func emitWithAck(event: String, withItems items: [AnyObject]) -> OnAckCallback {
return createOnAck([event] + items)
}
private func _emit(data: [AnyObject], ack: Int? = nil) {
guard status == .Connected else {
handleEvent("error", data: ["Tried emitting when not connected"], isInternalMessage: true)
return
}
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false)
let str = packet.packetString
DefaultSocketLogger.Logger.log("Emitting: %@", type: logType, args: str)
engine?.send(str, withData: packet.binary)
}
// If the server wants to know that the client received data
func emitAck(ack: Int, withItems items: [AnyObject]) {
dispatch_async(emitQueue) {
if self.status == .Connected {
let packet = SocketPacket.packetFromEmit(items, id: ack ?? -1, nsp: self.nsp, ack: true)
let str = packet.packetString
DefaultSocketLogger.Logger.log("Emitting Ack: %@", type: self.logType, args: str)
self.engine?.send(str, withData: packet.binary)
}
}
}
public func engineDidClose(reason: String) {
waitingData.removeAll()
if status == .Closed || !reconnects {
didDisconnect(reason)
} else if status != .Reconnecting {
status = .Reconnecting
handleEvent("reconnect", data: [reason], isInternalMessage: true)
tryReconnect()
}
}
/// error
public func engineDidError(reason: String) {
DefaultSocketLogger.Logger.error("%@", type: logType, args: reason)
handleEvent("error", data: [reason], isInternalMessage: true)
}
// Called when the socket gets an ack for something it sent
func handleAck(ack: Int, data: [AnyObject]) {
guard status == .Connected else {return}
DefaultSocketLogger.Logger.log("Handling ack: %@ with data: %@", type: logType, args: ack, data ?? "")
ackHandlers.executeAck(ack, items: data)
}
/**
Causes an event to be handled. Only use if you know what you're doing.
*/
public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int = -1) {
guard status == .Connected || isInternalMessage else {
return
}
DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "")
dispatch_async(handleQueue) {
self.anyHandler?(SocketAnyEvent(event: event, items: data))
for handler in self.handlers where handler.event == event {
handler.executeCallback(data, withAck: ack, withSocket: self)
}
}
}
/**
Leaves nsp and goes back to /
*/
public func leaveNamespace() {
if nsp != "/" {
engine?.send("1\(nsp)", withData: [])
nsp = "/"
}
}
/**
Joins namespace
*/
public func joinNamespace(namespace: String) {
nsp = namespace
if nsp != "/" {
DefaultSocketLogger.Logger.log("Joining namespace", type: logType)
engine?.send("0\(nsp)", withData: [])
}
}
/**
Removes handler(s)
*/
public func off(event: String) {
DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: logType, args: event)
handlers = handlers.filter { $0.event != event }
}
/**
Removes a handler with the specified UUID gotten from an `on` or `once`
*/
public func off(id id: NSUUID) {
DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id)
handlers = handlers.filter { $0.id != id }
}
/**
Adds a handler for an event.
Returns: A unique id for the handler
*/
public func on(event: String, callback: NormalCallback) -> NSUUID {
DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event)
let handler = SocketEventHandler(event: event, id: NSUUID(), callback: callback)
handlers.append(handler)
return handler.id
}
/**
Adds a single-use handler for an event.
Returns: A unique id for the handler
*/
public func once(event: String, callback: NormalCallback) -> NSUUID {
DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: logType, args: event)
let id = NSUUID()
let handler = SocketEventHandler(event: event, id: id) {[weak self] data, ack in
guard let this = self else { return }
this.off(id: id)
callback(data, ack)
}
handlers.append(handler)
return handler.id
}
/**
Adds a handler that will be called on every event.
*/
public func onAny(handler: (SocketAnyEvent) -> Void) {
anyHandler = handler
}
/**
Same as connect
*/
@available(*, deprecated=5.3)
public func open() {
connect()
}
public func parseEngineMessage(msg: String) {
DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg)
dispatch_async(parseQueue) {
self.parseSocketMessage(msg)
}
}
public func parseEngineBinaryData(data: NSData) {
dispatch_async(parseQueue) {
self.parseBinaryData(data)
}
}
/**
Tries to reconnect to the server.
*/
public func reconnect() {
tryReconnect()
}
/**
Removes all handlers.
Can be used after disconnecting to break any potential remaining retain cycles.
*/
public func removeAllHandlers() {
handlers.removeAll(keepCapacity: false)
}
private func tryReconnect() {
if reconnectTimer == nil {
DefaultSocketLogger.Logger.log("Starting reconnect", type: logType)
status = .Reconnecting
dispatch_async(dispatch_get_main_queue()) {
self.reconnectTimer = NSTimer.scheduledTimerWithTimeInterval(Double(self.reconnectWait),
target: self, selector: "_tryReconnect", userInfo: nil, repeats: true)
}
}
}
@objc private func _tryReconnect() {
if status == .Connected {
clearReconnectTimer()
return
}
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
clearReconnectTimer()
didDisconnect("Reconnect Failed")
return
}
DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType)
handleEvent("reconnectAttempt", data: [reconnectAttempts - currentReconnectAttempt],
isInternalMessage: true)
currentReconnectAttempt += 1
connect()
}
}
// Test extensions
extension SocketIOClient {
var testHandlers: [SocketEventHandler] {
return handlers
}
func setTestable() {
status = .Connected
}
func setTestEngine(engine: SocketEngineSpec?) {
self.engine = engine
}
func emitTest(event: String, _ data: AnyObject...) {
self._emit([event] + data)
}
}

View File

@ -0,0 +1,213 @@
//
// SocketIOClientOption .swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/17/15.
//
// 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
protocol ClientOption: CustomStringConvertible, Hashable {
func getSocketIOOptionValue() -> AnyObject
}
public enum SocketIOClientOption: ClientOption {
case ConnectParams([String: AnyObject])
case Cookies([NSHTTPCookie])
case ExtraHeaders([String: String])
case ForceNew(Bool)
case ForcePolling(Bool)
case ForceWebsockets(Bool)
case HandleQueue(dispatch_queue_t)
case Log(Bool)
case Logger(SocketLogger)
case Nsp(String)
case Path(String)
case Reconnects(Bool)
case ReconnectAttempts(Int)
case ReconnectWait(Int)
case Secure(Bool)
case SelfSigned(Bool)
case SessionDelegate(NSURLSessionDelegate)
case VoipEnabled(Bool)
public var description: String {
let description: String
switch self {
case .ConnectParams:
description = "connectParams"
case .Cookies:
description = "cookies"
case .ExtraHeaders:
description = "extraHeaders"
case .ForceNew:
description = "forceNew"
case .ForcePolling:
description = "forcePolling"
case .ForceWebsockets:
description = "forceWebsockets"
case .HandleQueue:
description = "handleQueue"
case .Log:
description = "log"
case .Logger:
description = "logger"
case .Nsp:
description = "nsp"
case .Path:
description = "path"
case .Reconnects:
description = "reconnects"
case .ReconnectAttempts:
description = "reconnectAttempts"
case .ReconnectWait:
description = "reconnectWait"
case .Secure:
description = "secure"
case .SelfSigned:
description = "selfSigned"
case .SessionDelegate:
description = "sessionDelegate"
case .VoipEnabled:
description = "voipEnabled"
}
return description
}
public var hashValue: Int {
return description.hashValue
}
func getSocketIOOptionValue() -> AnyObject {
let value: AnyObject
switch self {
case let .ConnectParams(params):
value = params
case let .Cookies(cookies):
value = cookies
case let .ExtraHeaders(headers):
value = headers
case let .ForceNew(force):
value = force
case let .ForcePolling(force):
value = force
case let .ForceWebsockets(force):
value = force
case let .HandleQueue(queue):
value = queue
case let .Log(log):
value = log
case let .Logger(logger):
value = logger
case let .Nsp(nsp):
value = nsp
case let .Path(path):
value = path
case let .Reconnects(reconnects):
value = reconnects
case let .ReconnectAttempts(attempts):
value = attempts
case let .ReconnectWait(wait):
value = wait
case let .Secure(secure):
value = secure
case let .SelfSigned(signed):
value = signed
case let .SessionDelegate(delegate):
value = delegate
case let .VoipEnabled(enabled):
value = enabled
}
return value
}
}
public func ==(lhs: SocketIOClientOption, rhs: SocketIOClientOption) -> Bool {
return lhs.description == rhs.description
}
extension Set where Element: ClientOption {
mutating func insertIgnore(element: Element) {
if !contains(element) {
insert(element)
}
}
}
extension NSDictionary {
static func keyValueToSocketIOClientOption(key: String, value: AnyObject) -> SocketIOClientOption? {
switch (key, value) {
case let ("connectParams", params as [String: AnyObject]):
return .ConnectParams(params)
case let ("reconnects", reconnects as Bool):
return .Reconnects(reconnects)
case let ("reconnectAttempts", attempts as Int):
return .ReconnectAttempts(attempts)
case let ("reconnectWait", wait as Int):
return .ReconnectWait(wait)
case let ("forceNew", force as Bool):
return .ForceNew(force)
case let ("forcePolling", force as Bool):
return .ForcePolling(force)
case let ("forceWebsockets", force as Bool):
return .ForceWebsockets(force)
case let ("nsp", nsp as String):
return .Nsp(nsp)
case let ("cookies", cookies as [NSHTTPCookie]):
return .Cookies(cookies)
case let ("log", log as Bool):
return .Log(log)
case let ("logger", logger as SocketLogger):
return .Logger(logger)
case let ("sessionDelegate", delegate as NSURLSessionDelegate):
return .SessionDelegate(delegate)
case let ("path", path as String):
return .Path(path)
case let ("extraHeaders", headers as [String: String]):
return .ExtraHeaders(headers)
case let ("handleQueue", queue as dispatch_queue_t):
return .HandleQueue(queue)
case let ("voipEnabled", enable as Bool):
return .VoipEnabled(enable)
case let ("secure", secure as Bool):
return .Secure(secure)
case let ("selfSigned", selfSigned as Bool):
return .SelfSigned(selfSigned)
default:
return nil
}
}
func toSocketOptionsSet() -> Set<SocketIOClientOption> {
var options = Set<SocketIOClientOption>()
for (rawKey, value) in self {
if let key = rawKey as? String, opt = NSDictionary.keyValueToSocketIOClientOption(key, value: value) {
options.insertIgnore(opt)
}
}
return options
}
}

View File

@ -1,5 +1,5 @@
//
// SocketIOStatus.swift
// SocketIOClientStatus.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 8/14/15.
@ -24,36 +24,21 @@
import Foundation
/// Represents state of a manager or client.
@objc
public enum SocketIOStatus : Int, CustomStringConvertible {
// MARK: Cases
/// The client/manager has never been connected. Or the client has been reset.
case notConnected
/// The client/manager was once connected, but not anymore.
case disconnected
/// The client/manager is in the process of connecting.
case connecting
/// The client/manager is currently connected.
case connected
// MARK: Properties
/// - returns: True if this client/manager is connected/connecting to a server.
public var active: Bool {
return self == .connected || self == .connecting
}
@objc public enum SocketIOClientStatus: Int, CustomStringConvertible {
case NotConnected, Closed, Connecting, Connected, Reconnecting
public var description: String {
switch self {
case .connected: return "connected"
case .connecting: return "connecting"
case .disconnected: return "disconnected"
case .notConnected: return "notConnected"
case NotConnected:
return "Not Connected"
case Closed:
return "Closed"
case Connecting:
return "Connecting"
case Connected:
return "Connected"
case Reconnecting:
return "Reconnecting"
}
}
}

View File

@ -24,51 +24,37 @@
import Foundation
/// Represents a class will log client events.
public protocol SocketLogger : AnyObject {
// MARK: Properties
public protocol SocketLogger: class {
/// Whether to log or not
var log: Bool { get set }
// MARK: Methods
var log: Bool {get set}
/// Normal log messages
///
/// - parameter message: The message being logged. Can include `%@` that will be replaced with `args`
/// - parameter type: The type of entity that called for logging.
/// - parameter args: Any args that should be inserted into the message. May be left out.
func log(_ message: @autoclosure () -> String, type: String)
func log(message: String, type: String, args: AnyObject...)
/// Error Messages
///
/// - parameter message: The message being logged. Can include `%@` that will be replaced with `args`
/// - parameter type: The type of entity that called for logging.
/// - parameter args: Any args that should be inserted into the message. May be left out.
func error(_ message: @autoclosure () -> String, type: String)
func error(message: String, type: String, args: AnyObject...)
}
public extension SocketLogger {
/// Default implementation.
func log(_ message: @autoclosure () -> String, type: String) {
guard log else { return }
abstractLog("LOG", message: message(), type: type)
func log(message: String, type: String, args: AnyObject...) {
abstractLog("LOG", message: message, type: type, args: args)
}
/// Default implementation.
func error(_ message: @autoclosure () -> String, type: String) {
guard log else { return }
abstractLog("ERROR", message: message(), type: type)
func error(message: String, type: String, args: AnyObject...) {
abstractLog("ERROR", message: message, type: type, args: args)
}
private func abstractLog(_ logType: String, message: @autoclosure () -> String, type: String) {
NSLog("\(logType) \(type): %@", message())
private func abstractLog(logType: String, message: String, type: String, args: [AnyObject]) {
guard log else { return }
let newArgs = args.map({arg -> CVarArgType in String(arg)})
let replaced = String(format: message, arguments: newArgs)
NSLog("%@ %@: %@", logType, type, replaced)
}
}
class DefaultSocketLogger : SocketLogger {
class DefaultSocketLogger: SocketLogger {
static var Logger: SocketLogger = DefaultSocketLogger()
var log = false

274
Source/SocketPacket.swift Normal file
View File

@ -0,0 +1,274 @@
//
// SocketPacket.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 1/18/15.
//
// 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
struct SocketPacket {
private let placeholders: Int
private static let logType = "SocketPacket"
let nsp: String
let id: Int
let type: PacketType
enum PacketType: Int {
case Connect, Disconnect, Event, Ack, Error, BinaryEvent, BinaryAck
}
var args: [AnyObject] {
if type == .Event || type == .BinaryEvent && data.count != 0 {
return Array(data.dropFirst())
} else {
return data
}
}
var binary: [NSData]
var data: [AnyObject]
var description: String {
return "SocketPacket {type: \(String(type.rawValue)); data: " +
"\(String(data)); id: \(id); placeholders: \(placeholders); nsp: \(nsp)}"
}
var event: String {
return String(data[0])
}
var packetString: String {
return createPacketString()
}
init(type: SocketPacket.PacketType, data: [AnyObject] = [AnyObject](), id: Int = -1,
nsp: String, placeholders: Int = 0, binary: [NSData] = [NSData]()) {
self.data = data
self.id = id
self.nsp = nsp
self.type = type
self.placeholders = placeholders
self.binary = binary
}
mutating func addData(data: NSData) -> Bool {
if placeholders == binary.count {
return true
}
binary.append(data)
if placeholders == binary.count {
fillInPlaceholders()
return true
} else {
return false
}
}
private func completeMessage(message: String, ack: Bool) -> String {
var restOfMessage = ""
if data.count == 0 {
return message + "]"
}
for arg in data {
if arg is NSDictionary || arg is [AnyObject] {
do {
let jsonSend = try NSJSONSerialization.dataWithJSONObject(arg,
options: NSJSONWritingOptions(rawValue: 0))
let jsonString = String(data: jsonSend, encoding: NSUTF8StringEncoding)
restOfMessage += jsonString! + ","
} catch {
DefaultSocketLogger.Logger.error("Error creating JSON object in SocketPacket.completeMessage",
type: SocketPacket.logType)
}
} else if let str = arg as? String {
restOfMessage += "\"" + ((str["\n"] <~ "\\\\n")["\r"] <~ "\\\\r") + "\","
} else if arg is NSNull {
restOfMessage += "null,"
} else {
restOfMessage += "\(arg),"
}
}
if restOfMessage != "" {
restOfMessage.removeAtIndex(restOfMessage.endIndex.predecessor())
}
return message + restOfMessage + "]"
}
private func createAck() -> String {
let message: String
if type == .Ack {
if nsp == "/" {
message = "3\(id)["
} else {
message = "3\(nsp),\(id)["
}
} else {
if nsp == "/" {
message = "6\(binary.count)-\(id)["
} else {
message = "6\(binary.count)-\(nsp),\(id)["
}
}
return completeMessage(message, ack: true)
}
private func createMessageForEvent() -> String {
let message: String
if type == .Event {
if nsp == "/" {
if id == -1 {
message = "2["
} else {
message = "2\(id)["
}
} else {
if id == -1 {
message = "2\(nsp),["
} else {
message = "2\(nsp),\(id)["
}
}
} else {
if nsp == "/" {
if id == -1 {
message = "5\(binary.count)-["
} else {
message = "5\(binary.count)-\(id)["
}
} else {
if id == -1 {
message = "5\(binary.count)-\(nsp),["
} else {
message = "5\(binary.count)-\(nsp),\(id)["
}
}
}
return completeMessage(message, ack: false)
}
private func createPacketString() -> String {
let str: String
if type == .Event || type == .BinaryEvent {
str = createMessageForEvent()
} else {
str = createAck()
}
return str
}
// Called when we have all the binary data for a packet
// calls _fillInPlaceholders, which replaces placeholders with the
// corresponding binary
private mutating func fillInPlaceholders() {
data = data.map(_fillInPlaceholders)
}
// Helper method that looks for placeholder strings
// If object is a collection it will recurse
// Returns the object if it is not a placeholder string or the corresponding
// binary data
private func _fillInPlaceholders(object: AnyObject) -> AnyObject {
switch object {
case let string as String where string["~~(\\d)"].groups() != nil:
return binary[Int(string["~~(\\d)"].groups()![1])!]
case let dict as NSDictionary:
return dict.reduce(NSMutableDictionary(), combine: {cur, keyValue in
cur[keyValue.0 as! NSCopying] = _fillInPlaceholders(keyValue.1)
return cur
})
case let arr as [AnyObject]:
return arr.map(_fillInPlaceholders)
default:
return object
}
}
}
extension SocketPacket {
private static func findType(binCount: Int, ack: Bool) -> PacketType {
switch binCount {
case 0 where !ack:
return .Event
case 0 where ack:
return .Ack
case _ where !ack:
return .BinaryEvent
case _ where ack:
return .BinaryAck
default:
return .Error
}
}
static func packetFromEmit(items: [AnyObject], id: Int, nsp: String, ack: Bool) -> SocketPacket {
let (parsedData, binary) = deconstructData(items)
let packet = SocketPacket(type: findType(binary.count, ack: ack), data: parsedData,
id: id, nsp: nsp, placeholders: -1, binary: binary)
return packet
}
}
private extension SocketPacket {
// Recursive function that looks for NSData in collections
static func shred(data: AnyObject, inout binary: [NSData]) -> AnyObject {
let placeholder = ["_placeholder": true, "num": binary.count]
switch data {
case let bin as NSData:
binary.append(bin)
return placeholder
case let arr as [AnyObject]:
return arr.map({shred($0, binary: &binary)})
case let dict as NSDictionary:
return dict.reduce(NSMutableDictionary(), combine: {cur, keyValue in
cur[keyValue.0 as! NSCopying] = shred(keyValue.1, binary: &binary)
return cur
})
default:
return data
}
}
// Removes binary data from emit data
// Returns a type containing the de-binaryed data and the binary
static func deconstructData(data: [AnyObject]) -> ([AnyObject], [NSData]) {
var binary = [NSData]()
return (data.map({shred($0, binary: &binary)}), binary)
}
}

182
Source/SocketParsable.swift Normal file
View File

@ -0,0 +1,182 @@
//
// SocketParsable.swift
// Socket.IO-Client-Swift
//
// 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
protocol SocketParsable: SocketClientSpec {
func parseBinaryData(data: NSData)
func parseSocketMessage(message: String)
}
extension SocketParsable {
private func isCorrectNamespace(nsp: String) -> Bool {
return nsp == self.nsp
}
private func handleConnect(p: SocketPacket) {
if p.nsp == "/" && nsp != "/" {
joinNamespace(nsp)
} else if p.nsp != "/" && nsp == "/" {
didConnect()
} else {
didConnect()
}
}
private func handlePacket(pack: SocketPacket) {
switch pack.type {
case .Event where isCorrectNamespace(pack.nsp):
handleEvent(pack.event, data: pack.args,
isInternalMessage: false, withAck: pack.id)
case .Ack where isCorrectNamespace(pack.nsp):
handleAck(pack.id, data: pack.data)
case .BinaryEvent where isCorrectNamespace(pack.nsp):
waitingData.append(pack)
case .BinaryAck where isCorrectNamespace(pack.nsp):
waitingData.append(pack)
case .Connect:
handleConnect(pack)
case .Disconnect:
didDisconnect("Got Disconnect")
case .Error:
handleEvent("error", data: pack.data, isInternalMessage: true, withAck: pack.id)
default:
DefaultSocketLogger.Logger.log("Got invalid packet: %@", type: "SocketParser", args: pack.description)
}
}
/// Parses a messsage from the engine. Returning either a string error or a complete SocketPacket
func parseString(message: String) -> Either<String, SocketPacket> {
var parser = SocketStringReader(message: message)
guard let type = SocketPacket.PacketType(rawValue: Int(parser.read(1)) ?? -1) else {
return .Left("Invalid packet type")
}
if !parser.hasNext {
return .Right(SocketPacket(type: type, nsp: "/"))
}
var namespace: String?
var placeholders = -1
if type == .BinaryEvent || type == .BinaryAck {
if let holders = Int(parser.readUntilStringOccurence("-")) {
placeholders = holders
} else {
return .Left("Invalid packet")
}
}
if parser.currentCharacter == "/" {
namespace = parser.readUntilStringOccurence(",") ?? parser.readUntilEnd()
}
if !parser.hasNext {
return .Right(SocketPacket(type: type, id: -1,
nsp: namespace ?? "/", placeholders: placeholders))
}
var idString = ""
if type == .Error {
parser.advanceIndexBy(-1)
}
while parser.hasNext && type != .Error {
if let int = Int(parser.read(1)) {
idString += String(int)
} else {
parser.advanceIndexBy(-2)
break
}
}
let d = message[parser.currentIndex.advancedBy(1)..<message.endIndex]
let noPlaceholders = d["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] <~ "\"~~$2\""
switch parseData(noPlaceholders) {
case let .Left(err):
// If first you don't succeed, try again
if case let .Right(data) = parseData("\([noPlaceholders as AnyObject])") {
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
nsp: namespace ?? "/", placeholders: placeholders))
} else {
return .Left(err)
}
case let .Right(data):
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
nsp: namespace ?? "/", placeholders: placeholders))
}
}
// Parses data for events
private func parseData(data: String) -> Either<String, [AnyObject]> {
let stringData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
do {
if let arr = try NSJSONSerialization.JSONObjectWithData(stringData!,
options: NSJSONReadingOptions.MutableContainers) as? [AnyObject] {
return .Right(arr)
} else {
return .Left("Expected data array")
}
} catch {
return .Left("Error parsing data for packet")
}
}
// Parses messages recieved
func parseSocketMessage(message: String) {
guard !message.isEmpty else { return }
DefaultSocketLogger.Logger.log("Parsing %@", type: "SocketParser", args: message)
switch parseString(message) {
case let .Left(err):
DefaultSocketLogger.Logger.error("\(err): %@", type: "SocketParser", args: message)
case let .Right(pack):
DefaultSocketLogger.Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description)
handlePacket(pack)
}
}
func parseBinaryData(data: NSData) {
guard !waitingData.isEmpty else {
DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser")
return
}
// Should execute event?
guard waitingData[waitingData.count - 1].addData(data) else {
return
}
let packet = waitingData.removeLast()
if packet.type != .BinaryAck {
handleEvent(packet.event, data: packet.args ?? [],
isInternalMessage: false, withAck: packet.id)
} else {
handleAck(packet.id, data: packet.args)
}
}
}

View File

@ -24,50 +24,45 @@
struct SocketStringReader {
let message: String
var currentIndex: String.UTF16View.Index
var currentIndex: String.Index
var hasNext: Bool {
return currentIndex != message.utf16.endIndex
return currentIndex != message.endIndex
}
var currentCharacter: String {
return String(UnicodeScalar(message.utf16[currentIndex])!)
return String(message[currentIndex])
}
init(message: String) {
self.message = message
currentIndex = message.utf16.startIndex
currentIndex = message.startIndex
}
@discardableResult
mutating func advance(by: Int) -> String.UTF16View.Index {
currentIndex = message.utf16.index(currentIndex, offsetBy: by)
return currentIndex
mutating func advanceIndexBy(n: Int) {
currentIndex = currentIndex.advancedBy(n)
}
mutating func read(count: Int) -> String {
let readString = String(message.utf16[currentIndex..<message.utf16.index(currentIndex, offsetBy: count)])!
advance(by: count)
mutating func read(readLength: Int) -> String {
let readString = message[currentIndex..<currentIndex.advancedBy(readLength)]
advanceIndexBy(readLength)
return readString
}
mutating func readUntilOccurence(of string: String) -> String {
let substring = message.utf16[currentIndex...]
mutating func readUntilStringOccurence(string: String) -> String {
let substring = message[currentIndex..<message.endIndex]
guard let foundRange = substring.rangeOfString(string) else {
currentIndex = message.endIndex
guard let foundIndex = substring.firstIndex(where: { $0 == string.utf16.first! }) else {
currentIndex = message.utf16.endIndex
return String(substring)!
return substring
}
advance(by: substring.distance(from: substring.startIndex, to: foundIndex) + 1)
advanceIndexBy(message.startIndex.distanceTo(foundRange.startIndex) + 1)
return String(substring[substring.startIndex..<foundIndex])!
return substring.substringToIndex(foundRange.startIndex)
}
mutating func readUntilEnd() -> String {
return read(count: message.utf16.distance(from: currentIndex, to: message.utf16.endIndex))
return read(currentIndex.distanceTo(message.endIndex))
}
}

34
Source/SocketTypes.swift Normal file
View File

@ -0,0 +1,34 @@
//
// SocketTypes.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 4/8/15.
//
// 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
public typealias AckCallback = ([AnyObject]) -> Void
public typealias NormalCallback = ([AnyObject], SocketAckEmitter) -> Void
public typealias OnAckCallback = (timeoutAfter: UInt64, callback: AckCallback) -> Void
enum Either<E, V> {
case Left(E)
case Right(V)
}

184
Source/SwiftRegex.swift Normal file
View File

@ -0,0 +1,184 @@
//
// SwiftRegex.swift
// SwiftRegex
//
// Created by John Holdsworth on 26/06/2014.
// Copyright (c) 2014 John Holdsworth.
//
// $Id: //depot/SwiftRegex/SwiftRegex.swift#37 $
//
// This code is in the public domain from:
// https://github.com/johnno1962/SwiftRegex
//
import Foundation
infix operator <~ { associativity none precedence 130 }
private let lock = dispatch_semaphore_create(1)
private var swiftRegexCache = [String: NSRegularExpression]()
internal final class SwiftRegex: NSObject, BooleanType {
var target:String
var regex: NSRegularExpression
init(target:String, pattern:String, options:NSRegularExpressionOptions?) {
if dispatch_semaphore_wait(lock, dispatch_time(DISPATCH_TIME_NOW, Int64(10 * NSEC_PER_MSEC))) != 0 {
fatalError("This should never happen")
}
self.target = target
if let regex = swiftRegexCache[pattern] {
self.regex = regex
} else {
do {
let regex = try NSRegularExpression(pattern: pattern, options:
NSRegularExpressionOptions.DotMatchesLineSeparators)
swiftRegexCache[pattern] = regex
self.regex = regex
} catch let error as NSError {
SwiftRegex.failure("Error in pattern: \(pattern) - \(error)")
self.regex = NSRegularExpression()
}
}
dispatch_semaphore_signal(lock)
super.init()
}
private static func failure(message: String) {
fatalError("SwiftRegex: \(message)")
}
private var targetRange: NSRange {
return NSRange(location: 0,length: target.utf16.count)
}
private func substring(range: NSRange) -> String? {
if range.location != NSNotFound {
return (target as NSString).substringWithRange(range)
} else {
return nil
}
}
func doesMatch(options: NSMatchingOptions!) -> Bool {
return range(options).location != NSNotFound
}
func range(options: NSMatchingOptions) -> NSRange {
return regex.rangeOfFirstMatchInString(target as String, options: [], range: targetRange)
}
func match(options: NSMatchingOptions) -> String? {
return substring(range(options))
}
func groups() -> [String]? {
return groupsForMatch(regex.firstMatchInString(target as String, options:
NSMatchingOptions.WithoutAnchoringBounds, range: targetRange))
}
private func groupsForMatch(match: NSTextCheckingResult?) -> [String]? {
guard let match = match else {
return nil
}
var groups = [String]()
for groupno in 0...regex.numberOfCaptureGroups {
if let group = substring(match.rangeAtIndex(groupno)) {
groups += [group]
} else {
groups += ["_"] // avoids bridging problems
}
}
return groups
}
subscript(groupno: Int) -> String? {
get {
return groups()?[groupno]
}
set(newValue) {
if newValue == nil {
return
}
for match in Array(matchResults().reverse()) {
let replacement = regex.replacementStringForResult(match,
inString: target as String, offset: 0, template: newValue!)
let mut = NSMutableString(string: target)
mut.replaceCharactersInRange(match.rangeAtIndex(groupno), withString: replacement)
target = mut as String
}
}
}
func matchResults() -> [NSTextCheckingResult] {
let matches = regex.matchesInString(target as String, options:
NSMatchingOptions.WithoutAnchoringBounds, range: targetRange)
as [NSTextCheckingResult]
return matches
}
func ranges() -> [NSRange] {
return matchResults().map { $0.range }
}
func matches() -> [String] {
return matchResults().map( { self.substring($0.range)!})
}
func allGroups() -> [[String]?] {
return matchResults().map { self.groupsForMatch($0) }
}
func dictionary(options: NSMatchingOptions!) -> Dictionary<String,String> {
var out = Dictionary<String,String>()
for match in matchResults() {
out[substring(match.rangeAtIndex(1))!] = substring(match.rangeAtIndex(2))!
}
return out
}
func substituteMatches(substitution: ((NSTextCheckingResult, UnsafeMutablePointer<ObjCBool>) -> String),
options:NSMatchingOptions) -> String {
let out = NSMutableString()
var pos = 0
regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) {match, flags, stop in
let matchRange = match!.range
out.appendString( self.substring(NSRange(location:pos, length:matchRange.location-pos))!)
out.appendString( substitution(match!, stop) )
pos = matchRange.location + matchRange.length
}
out.appendString(substring(NSRange(location:pos, length:targetRange.length-pos))!)
return out as String
}
var boolValue: Bool {
return doesMatch(nil)
}
}
extension String {
subscript(pattern: String, options: NSRegularExpressionOptions) -> SwiftRegex {
return SwiftRegex(target: self, pattern: pattern, options: options)
}
}
extension String {
subscript(pattern: String) -> SwiftRegex {
return SwiftRegex(target: self, pattern: pattern, options: nil)
}
}
func <~ (left: SwiftRegex, right: String) -> String {
return left.substituteMatches({match, stop in
return left.regex.replacementStringForResult( match,
inString: left.target as String, offset: 0, template: right )
}, options: [])
}

1043
Source/WebSocket.swift Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,50 +0,0 @@
//
// SocketAckManagerTest.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 04.09.15.
//
//
import XCTest
@testable import SocketIO
class SocketAckManagerTest : XCTestCase {
var ackManager = SocketAckManager()
func testAddAcks() {
let callbackExpection = expectation(description: "callbackExpection")
let itemsArray = ["Hi", "ho"]
func callback(_ items: [Any]) {
callbackExpection.fulfill()
}
ackManager.addAck(1, callback: callback)
ackManager.executeAck(1, with: itemsArray)
waitForExpectations(timeout: 3.0, handler: nil)
}
func testManagerTimeoutAck() {
let callbackExpection = expectation(description: "Manager should timeout ack with noAck status")
func callback(_ items: [Any]) {
XCTAssertEqual(items.count, 1, "Timed out ack should have one value")
guard let timeoutReason = items[0] as? String else {
XCTFail("Timeout reason should be a string")
return
}
XCTAssert(timeoutReason == SocketAckStatus.noAck)
callbackExpection.fulfill()
}
ackManager.addAck(1, callback: callback)
ackManager.timeoutAck(1)
waitForExpectations(timeout: 0.2, handler: nil)
}
}

View File

@ -1,215 +0,0 @@
//
// SocketBasicPacketTest.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/7/15.
//
//
import XCTest
@testable import SocketIO
class SocketBasicPacketTest : XCTestCase {
func testEmptyEmit() {
let sendData = ["test"]
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .event)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testNullEmit() {
let sendData: [Any] = ["test", NSNull()]
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .event)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testStringEmit() {
let sendData = ["test", "foo bar"]
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .event)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testStringEmitWithQuotes() {
let sendData = ["test", "\"he\"llo world\""]
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .event)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testJSONEmit() {
let sendData: [Any] = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .event)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testArrayEmit() {
let sendData: [Any] = ["test", ["hello", 1, ["test": "test"]]]
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .event)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testBinaryEmit() {
let sendData: [Any] = ["test", data]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .binaryEvent)
XCTAssertEqual(packet.binary, [data])
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
"test",
["_placeholder": true, "num": 0]
]))
}
func testMultipleBinaryEmit() {
let sendData: [Any] = ["test", ["data1": data, "data2": data2] as NSDictionary]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .binaryEvent)
let binaryObj = parsed.data[1] as! [String: Any]
let data1Loc = (binaryObj["data1"] as! [String: Any])["num"] as! Int
let data2Loc = (binaryObj["data2"] as! [String: Any])["num"] as! Int
XCTAssertEqual(packet.binary[data1Loc], data)
XCTAssertEqual(packet.binary[data2Loc], data2)
}
func testEmitWithAck() {
let sendData = ["test"]
let packetStr = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .event)
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testEmitDataWithAck() {
let sendData: [Any] = ["test", data]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .binaryEvent)
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
"test",
["_placeholder": true, "num": 0]
]))
XCTAssertEqual(packet.binary, [data])
}
// Acks
func testEmptyAck() {
let packetStr = SocketPacket.packetFromEmit([], id: 0, nsp: "/", ack: true).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .ack)
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: []))
}
func testNullAck() {
let sendData = [NSNull()]
let packetStr = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .ack)
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testStringAck() {
let sendData = ["test"]
let packetStr = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .ack)
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testJSONAck() {
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
let packetStr = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true).packetString
let parsed = parser.parseSocketMessage(packetStr)!
XCTAssertEqual(parsed.type, .ack)
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testBinaryAck() {
let sendData = [data]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .binaryAck)
XCTAssertEqual(packet.binary, [data])
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
["_placeholder": true, "num": 0]
]))
}
func testMultipleBinaryAck() {
let sendData = [["data1": data, "data2": data2]]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.id, 0)
XCTAssertEqual(parsed.type, .binaryAck)
let binaryObj = parsed.data[0] as! [String: Any]
let data1Loc = (binaryObj["data1"] as! [String: Any])["num"] as! Int
let data2Loc = (binaryObj["data2"] as! [String: Any])["num"] as! Int
XCTAssertEqual(packet.binary[data1Loc], data)
XCTAssertEqual(packet.binary[data2Loc], data2)
}
func testBinaryStringPlaceholderInMessage() {
let engineString = "52-[\"test\",\"~~0\",{\"num\":0,\"_placeholder\":true},{\"_placeholder\":true,\"num\":1}]"
let manager = SocketManager(socketURL: URL(string: "http://localhost/")!)
var packet = try! manager.parseString(engineString)
XCTAssertEqual(packet.event, "test")
_ = packet.addData(data)
_ = packet.addData(data2)
XCTAssertEqual(packet.args[0] as? String, "~~0")
}
private func compareAnyArray(input: [Any], expected: [Any]) -> Bool {
guard input.count == expected.count else { return false }
return (input as NSArray).isEqual(to: expected)
}
let data = "test".data(using: String.Encoding.utf8)!
let data2 = "test2".data(using: String.Encoding.utf8)!
var parser: SocketParsable!
override func setUp() {
super.setUp()
parser = SocketManager(socketURL: URL(string: "http://localhost")!)
}
}

View File

@ -1,229 +0,0 @@
//
// SocketEngineTest.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/15/15.
//
//
import XCTest
@testable import SocketIO
class SocketEngineTest: XCTestCase {
func testBasicPollingMessageV3() {
let expect = expectation(description: "Basic polling test v3")
socket.on("blankTest") {data, ack in
expect.fulfill()
}
engine.setConfigs([.version(.two)])
engine.parsePollingMessage("15:42[\"blankTest\"]")
waitForExpectations(timeout: 3, handler: nil)
}
func testBasicPollingMessage() {
let expect = expectation(description: "Basic polling test")
socket.on("blankTest") {data, ack in
expect.fulfill()
}
engine.parsePollingMessage("42[\"blankTest\"]")
waitForExpectations(timeout: 3, handler: nil)
}
func testTwoPacketsInOnePollTest() {
let finalExpectation = expectation(description: "Final packet in poll test")
var gotBlank = false
socket.on("blankTest") {data, ack in
gotBlank = true
}
socket.on("stringTest") {data, ack in
if let str = data[0] as? String, gotBlank {
if str == "hello" {
finalExpectation.fulfill()
}
}
}
engine.parsePollingMessage("42[\"blankTest\"]\u{1e}42[\"stringTest\",\"hello\"]")
waitForExpectations(timeout: 3, handler: nil)
}
func testEngineDoesErrorOnUnknownTransport() {
let finalExpectation = expectation(description: "Unknown Transport")
socket.on("error") {data, ack in
if let error = data[0] as? String, error == "Unknown transport" {
finalExpectation.fulfill()
}
}
engine.parseEngineMessage("{\"code\": 0, \"message\": \"Unknown transport\"}")
waitForExpectations(timeout: 3, handler: nil)
}
func testEngineDoesErrorOnUnknownMessage() {
let finalExpectation = expectation(description: "Engine Errors")
socket.on("error") {data, ack in
finalExpectation.fulfill()
}
engine.parseEngineMessage("afafafda")
waitForExpectations(timeout: 3, handler: nil)
}
func testEngineDecodesUTF8Properly() {
let expect = expectation(description: "Engine Decodes utf8")
socket.on("stringTest") {data, ack in
XCTAssertEqual(data[0] as? String, "lïne one\nlīne \rtwo𦅙𦅛", "Failed string test")
expect.fulfill()
}
let stringMessage = "42[\"stringTest\",\"lïne one\\nlīne \\rtwo𦅙𦅛\"]"
engine.parsePollingMessage("\(stringMessage)")
waitForExpectations(timeout: 3, handler: nil)
}
func testEncodeURLProperly() {
engine.connectParams = [
"created": "2016-05-04T18:31:15+0200"
]
XCTAssertEqual(engine.urlPolling.query, "transport=polling&b64=1&created=2016-05-04T18%3A31%3A15%2B0200&EIO=4")
XCTAssertEqual(engine.urlWebSocket.query, "transport=websocket&created=2016-05-04T18%3A31%3A15%2B0200&EIO=4")
engine.connectParams = [
"forbidden": "!*'();:@&=+$,/?%#[]\" {}^|"
]
XCTAssertEqual(engine.urlPolling.query, "transport=polling&b64=1&forbidden=%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%25%23%5B%5D%22%20%7B%7D%5E%7C&EIO=4")
XCTAssertEqual(engine.urlWebSocket.query, "transport=websocket&forbidden=%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%25%23%5B%5D%22%20%7B%7D%5E%7C&EIO=4")
}
func testBase64Data() {
let expect = expectation(description: "Engine Decodes base64 data")
let b64String = "baGVsbG8NCg=="
let packetString = "451-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]"
socket.on("test") {data, ack in
if let data = data[0] as? Data, let string = String(data: data, encoding: .utf8) {
XCTAssertEqual(string, "hello")
}
expect.fulfill()
}
engine.parseEngineMessage(packetString)
engine.parseEngineMessage(b64String)
waitForExpectations(timeout: 3, handler: nil)
}
func testSettingExtraHeadersBeforeConnectSetsEngineExtraHeaders() {
let newValue = ["hello": "world"]
manager.engine = engine
manager.setTestStatus(.notConnected)
manager.config = [.extraHeaders(["new": "value"])]
manager.config.insert(.extraHeaders(newValue), replacing: true)
XCTAssertEqual(2, manager.config.count)
XCTAssertEqual(manager.engine!.extraHeaders!, newValue)
for config in manager.config {
switch config {
case let .extraHeaders(headers):
XCTAssertTrue(headers.keys.contains("hello"), "It should contain hello header key")
XCTAssertFalse(headers.keys.contains("new"), "It should not contain old data")
case .path:
continue
default:
XCTFail("It should only have two configs")
}
}
}
func testSettingExtraHeadersAfterConnectDoesNotIgnoreChanges() {
let newValue = ["hello": "world"]
manager.engine = engine
manager.setTestStatus(.connected)
engine.setConnected(true)
manager.config = [.extraHeaders(["new": "value"])]
manager.config.insert(.extraHeaders(["hello": "world"]), replacing: true)
XCTAssertEqual(2, manager.config.count)
XCTAssertEqual(manager.engine!.extraHeaders!, newValue)
}
func testSettingPathAfterConnectDoesNotIgnoreChanges() {
let newValue = "/newpath/"
manager.engine = engine
manager.setTestStatus(.connected)
engine.setConnected(true)
manager.config.insert(.path(newValue))
XCTAssertEqual(1, manager.config.count)
XCTAssertEqual(manager.engine!.socketPath, newValue)
}
func testSettingCompressAfterConnectDoesNotIgnoreChanges() {
manager.engine = engine
manager.setTestStatus(.connected)
engine.setConnected(true)
manager.config.insert(.compress)
XCTAssertEqual(2, manager.config.count)
XCTAssertTrue(manager.engine!.compress)
}
func testSettingForcePollingAfterConnectDoesNotIgnoreChanges() {
manager.engine = engine
manager.setTestStatus(.connected)
engine.setConnected(true)
manager.config.insert(.forcePolling(true))
XCTAssertEqual(2, manager.config.count)
XCTAssertTrue(manager.engine!.forcePolling)
}
func testSettingForceWebSocketsAfterConnectDoesNotIgnoreChanges() {
manager.engine = engine
manager.setTestStatus(.connected)
engine.setConnected(true)
manager.config.insert(.forceWebsockets(true))
XCTAssertEqual(2, manager.config.count)
XCTAssertTrue(manager.engine!.forceWebsockets)
}
func testChangingEngineHeadersAfterInit() {
engine.extraHeaders = ["Hello": "World"]
let req = engine.createRequestForPostWithPostWait()
XCTAssertEqual("World", req.allHTTPHeaderFields?["Hello"])
}
var manager: SocketManager!
var socket: SocketIOClient!
var engine: SocketEngine!
override func setUp() {
super.setUp()
manager = SocketManager(socketURL: URL(string: "http://localhost")!)
socket = manager.defaultSocket
engine = SocketEngine(client: manager, url: URL(string: "http://localhost")!, options: nil)
socket.setTestable()
}
}

View File

@ -1,46 +0,0 @@
//
// TestSocketIOClientConfiguration.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 8/13/16.
//
//
import XCTest
import SocketIO
class TestSocketIOClientConfiguration : XCTestCase {
func testReplaceSameOption() {
config.insert(.log(true))
XCTAssertEqual(config.count, 2)
switch config[0] {
case let .log(log):
XCTAssertTrue(log)
default:
XCTFail()
}
}
func testIgnoreIfExisting() {
config.insert(.forceNew(false), replacing: false)
XCTAssertEqual(config.count, 2)
switch config[1] {
case let .forceNew(new):
XCTAssertTrue(new)
default:
XCTFail()
}
}
var config = [] as SocketIOClientConfiguration
override func setUp() {
config = [.log(false), .forceNew(true)]
super.setUp()
}
}

View File

@ -1,247 +0,0 @@
//
// Created by Erik Little on 10/21/17.
//
import Dispatch
import Foundation
@testable import SocketIO
import XCTest
class SocketMangerTest : XCTestCase {
func testManagerProperties() {
XCTAssertNotNil(manager.defaultSocket)
XCTAssertNil(manager.engine)
XCTAssertFalse(manager.forceNew)
XCTAssertEqual(manager.handleQueue, DispatchQueue.main)
XCTAssertTrue(manager.reconnects)
XCTAssertEqual(manager.reconnectWait, 10)
XCTAssertEqual(manager.reconnectWaitMax, 30)
XCTAssertEqual(manager.randomizationFactor, 0.5)
XCTAssertEqual(manager.status, .notConnected)
}
func testSettingConfig() {
let manager = SocketManager(socketURL: URL(string: "https://example.com/")!)
XCTAssertEqual(manager.config.first!, .secure(true))
manager.config = []
XCTAssertEqual(manager.config.first!, .secure(true))
}
func testBackoffIntervalCalulation() {
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: -1), Double(manager.reconnectWaitMax))
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 0), 15)
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 1), 22.5)
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 2), 33.75)
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 50), Double(manager.reconnectWaitMax))
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 10000), Double(manager.reconnectWaitMax))
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: -1), Double(manager.reconnectWait))
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 0), Double(manager.reconnectWait))
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 1), 15)
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 2), 22.5)
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 10000), Double(manager.reconnectWait))
}
func testManagerCallsConnect() {
setUpSockets()
socket.expectations[ManagerExpectation.didConnectCalled] = expectation(description: "The manager should call connect on the default socket")
socket2.expectations[ManagerExpectation.didConnectCalled] = expectation(description: "The manager should call connect on the socket")
socket.connect()
socket2.connect()
manager.fakeConnecting()
manager.fakeConnecting(toNamespace: "/swift")
waitForExpectations(timeout: 0.3)
}
func testManagerDoesNotCallConnectWhenConnectingWithLessThanOneReconnect() {
setUpSockets()
let expect = expectation(description: "The manager should not call connect on the engine")
expect.isInverted = true
let engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
engine.onConnect = {
expect.fulfill()
}
manager.setTestStatus(.connecting)
manager.setCurrentReconnect(currentReconnect: 0)
manager.engine = engine
manager.connect()
waitForExpectations(timeout: 0.3)
}
func testManagerCallConnectWhenConnectingAndMoreThanOneReconnect() {
setUpSockets()
let expect = expectation(description: "The manager should call connect on the engine")
let engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
engine.onConnect = {
expect.fulfill()
}
manager.setTestStatus(.connecting)
manager.setCurrentReconnect(currentReconnect: 1)
manager.engine = engine
manager.connect()
waitForExpectations(timeout: 0.8)
}
func testManagerCallsDisconnect() {
setUpSockets()
socket.expectations[ManagerExpectation.didDisconnectCalled] = expectation(description: "The manager should call disconnect on the default socket")
socket2.expectations[ManagerExpectation.didDisconnectCalled] = expectation(description: "The manager should call disconnect on the socket")
socket2.on(clientEvent: .connect) {data, ack in
self.manager.disconnect()
self.manager.fakeDisconnecting()
}
socket.connect()
socket2.connect()
manager.fakeConnecting()
manager.fakeConnecting(toNamespace: "/swift")
waitForExpectations(timeout: 0.3)
}
// func testManagerEmitAll() {
// setUpSockets()
//
// socket.expectations[ManagerExpectation.emitAllEventCalled] = expectation(description: "The manager should emit an event to the default socket")
// socket2.expectations[ManagerExpectation.emitAllEventCalled] = expectation(description: "The manager should emit an event to the socket")
//
// socket2.on(clientEvent: .connect) {data, ack in
// print("connect")
// self.manager.emitAll("event", "testing")
// }
//
// socket.connect()
// socket2.connect()
//
// manager.fakeConnecting(toNamespace: "/swift")
//
// waitForExpectations(timeout: 0.3)
// }
func testManagerSetsConfigs() {
let queue = DispatchQueue(label: "testQueue")
manager = TestManager(socketURL: URL(string: "http://localhost/")!, config: [
.handleQueue(queue),
.forceNew(true),
.reconnects(false),
.reconnectWait(5),
.reconnectWaitMax(5),
.randomizationFactor(0.7),
.reconnectAttempts(5)
])
XCTAssertEqual(manager.handleQueue, queue)
XCTAssertTrue(manager.forceNew)
XCTAssertFalse(manager.reconnects)
XCTAssertEqual(manager.reconnectWait, 5)
XCTAssertEqual(manager.reconnectWaitMax, 5)
XCTAssertEqual(manager.randomizationFactor, 0.7)
XCTAssertEqual(manager.reconnectAttempts, 5)
}
func testManagerRemovesSocket() {
setUpSockets()
manager.removeSocket(socket)
XCTAssertNil(manager.nsps[socket.nsp])
}
private func setUpSockets() {
socket = manager.testSocket(forNamespace: "/")
socket2 = manager.testSocket(forNamespace: "/swift")
}
private var manager: TestManager!
private var socket: TestSocket!
private var socket2: TestSocket!
override func setUp() {
super.setUp()
manager = TestManager(socketURL: URL(string: "http://localhost/")!, config: [.log(false)])
socket = nil
socket2 = nil
}
}
public enum ManagerExpectation: String {
case didConnectCalled
case didDisconnectCalled
case emitAllEventCalled
}
public class TestManager: SocketManager {
public func setCurrentReconnect(currentReconnect: Int) {
self.currentReconnectAttempt = currentReconnect
}
public override func disconnect() {
setTestStatus(.disconnected)
}
public func testSocket(forNamespace nsp: String) -> TestSocket {
return socket(forNamespace: nsp) as! TestSocket
}
public func fakeDisconnecting() {
engineDidClose(reason: "")
}
public func fakeConnecting(toNamespace nsp: String = "/") {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// Fake connecting
self.parseEngineMessage("0\(nsp)")
}
}
public override func socket(forNamespace nsp: String) -> SocketIOClient {
// set socket to our test socket, the superclass method will get this from nsps
nsps[nsp] = TestSocket(manager: self, nsp: nsp)
return super.socket(forNamespace: nsp)
}
}
public class TestSocket: SocketIOClient {
public var expectations = [ManagerExpectation: XCTestExpectation]()
public override func didConnect(toNamespace nsp: String, payload: [String: Any]?) {
expectations[ManagerExpectation.didConnectCalled]?.fulfill()
expectations[ManagerExpectation.didConnectCalled] = nil
super.didConnect(toNamespace: nsp, payload: payload)
}
public override func didDisconnect(reason: String) {
expectations[ManagerExpectation.didDisconnectCalled]?.fulfill()
expectations[ManagerExpectation.didDisconnectCalled] = nil
super.didDisconnect(reason: reason)
}
public override func emit(_ event: String, _ items: SocketData..., completion: (() -> ())? = nil) {
expectations[ManagerExpectation.emitAllEventCalled]?.fulfill()
expectations[ManagerExpectation.emitAllEventCalled] = nil
}
}

View File

@ -1,206 +0,0 @@
//
// SocketNamespacePacketTest.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/11/15.
//
//
import XCTest
@testable import SocketIO
class SocketNamespacePacketTest : XCTestCase {
func testEmptyEmit() {
let sendData: [Any] = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .event)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testNullEmit() {
let sendData: [Any] = ["test", NSNull()]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .event)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testStringEmit() {
let sendData: [Any] = ["test", "foo bar"]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .event)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testJSONEmit() {
let sendData: [Any] = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()] as NSDictionary]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .event)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testArrayEmit() {
let sendData: [Any] = ["test", ["hello", 1, ["test": "test"], true]]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .event)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testBinaryEmit() {
let sendData: [Any] = ["test", data]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .binaryEvent)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertEqual(packet.binary, [data])
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
"test",
["_placeholder": true, "num": 0]
]))
}
func testMultipleBinaryEmit() {
let sendData: [Any] = ["test", ["data1": data, "data2": data2] as NSDictionary]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .binaryEvent)
XCTAssertEqual(parsed.nsp, "/swift")
let binaryObj = parsed.data[1] as! [String: Any]
let data1Loc = (binaryObj["data1"] as! [String: Any])["num"] as! Int
let data2Loc = (binaryObj["data2"] as! [String: Any])["num"] as! Int
XCTAssertEqual(packet.binary[data1Loc], data)
XCTAssertEqual(packet.binary[data2Loc], data2)
}
func testEmitWithAck() {
let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .event)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testEmitDataWithAck() {
let sendData: [Any] = ["test", data]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .binaryEvent)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
"test",
["_placeholder": true, "num": 0]
]))
}
// Acks
func testEmptyAck() {
let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/swift", ack: true)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .ack)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertEqual(parsed.id, 0)
}
func testNullAck() {
let sendData = [NSNull()]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .ack)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testStringAck() {
let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .ack)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testJSONAck() {
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .ack)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
}
func testBinaryAck() {
let sendData = [data]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .binaryAck)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertEqual(parsed.id, 0)
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
["_placeholder": true, "num": 0]
]))
}
func testMultipleBinaryAck() {
let sendData = [["data1": data, "data2": data2]]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
let parsed = parser.parseSocketMessage(packet.packetString)!
XCTAssertEqual(parsed.type, .binaryAck)
XCTAssertEqual(parsed.nsp, "/swift")
XCTAssertEqual(parsed.id, 0)
let binaryObj = parsed.data[0] as! [String: Any]
let data1Loc = (binaryObj["data1"] as! [String: Any])["num"] as! Int
let data2Loc = (binaryObj["data2"] as! [String: Any])["num"] as! Int
XCTAssertEqual(packet.binary[data1Loc], data)
XCTAssertEqual(packet.binary[data2Loc], data2)
}
let data = "test".data(using: String.Encoding.utf8)!
let data2 = "test2".data(using: String.Encoding.utf8)!
var parser: SocketParsable!
private func compareAnyArray(input: [Any], expected: [Any]) -> Bool {
guard input.count == expected.count else { return false }
return (input as NSArray).isEqual(to: expected)
}
override func setUp() {
super.setUp()
parser = SocketManager(socketURL: URL(string: "http://localhost")!)
}
}

View File

@ -1,507 +0,0 @@
//
// SocketSideEffectTest.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/11/15.
//
//
import XCTest
@testable import SocketIO
import Starscream
class SocketSideEffectTest: XCTestCase {
func testInitialCurrentAck() {
XCTAssertEqual(socket.currentAck, -1)
}
func testFirstAck() {
socket.emitWithAck("test").timingOut(after: 0) {data in}
XCTAssertEqual(socket.currentAck, 0)
}
func testSecondAck() {
socket.emitWithAck("test").timingOut(after: 0) {data in}
socket.emitWithAck("test").timingOut(after: 0) {data in}
XCTAssertEqual(socket.currentAck, 1)
}
func testEmitCompletionSyntax() {
socket.emit("test", completion: {})
socket.emit("test", "thing", completion: {})
}
func testHandleAck() {
let expect = expectation(description: "handled ack")
socket.emitWithAck("test").timingOut(after: 0) {data in
XCTAssertEqual(data[0] as? String, "hello world")
expect.fulfill()
}
manager.parseEngineMessage("30[\"hello world\"]")
waitForExpectations(timeout: 3, handler: nil)
}
func testHandleAckWithAckEmit() {
let expect = expectation(description: "handled ack")
socket.emitWithAck("test").timingOut(after: 0) {data in
XCTAssertEqual(data[0] as? String, "hello world")
self.socket.emitWithAck("test").timingOut(after: 0) {data in}
expect.fulfill()
}
manager.parseEngineMessage("30[\"hello world\"]")
waitForExpectations(timeout: 3, handler: nil)
}
func testHandleAck2() {
let expect = expectation(description: "handled ack2")
socket.emitWithAck("test").timingOut(after: 0) {data in
XCTAssertTrue(data.count == 2, "Wrong number of ack items")
expect.fulfill()
}
manager.parseEngineMessage("61-0[{\"_placeholder\":true,\"num\":0},{\"test\":true}]")
manager.parseEngineBinaryData(Data())
waitForExpectations(timeout: 3, handler: nil)
}
func testHandleEvent() {
let expect = expectation(description: "handled event")
socket.on("test") {data, ack in
XCTAssertEqual(data[0] as? String, "hello world")
expect.fulfill()
}
manager.parseEngineMessage("2[\"test\",\"hello world\"]")
waitForExpectations(timeout: 3, handler: nil)
}
func testHandleStringEventWithQuotes() {
let expect = expectation(description: "handled event")
socket.on("test") {data, ack in
XCTAssertEqual(data[0] as? String, "\"hello world\"")
expect.fulfill()
}
manager.parseEngineMessage("2[\"test\",\"\\\"hello world\\\"\"]")
waitForExpectations(timeout: 3, handler: nil)
}
func testHandleOnceEvent() {
let expect = expectation(description: "handled event")
socket.once("test") {data, ack in
XCTAssertEqual(data[0] as? String, "hello world")
XCTAssertEqual(self.socket.testHandlers.count, 0)
expect.fulfill()
}
manager.parseEngineMessage("2[\"test\",\"hello world\"]")
waitForExpectations(timeout: 3, handler: nil)
}
func testHandleOnceClientEvent() {
let expect = expectation(description: "handled event")
socket.setTestStatus(.connecting)
socket.once(clientEvent: .connect) {data, ack in
XCTAssertEqual(self.socket.testHandlers.count, 0)
expect.fulfill()
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
// Fake connecting
self.manager.parseEngineMessage("0/")
}
waitForExpectations(timeout: 3, handler: nil)
}
func testOffWithEvent() {
socket.on("test") {data, ack in }
socket.on("test") {data, ack in }
XCTAssertEqual(socket.testHandlers.count, 2)
socket.off("test")
XCTAssertEqual(socket.testHandlers.count, 0)
}
func testOffClientEvent() {
socket.on(clientEvent: .connect) {data, ack in }
socket.on(clientEvent: .disconnect) {data, ack in }
XCTAssertEqual(socket.testHandlers.count, 2)
socket.off(clientEvent: .disconnect)
XCTAssertEqual(socket.testHandlers.count, 1)
XCTAssertTrue(socket.testHandlers.contains(where: { $0.event == "connect" }))
}
func testOffWithId() {
let handler = socket.on("test") {data, ack in }
XCTAssertEqual(socket.testHandlers.count, 1)
socket.on("test") {data, ack in }
XCTAssertEqual(socket.testHandlers.count, 2)
socket.off(id: handler)
XCTAssertEqual(socket.testHandlers.count, 1)
}
func testHandlesErrorPacket() {
let expect = expectation(description: "Handled error")
socket.on("error") {data, ack in
if let error = data[0] as? String, error == "test error" {
expect.fulfill()
}
}
manager.parseEngineMessage("4\"test error\"")
waitForExpectations(timeout: 3, handler: nil)
}
func testHandleBinaryEvent() {
let expect = expectation(description: "handled binary event")
socket.on("test") {data, ack in
if let dict = data[0] as? [String: Any], let data = dict["test"] as? Data {
XCTAssertEqual(data as Data, self.data)
expect.fulfill()
}
}
manager.parseEngineMessage("51-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]")
manager.parseEngineBinaryData(data)
waitForExpectations(timeout: 3, handler: nil)
}
func testHandleMultipleBinaryEvent() {
let expect = expectation(description: "handled multiple binary event")
socket.on("test") {data, ack in
if let dict = data[0] as? [String: Any], let data = dict["test"] as? Data,
let data2 = dict["test2"] as? Data {
XCTAssertEqual(data as Data, self.data)
XCTAssertEqual(data2 as Data, self.data2)
expect.fulfill()
}
}
manager.parseEngineMessage("52-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0},\"test2\":{\"_placeholder\":true,\"num\":1}}]")
manager.parseEngineBinaryData(data)
manager.parseEngineBinaryData(data2)
waitForExpectations(timeout: 3, handler: nil)
}
func testChangingStatusCallsStatusChangeHandler() {
let expect = expectation(description: "The client should announce when the status changes")
let statusChange = SocketIOStatus.connecting
socket.on("statusChange") {data, ack in
guard let status = data[0] as? SocketIOStatus else {
XCTFail("Status should be one of the defined statuses")
return
}
XCTAssertEqual(status, statusChange, "The status changed should be the one set")
expect.fulfill()
}
socket.setTestStatus(statusChange)
waitForExpectations(timeout: 0.2)
}
func testOnClientEvent() {
let expect = expectation(description: "The client should call client event handlers")
let event = SocketClientEvent.disconnect
let closeReason = "testing"
socket.on(clientEvent: event) {data, ack in
guard let reason = data[0] as? String else {
XCTFail("Client should pass data for client events")
return
}
XCTAssertEqual(closeReason, reason, "The data should be what was sent to handleClientEvent")
expect.fulfill()
}
socket.handleClientEvent(event, data: [closeReason])
waitForExpectations(timeout: 0.2)
}
func testClientEventsAreBackwardsCompatible() {
let expect = expectation(description: "The client should call old style client event handlers")
let event = SocketClientEvent.disconnect
let closeReason = "testing"
socket.on("disconnect") {data, ack in
guard let reason = data[0] as? String else {
XCTFail("Client should pass data for client events")
return
}
XCTAssertEqual(closeReason, reason, "The data should be what was sent to handleClientEvent")
expect.fulfill()
}
socket.handleClientEvent(event, data: [closeReason])
waitForExpectations(timeout: 0.2)
}
func testConnectTimesOutIfNotConnected() {
let expect = expectation(description: "The client should call the timeout function")
socket = manager.socket(forNamespace: "/someNamespace")
socket.setTestStatus(.notConnected)
manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
socket.connect(timeoutAfter: 0.5, withHandler: {
expect.fulfill()
})
waitForExpectations(timeout: 0.8)
}
func testConnectDoesNotTimeOutIfConnected() {
let expect = expectation(description: "The client should not call the timeout function")
socket.setTestStatus(.notConnected)
manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
socket.on(clientEvent: .connect) {data, ack in
expect.fulfill()
}
socket.connect(timeoutAfter: 0.5, withHandler: {
XCTFail("Should not call timeout handler if status is connected")
})
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
// Fake connecting
self.manager.parseEngineMessage("0/")
}
waitForExpectations(timeout: 2)
}
func testClientCallsConnectOnEngineOpen() {
let expect = expectation(description: "The client call the connect handler")
let eng = TestEngine(client: manager, url: manager.socketURL, options: nil)
eng.onConnect = {
self.socket.didConnect(toNamespace: self.socket.nsp, payload: nil)
}
manager.engine = eng
socket.setTestStatus(.notConnected)
socket.on(clientEvent: .connect) {data, ack in
expect.fulfill()
}
socket.connect(timeoutAfter: 0.5, withHandler: {
XCTFail("Should not call timeout handler if status is connected")
})
waitForExpectations(timeout: 2)
}
func testConnectIsCalledWithNamespace() {
let expect = expectation(description: "The client should not call the timeout function")
let nspString = "/swift"
socket = manager.socket(forNamespace: "/swift")
socket.setTestStatus(.notConnected)
manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
socket.on(clientEvent: .connect) {data, ack in
guard let nsp = data[0] as? String else {
XCTFail("Connect should be called with a namespace")
return
}
XCTAssertEqual(nspString, nsp, "It should connect with the correct namespace")
expect.fulfill()
}
socket.connect(timeoutAfter: 0.3, withHandler: {
XCTFail("Should not call timeout handler if status is connected")
})
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
// Fake connecting
self.manager.parseEngineMessage("0/swift")
}
waitForExpectations(timeout: 2)
}
func testErrorInCustomSocketDataCallsErrorHandler() {
let expect = expectation(description: "The client should call the error handler for emit errors because of " +
"custom data")
socket.on(clientEvent: .error) {data, ack in
guard data.count == 3, data[0] as? String == "myEvent",
data[2] is ThrowingData.ThrowingError else {
XCTFail("Incorrect error call")
return
}
expect.fulfill()
}
socket.emit("myEvent", ThrowingData())
waitForExpectations(timeout: 0.2)
}
func testErrorInCustomSocketDataCallsErrorHandler_ack() {
let expect = expectation(description: "The client should call the error handler for emit errors because of " +
"custom data")
socket.on(clientEvent: .error) {data, ack in
guard data.count == 3, data[0] as? String == "myEvent",
data[2] is ThrowingData.ThrowingError else {
XCTFail("Incorrect error call")
return
}
expect.fulfill()
}
socket.emitWithAck("myEvent", ThrowingData()).timingOut(after: 0.8, callback: {_ in
XCTFail("Ack callback should not be called")
})
waitForExpectations(timeout: 0.2)
}
func testSettingConfigAfterInit() {
socket.setTestStatus(.notConnected)
manager.config.insert(.log(true))
XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to true after creation")
manager.config = [.log(false)]
XCTAssertFalse(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
}
func testSettingConfigAfterDisconnect() {
socket.setTestStatus(.disconnected)
manager.config.insert(.log(true))
XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to true after creation")
manager.config = [.log(false)]
XCTAssertFalse(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
}
func testSettingConfigAfterInitWhenConnectedDoesNotIgnoreChanges() {
manager.setTestStatus(.connected)
manager.config = [.log(true)]
XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
}
func testClientCallsSentPingHandler() {
let expect = expectation(description: "The client should emit a ping event")
socket.on(clientEvent: .pong) {data, ack in
expect.fulfill()
}
manager.engineDidSendPong()
waitForExpectations(timeout: 0.2)
}
func testClientCallsGotPongHandler() {
let expect = expectation(description: "The client should emit a pong event")
socket.on(clientEvent: .ping) {data, ack in
expect.fulfill()
}
manager.engineDidReceivePing()
waitForExpectations(timeout: 0.2)
}
let data = "test".data(using: String.Encoding.utf8)!
let data2 = "test2".data(using: String.Encoding.utf8)!
private var manager: SocketManager!
private var socket: SocketIOClient!
override func setUp() {
super.setUp()
manager = SocketManager(socketURL: URL(string: "http://localhost/")!, config: [.log(false)])
socket = manager.defaultSocket
socket.setTestable()
}
}
struct ThrowingData: SocketData {
enum ThrowingError : Error {
case error
}
func socketRepresentation() throws -> SocketData {
throw ThrowingError.error
}
}
class TestEngine: SocketEngineSpec {
weak var client: SocketEngineClient?
private(set) var closed = false
private(set) var compress = false
private(set) var connected = false
var connectParams: [String: Any]? = nil
private(set) var cookies: [HTTPCookie]? = nil
private(set) var engineQueue = DispatchQueue.main
var extraHeaders: [String: String]? = nil
private(set) var fastUpgrade = false
private(set) var forcePolling = false
private(set) var forceWebsockets = false
private(set) var polling = false
private(set) var probing = false
private(set) var sid = ""
private(set) var socketPath = ""
private(set) var urlPolling = URL(string: "http://localhost/")!
private(set) var urlWebSocket = URL(string: "http://localhost/")!
private(set) var websocket = false
private(set) var ws: WebSocket? = nil
private(set) var version = SocketIOVersion.three
internal var onConnect: (() -> ())?
required init(client: SocketEngineClient, url: URL, options: [String: Any]?) {
self.client = client
}
func connect() {
onConnect?()
}
func didError(reason: String) { }
func disconnect(reason: String) { }
func doFastUpgrade() { }
func flushWaitingForPostToWebSocket() { }
func parseEngineData(_ data: Data) { }
func parseEngineMessage(_ message: String) { }
func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data], completion: (() -> ())?) { }
}

View File

@ -1,13 +0,0 @@
//
// Created by Erik Little on 2019-01-11.
//
import Foundation
@testable import SocketIO
public class OBjcUtils: NSObject {
@objc
public static func setTestStatus(socket: SocketIOClient, status: SocketIOStatus) {
socket.setTestStatus(status)
}
}

View File

@ -1,109 +0,0 @@
# Upgrading from v12
This guide will help you navigate the changes that were introduced in v13.
## What are the big changes?
The biggest change is how to create and manage clients. Much like the native JS client and server,
the swift client now only uses one engine per connection. Previously in order to use namespaces it was required
to create multiple clients, and each client had its own engine.
Some v12 code might've looked like this:
```swift
let defaultSocket = SocketIOClient(socketURL: myURL)
let namespaceSocket = SocketIOClient(socketURL: myURL, config: [.nsp("/swift")])
// add handlers for sockets and connect
```
In v12 this would have opened two connections to the socket.io.
In v13 the same code would look like this:
```swift
let manager = SocketManager(socketURL: myURL)
let defaultSocket = manager.defaultSocket
let namespaceSocket = manager.socket(forNamespace: "/swift")
// add handlers for sockets and connect
```
In v13 `defaultSocket` and `namespaceSocket` will share a single transport. This means one less connection to the server
needs to be opened.
## What might I have to change?
- The most obvious thing you will need to change is that instead of creating `SocketIOClient`s directly, you will create a
`SocketManager` and either use the `defaultSocket` property if you don't need namespaces, or call the
`socket(forNamespace:)` method on the manager.
- `SocketIOClient` is no longer a client to an engine. So if you were overriding the engine methods, these have been moved
to the manager.
- The library is now a single target. So you might have to change some of your Xcode project settings.
- `SocketIOClient`s no longer take a configuration, they are shared from the manager.
- The `joinNamespace()` and `leaveNamespace()` methods on `SocketIOClient` no longer take any arguments, and in most cases
no longer need to be called. Namespace joining/leaving can be managed by calling `connect()`/`disconnect()` on the socket
associated with that namespace.
----------
# What things should I know?
How sockets are stored
---
You should know that `SocketIOClient`s no longer need to be held around in properties, but the `SocketManager` should.
One of the most common mistakes people made is not maintaining a strong reference to the client.
```swift
class Manager {
func addHandlers() {
let socket = SocketIOClient(socketURL: myURL, config: [.nsp("/swift")])
// Add handlers
}
}
```
This would have resulted in the client being released and no handlers being called.
A *correct* equivalent would be:
```swift
class Manager {
let socketManager = SocketManager(socketURL: someURL)
func addHandlers() {
let socket = socketManager.socket(forNamespace: "/swift")
// Add handlers
}
}
```
This code is fine because the `SocketManager` will maintain a strong reference to the socket.
It's also worth noting that subsequent calls to `socket(forNamespace:)` will return the *same* socket instance as the
first call. So you don't need to hold onto the socket directly just to access it again, just call `socket(forNamespace:)`
on the manager to get it. **This does mean that if you need multiple sockets on the same namespace, you will have to use
multiple managers.**
What to call connect on
---
Connect can either be called on the manager directly, or on one of the sockets made from it. In either case, if the manager
was not already connected to the server, a connection will be made. Also in both cases the default socket (namespace "/")
will fire a `connect` event.
The difference is that if `connect()` is just called on the manager, then any sockets for that manager that are not the default
socket will not automatically connect. `connect()` will need to be called individually for each socket. However, if `connect()`
is called on a client, then in addition to opening the connection if needed, the client will connect to its namespace,
and a `connect` event fired.

View File

@ -1,35 +0,0 @@
# Upgrading from v15 to v16
This guide will help you navigate the changes that were introduced in v16.
## Objective-c is no longer supported. You must now use Swift.
## Client supports multiple socket.io versions
The client now supports socket.io 3 servers. This is mostly a transparent change, however if your server
is socket.io 2, you must send `.version(.two)` as an option to the manager.
```swift
SocketManager(socketURL: URL(string:"http://localhost:8087/")!, config: [.version(.two)])
```
## How to upgrade
- first, upgrade the Socket.IO server to v4 with the compatibility mode enabled (`allowEIO3: true`)
- then, upgrade the clients to v16
- finally, once all clients have upgraded, disable the compatibility mode
You can check the version of the connection on the server side with:
```js
io.on("connection", (socket) => {
// either 3 for the 3rd revision of the protocol (Socket.IO v2) or 4 for the 4th revision (Socket.IO v3/v4)
const version = socket.conn.protocol;
});
```
See also:
- [Compatibility table](https://nuclearace.github.io/Socket.IO-Client-Swift/Compatibility.html)
- Migrating from 2.x to 3.0: https://socket.io/docs/v4/migrating-from-2-x-to-3-0/
- Migrating from 3.x to 4.0: https://socket.io/docs/v4/migrating-from-3-x-to-4-0/

View File

@ -1,61 +0,0 @@
Here is the compatibility table with the Node.js server:
<table>
<tr>
<th rowspan="2">Swift Client version</th>
<th colspan="3">Socket.IO server version</th>
</tr>
<tr>
<td align="center">2.x</td>
<td align="center">3.x</td>
<td align="center">4.x</td>
</tr>
<tr>
<td align="center">v15.x</td>
<td align="center"><b>YES</b></td>
<td align="center"><b>YES</b><sup>1</sup></td>
<td align="center"><b>YES</b><sup>2</sup></td>
</tr>
<tr>
<td align="center">v16.x</td>
<td align="center"><b>YES</b><sup>3</sup></td>
<td align="center"><b>YES</b></td>
<td align="center"><b>YES</b></td>
</tr>
</table>
[1] Yes, with <code><a href="https://socket.io/docs/v4/server-initialization/#allowEIO3">allowEIO3: true</a></code> (server) and `.connectParams(["EIO": "3"])` (client):
*Server*
```js
const { createServer } = require("http");
const { Server } = require("socket.io");
const httpServer = createServer();
const io = new Server(httpServer, {
allowEIO3: true
});
httpServer.listen(8080);
```
*Client*
```swift
SocketManager(socketURL: URL(string:"http://localhost:8080/")!, config: [.connectParams(["EIO": "3"])])
```
[2] Yes, <code><a href="https://socket.io/docs/v4/server-initialization/#allowEIO3">allowEIO3: true</a></code> (server)
[3] Yes, with `.version(.two)` (client):
```swift
SocketManager(socketURL: URL(string:"http://localhost:8080/")!, config: [.version(.two)])
```
See also:
- Migrating from 2.x to 3.0: https://socket.io/docs/v4/migrating-from-2-x-to-3-0/
- Migrating from 3.x to 4.0: https://socket.io/docs/v4/migrating-from-3-x-to-4-0/
- Socket.IO protocol: https://github.com/socketio/socket.io-protocol

View File

@ -1,44 +0,0 @@
## How do I connect to my WebSocket server?
This library is **NOT** a WebSockets library. This library is only for servers that implement the socket.io protocol,
such as [socket.io](https://socket.io/). If you need a plain WebSockets client check out
[Starscream](https://github.com/daltoniam/Starscream) for Swift and [JetFire](https://github.com/acmacalister/jetfire)
for Objective-C.
## Why isn't my event handler being called?
One of the most common reasons your event might not be called is if the client is released by
[ARC](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html).
Take this code for example:
```swift
class Manager {
func addHandlers() {
let manager = SocketManager(socketURL: URL(string: "http://somesocketioserver.com")!)
manager.defaultSocket.on("myEvent") {data, ack in
print(data)
}
}
}
```
This code is **incorrect**, and the event handler will never be called. Because as soon as this method is called `manager`
will be released, along with the socket, and its memory reclaimed.
A correct way would be:
```swift
class Manager {
let manager = SocketManager(socketURL: URL(string: "http://somesocketioserver.com")!)
func addHandlers() {
manager.defaultSocket.on("myEvent") {data, ack in
print(data)
}
}
}
```

View File

@ -1,335 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>12to13 Reference</title>
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
<meta charset="utf-8">
<script src="js/jquery.min.js" defer></script>
<script src="js/jazzy.js" defer></script>
<script src="js/lunr.min.js" defer></script>
<script src="js/typeahead.jquery.js" defer></script>
<script src="js/jazzy.search.js" defer></script>
</head>
<body>
<a title="12to13 Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="index.html">SocketIO Reference</a>
<img class="carat" src="img/carat.png" />
12to13 Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1 id='upgrading-from-v12' class='heading'>Upgrading from v12</h1>
<p>This guide will help you navigate the changes that were introduced in v13.</p>
<h2 id='what-are-the-big-changes' class='heading'>What are the big changes?</h2>
<p>The biggest change is how to create and manage clients. Much like the native JS client and server,
the swift client now only uses one engine per connection. Previously in order to use namespaces it was required
to create multiple clients, and each client had its own engine.</p>
<p>Some v12 code might&rsquo;ve looked like this:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">defaultSocket</span> <span class="o">=</span> <span class="kt">SocketIOClient</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">myURL</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">namespaceSocket</span> <span class="o">=</span> <span class="kt">SocketIOClient</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">myURL</span><span class="p">,</span> <span class="nv">config</span><span class="p">:</span> <span class="p">[</span><span class="o">.</span><span class="nf">nsp</span><span class="p">(</span><span class="s">"/swift"</span><span class="p">)])</span>
<span class="c1">// add handlers for sockets and connect</span>
</code></pre>
<p>In v12 this would have opened two connections to the socket.io.</p>
<p>In v13 the same code would look like this:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">manager</span> <span class="o">=</span> <span class="kt">SocketManager</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">myURL</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">defaultSocket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="n">defaultSocket</span>
<span class="k">let</span> <span class="nv">namespaceSocket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="nf">socket</span><span class="p">(</span><span class="nv">forNamespace</span><span class="p">:</span> <span class="s">"/swift"</span><span class="p">)</span>
<span class="c1">// add handlers for sockets and connect</span>
</code></pre>
<p>In v13 <code>defaultSocket</code> and <code>namespaceSocket</code> will share a single transport. This means one less connection to the server
needs to be opened. </p>
<h2 id='what-might-i-have-to-change' class='heading'>What might I have to change?</h2>
<ul>
<li><p>The most obvious thing you will need to change is that instead of creating <code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code>s directly, you will create a
<code><a href="Classes/SocketManager.html">SocketManager</a></code> and either use the <code>defaultSocket</code> property if you don&rsquo;t need namespaces, or call the
<code>socket(forNamespace:)</code> method on the manager.</p></li>
<li><p><code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code> is no longer a client to an engine. So if you were overriding the engine methods, these have been moved
to the manager. </p></li>
<li><p>The library is now a single target. So you might have to change some of your Xcode project settings.</p></li>
<li><p><code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code>s no longer take a configuration, they are shared from the manager.</p></li>
<li><p>The <code>joinNamespace()</code> and <code>leaveNamespace()</code> methods on <code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code> no longer take any arguments, and in most cases
no longer need to be called. Namespace joining/leaving can be managed by calling <code>connect()</code>/<code>disconnect()</code> on the socket
associated with that namespace.</p></li>
</ul>
<hr>
<h1 id='what-things-should-i-know' class='heading'>What things should I know?</h1>
<h2 id='how-sockets-are-stored' class='heading'>How sockets are stored</h2>
<p>You should know that <code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code>s no longer need to be held around in properties, but the <code><a href="Classes/SocketManager.html">SocketManager</a></code> should.</p>
<p>One of the most common mistakes people made is not maintaining a strong reference to the client.</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">Manager</span> <span class="p">{</span>
<span class="kd">func</span> <span class="nf">addHandlers</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">socket</span> <span class="o">=</span> <span class="kt">SocketIOClient</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">myURL</span><span class="p">,</span> <span class="nv">config</span><span class="p">:</span> <span class="p">[</span><span class="o">.</span><span class="nf">nsp</span><span class="p">(</span><span class="s">"/swift"</span><span class="p">)])</span>
<span class="c1">// Add handlers</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>This would have resulted in the client being released and no handlers being called.</p>
<p>A <em>correct</em> equivalent would be:</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">Manager</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">socketManager</span> <span class="o">=</span> <span class="kt">SocketManager</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">someURL</span><span class="p">)</span>
<span class="kd">func</span> <span class="nf">addHandlers</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">socket</span> <span class="o">=</span> <span class="n">socketManager</span><span class="o">.</span><span class="nf">socket</span><span class="p">(</span><span class="nv">forNamespace</span><span class="p">:</span> <span class="s">"/swift"</span><span class="p">)</span>
<span class="c1">// Add handlers</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>This code is fine because the <code><a href="Classes/SocketManager.html">SocketManager</a></code> will maintain a strong reference to the socket.</p>
<p>It&rsquo;s also worth noting that subsequent calls to <code>socket(forNamespace:)</code> will return the <em>same</em> socket instance as the
first call. So you don&rsquo;t need to hold onto the socket directly just to access it again, just call <code>socket(forNamespace:)</code>
on the manager to get it. <strong>This does mean that if you need multiple sockets on the same namespace, you will have to use
multiple managers.</strong></p>
<h2 id='what-to-call-connect-on' class='heading'>What to call connect on</h2>
<p>Connect can either be called on the manager directly, or on one of the sockets made from it. In either case, if the manager
was not already connected to the server, a connection will be made. Also in both cases the default socket (namespace &ldquo;/&rdquo;)
will fire a <code>connect</code> event. </p>
<p>The difference is that if <code>connect()</code> is just called on the manager, then any sockets for that manager that are not the default
socket will not automatically connect. <code>connect()</code> will need to be called individually for each socket. However, if <code>connect()</code>
is called on a client, then in addition to opening the connection if needed, the client will connect to its namespace,
and a <code>connect</code> event fired.</p>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,255 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>15to16 Reference</title>
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
<meta charset="utf-8">
<script src="js/jquery.min.js" defer></script>
<script src="js/jazzy.js" defer></script>
<script src="js/lunr.min.js" defer></script>
<script src="js/typeahead.jquery.js" defer></script>
<script src="js/jazzy.search.js" defer></script>
</head>
<body>
<a title="15to16 Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="index.html">SocketIO Reference</a>
<img class="carat" src="img/carat.png" />
15to16 Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1 id='upgrading-from-v15-to-v16' class='heading'>Upgrading from v15 to v16</h1>
<p>This guide will help you navigate the changes that were introduced in v16.</p>
<h2 id='objective-c-is-no-longer-supported-you-must-now-use-swift' class='heading'>Objective-c is no longer supported. You must now use Swift.</h2>
<h2 id='client-supports-multiple-socket-io-versions' class='heading'>Client supports multiple socket.io versions</h2>
<p>The client now supports socket.io 3 servers. This is mostly a transparent change, however if your sever
is socket.io 2, you must send <code>.version(.two)</code> as an option to the manager.</p>
<pre class="highlight swift"><code><span class="kt">SocketManager</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span><span class="s">"http://localhost:8087/"</span><span class="p">)</span><span class="o">!</span><span class="p">,</span> <span class="nv">config</span><span class="p">:</span> <span class="p">[</span><span class="o">.</span><span class="nf">version</span><span class="p">(</span><span class="o">.</span><span class="n">two</span><span class="p">)])</span>
</code></pre>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,526 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Classes Reference</title>
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
<meta charset="utf-8">
<script src="js/jquery.min.js" defer></script>
<script src="js/jazzy.js" defer></script>
<script src="js/lunr.min.js" defer></script>
<script src="js/typeahead.jquery.js" defer></script>
<script src="js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Section/Classes" class="dashAnchor"></a>
<a title="Classes Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="index.html">SocketIO Reference</a>
<img class="carat" src="img/carat.png" />
Classes Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1>Classes</h1>
<p>The following classes are available globally.</p>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketAckEmitter"></a>
<a name="//apple_ref/swift/Class/SocketAckEmitter" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAckEmitter">SocketAckEmitter</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>A class that represents a waiting ack call.</p>
<p><strong>NOTE</strong>: You should not store this beyond the life of the event handler.</p>
<a href="Classes/SocketAckEmitter.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketAckEmitter</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)OnAckCallback"></a>
<a name="//apple_ref/swift/Class/OnAckCallback" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)OnAckCallback">OnAckCallback</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>A class that represents an emit that will request an ack that has not yet been sent.
Call <code>timingOut(after:callback:)</code> to complete the emit
Example:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">emitWithAck</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">)</span><span class="o">.</span><span class="nf">timingOut</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span> <span class="k">in</span>
<span class="o">...</span>
<span class="p">}</span>
</code></pre>
<a href="Classes/OnAckCallback.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">OnAckCallback</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketAnyEvent"></a>
<a name="//apple_ref/swift/Class/SocketAnyEvent" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAnyEvent">SocketAnyEvent</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Represents some event that was received.</p>
<a href="Classes/SocketAnyEvent.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketAnyEvent</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketIOClient"></a>
<a name="//apple_ref/swift/Class/SocketIOClient" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketIOClient">SocketIOClient</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Represents a socket.io-client.</p>
<p>Clients are created through a <code><a href="Classes/SocketManager.html">SocketManager</a></code>, which owns the <code><a href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a></code> that controls the connection to the server.</p>
<p>For example:</p>
<pre class="highlight swift"><code><span class="c1">// Create a socket for the /swift namespace</span>
<span class="k">let</span> <span class="nv">socket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="nf">socket</span><span class="p">(</span><span class="nv">forNamespace</span><span class="p">:</span> <span class="s">"/swift"</span><span class="p">)</span>
<span class="c1">// Add some handlers and connect</span>
</code></pre>
<p><strong>NOTE</strong>: The client is not thread/queue safe, all interaction with the socket should be done on the <code>manager.handleQueue</code></p>
<a href="Classes/SocketIOClient.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">open</span> <span class="kd">class</span> <span class="kt">SocketIOClient</span> <span class="p">:</span> <span class="kt">NSObject</span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a></span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketRawView"></a>
<a name="//apple_ref/swift/Class/SocketRawView" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawView">SocketRawView</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">emit</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">,</span> <span class="n">myObject</span><span class="p">)</span>
</code></pre>
<a href="Classes/SocketRawView.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketRawView</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketRawAckView"></a>
<a name="//apple_ref/swift/Class/SocketRawAckView" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawAckView">SocketRawAckView</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">ack</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">with</span><span class="p">(</span><span class="n">myObject</span><span class="p">)</span>
</code></pre>
<a href="Classes/SocketRawAckView.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketRawAckView</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketEngine"></a>
<a name="//apple_ref/swift/Class/SocketEngine" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketEngine">SocketEngine</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The class that handles the engine.io protocol and transports.
See <code><a href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a></code> and <code><a href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a></code> for transport specific methods.</p>
<a href="Classes/SocketEngine.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">open</span> <span class="kd">class</span> <span class="kt">SocketEngine</span><span class="p">:</span>
<span class="kt">NSObject</span><span class="p">,</span> <span class="kt">WebSocketDelegate</span><span class="p">,</span> <span class="kt">URLSessionDelegate</span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/ConfigSettable.html">ConfigSettable</a></span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketManager"></a>
<a name="//apple_ref/swift/Class/SocketManager" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketManager">SocketManager</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>A manager for a socket.io connection.</p>
<p>A <code>SocketManager</code> is responsible for multiplexing multiple namespaces through a single <code><a href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a></code>.</p>
<p>Example:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">manager</span> <span class="o">=</span> <span class="kt">SocketManager</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span><span class="s">"http://localhost:8080/"</span><span class="p">)</span><span class="o">!</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">defaultNamespaceSocket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="n">defaultSocket</span>
<span class="k">let</span> <span class="nv">swiftSocket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="nf">socket</span><span class="p">(</span><span class="nv">forNamespace</span><span class="p">:</span> <span class="s">"/swift"</span><span class="p">)</span>
<span class="c1">// defaultNamespaceSocket and swiftSocket both share a single connection to the server</span>
</code></pre>
<p>Sockets created through the manager are retained by the manager. So at the very least, a single strong reference
to the manager must be maintained to keep sockets alive.</p>
<p>To disconnect a socket and remove it from the manager, either call <code><a href="Classes/SocketIOClient.html#/s:8SocketIO0A8IOClientC10disconnectyyF">SocketIOClient.disconnect()</a></code> on the socket,
or call one of the <code>disconnectSocket</code> methods on this class.</p>
<p><strong>NOTE</strong>: The manager is not thread/queue safe, all interaction with the manager should be done on the <code>handleQueue</code></p>
<a href="Classes/SocketManager.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">open</span> <span class="kd">class</span> <span class="kt">SocketManager</span> <span class="p">:</span> <span class="kt">NSObject</span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketParsable.html">SocketParsable</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/ConfigSettable.html">ConfigSettable</a></span></code></pre>
</div>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,337 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>OnAckCallback Class Reference</title>
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
<meta charset="utf-8">
<script src="../js/jquery.min.js" defer></script>
<script src="../js/jazzy.js" defer></script>
<script src="../js/lunr.min.js" defer></script>
<script src="../js/typeahead.jquery.js" defer></script>
<script src="../js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Class/OnAckCallback" class="dashAnchor"></a>
<a title="OnAckCallback Class Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="../index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="../search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
<img class="carat" src="../img/carat.png" />
OnAckCallback Class Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1>OnAckCallback</h1>
<div class="declaration">
<div class="language">
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">OnAckCallback</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
<p>A class that represents an emit that will request an ack that has not yet been sent.
Call <code>timingOut(after:callback:)</code> to complete the emit
Example:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">emitWithAck</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">)</span><span class="o">.</span><span class="nf">timingOut</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span> <span class="k">in</span>
<span class="o">...</span>
<span class="p">}</span>
</code></pre>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<div class="task-name-container">
<a name="/Methods"></a>
<a name="//apple_ref/swift/Section/Methods" class="dashAnchor"></a>
<div class="section-name-container">
<a class="section-name-link" href="#/Methods"></a>
<h3 class="section-name"><p>Methods</p>
</h3>
</div>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)OnAckCallback(im)timingOutAfter:callback:"></a>
<a name="//apple_ref/swift/Method/timingOut(after:callback:)" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)OnAckCallback(im)timingOutAfter:callback:">timingOut(after:<wbr>callback:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Completes an emitWithAck. If this isn&rsquo;t called, the emit never happens.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">timingOut</span><span class="p">(</span><span class="n">after</span> <span class="nv">seconds</span><span class="p">:</span> <span class="kt">Double</span><span class="p">,</span> <span class="nv">callback</span><span class="p">:</span> <span class="kd">@escaping</span> <span class="kt"><a href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a></span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>seconds</em>
</code>
</td>
<td>
<div>
<p>The number of seconds before this emit times out if an ack hasn&rsquo;t been received.</p>
</div>
</td>
</tr>
<tr>
<td>
<code>
<em>callback</em>
</code>
</td>
<td>
<div>
<p>The callback called when an ack is received, or when a timeout happens.
To check for timeout, use <code><a href="../Enums/SocketAckStatus.html">SocketAckStatus</a></code>&lsquo;s <code>noAck</code> case.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,436 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SSLSecurity Class Reference</title>
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
<meta charset="utf-8">
<script src="../js/jquery.min.js" defer></script>
<script src="../js/jazzy.js" defer></script>
<script src="../js/lunr.min.js" defer></script>
<script src="../js/typeahead.jquery.js" defer></script>
<script src="../js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Class/SSLSecurity" class="dashAnchor"></a>
<a title="SSLSecurity Class Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="../index.html">
SocketIO Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="../search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
<img class="carat" src="../img/carat.png" />
SSLSecurity Class Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SSLSecurity.html">SSLSecurity</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content">
<h1>SSLSecurity</h1>
<div class="declaration">
<div class="language">
<pre class="highlight swift"><code><span class="kd">open</span> <span class="kd">class</span> <span class="kt">SSLSecurity</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
<p>A wrapper around Starscream&rsquo;s SSLSecurity that provides a minimal Objective-C interface.</p>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<div class="task-name-container">
<a name="/Properties"></a>
<a name="//apple_ref/swift/Section/Properties" class="dashAnchor"></a>
<a href="#/Properties">
<h3 class="section-name">Properties</h3>
</a>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/s:8SocketIO11SSLSecurityC8security10StarscreamABCvp"></a>
<a name="//apple_ref/swift/Property/security" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO11SSLSecurityC8security10StarscreamABCvp">security</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The internal Starscream SSLSecurity.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="k">let</span> <span class="nv">security</span><span class="p">:</span> <span class="kt">Starscream</span><span class="o">.</span><span class="kt">SSLSecurity</span></code></pre>
</div>
</div>
</section>
</div>
</li>
</ul>
</div>
<div class="task-group">
<div class="task-name-container">
<a name="/Methods"></a>
<a name="//apple_ref/swift/Section/Methods" class="dashAnchor"></a>
<a href="#/Methods">
<h3 class="section-name">Methods</h3>
</a>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SSLSecurity(im)initWithUsePublicKeys:"></a>
<a name="//apple_ref/swift/Method/init(usePublicKeys:)" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SSLSecurity(im)initWithUsePublicKeys:">init(usePublicKeys:)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Creates a new SSLSecurity that specifies whether to use publicKeys or certificates should be used for SSL
pinning validation</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="n">convenience</span> <span class="nf">init</span><span class="p">(</span><span class="nv">usePublicKeys</span><span class="p">:</span> <span class="kt">Bool</span> <span class="o">=</span> <span class="kc">true</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>usePublicKeys</em>
</code>
</td>
<td>
<div>
<p>is to specific if the publicKeys or certificates should be used for SSL pinning
validation</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO11SSLSecurityC5certs13usePublicKeysACSay10Starscream7SSLCertCG_Sbtcfc"></a>
<a name="//apple_ref/swift/Method/init(certs:usePublicKeys:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO11SSLSecurityC5certs13usePublicKeysACSay10Starscream7SSLCertCG_Sbtcfc">init(certs:usePublicKeys:)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Designated init</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="n">convenience</span> <span class="nf">init</span><span class="p">(</span><span class="nv">certs</span><span class="p">:</span> <span class="p">[</span><span class="kt">SSLCert</span><span class="p">],</span> <span class="nv">usePublicKeys</span><span class="p">:</span> <span class="kt">Bool</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>certs</em>
</code>
</td>
<td>
<div>
<p>is the certificates or public keys to use</p>
</div>
</td>
</tr>
<tr>
<td>
<code>
<em>usePublicKeys</em>
</code>
</td>
<td>
<div>
<p>is to specific if the publicKeys or certificates should be used for SSL pinning
validation</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<h4>Return Value</h4>
<p>a representation security object to be used with</p>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO11SSLSecurityC7isValid_6domainSbSo11SecTrustRefa_SSSgtF"></a>
<a name="//apple_ref/swift/Method/isValid(_:domain:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO11SSLSecurityC7isValid_6domainSbSo11SecTrustRefa_SSSgtF">isValid(_:domain:)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Returns whether or not the given trust is valid.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">isValid</span><span class="p">(</span><span class="n">_</span> <span class="nv">trust</span><span class="p">:</span> <span class="kt">SecTrust</span><span class="p">,</span> <span class="nv">domain</span><span class="p">:</span> <span class="kt">String</span><span class="p">?)</span> <span class="o">-&gt;</span> <span class="kt">Bool</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>trust</em>
</code>
</td>
<td>
<div>
<p>The trust to validate.</p>
</div>
</td>
</tr>
<tr>
<td>
<code>
<em>domain</em>
</code>
</td>
<td>
<div>
<p>The CN domain to validate.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<h4>Return Value</h4>
<p>Whether or not this is valid.</p>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2019 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2019-05-28)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.9.4</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,518 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SocketAckEmitter Class Reference</title>
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
<meta charset="utf-8">
<script src="../js/jquery.min.js" defer></script>
<script src="../js/jazzy.js" defer></script>
<script src="../js/lunr.min.js" defer></script>
<script src="../js/typeahead.jquery.js" defer></script>
<script src="../js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Class/SocketAckEmitter" class="dashAnchor"></a>
<a title="SocketAckEmitter Class Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="../index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="../search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
<img class="carat" src="../img/carat.png" />
SocketAckEmitter Class Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1>SocketAckEmitter</h1>
<div class="declaration">
<div class="language">
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketAckEmitter</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
<p>A class that represents a waiting ack call.</p>
<p><strong>NOTE</strong>: You should not store this beyond the life of the event handler.</p>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketAckEmitter(py)rawEmitView"></a>
<a name="//apple_ref/swift/Property/rawEmitView" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAckEmitter(py)rawEmitView">rawEmitView</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>A view into this emitter where emits do not check for binary data.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">ack</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">with</span><span class="p">(</span><span class="n">myObject</span><span class="p">)</span>
</code></pre>
<p><strong>NOTE</strong>: It is not safe to hold on to this view beyond the life of the socket.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="kd">private(set)</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">rawEmitView</span><span class="p">:</span> <span class="kt"><a href="../Classes/SocketRawAckView.html">SocketRawAckView</a></span> <span class="p">{</span> <span class="k">get</span> <span class="k">set</span> <span class="p">}</span></code></pre>
</div>
</div>
</section>
</div>
</li>
</ul>
</div>
<div class="task-group">
<div class="task-name-container">
<a name="/Properties"></a>
<a name="//apple_ref/swift/Section/Properties" class="dashAnchor"></a>
<div class="section-name-container">
<a class="section-name-link" href="#/Properties"></a>
<h3 class="section-name"><p>Properties</p>
</h3>
</div>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A10AckEmitterC8expectedSbvp"></a>
<a name="//apple_ref/swift/Property/expected" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A10AckEmitterC8expectedSbvp">expected</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>If true, this handler is expecting to be acked. Call <code>with(_: SocketData...)</code> to ack.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="k">var</span> <span class="nv">expected</span><span class="p">:</span> <span class="kt">Bool</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span></code></pre>
</div>
</div>
</section>
</div>
</li>
</ul>
</div>
<div class="task-group">
<div class="task-name-container">
<a name="/Initializers"></a>
<a name="//apple_ref/swift/Section/Initializers" class="dashAnchor"></a>
<div class="section-name-container">
<a class="section-name-link" href="#/Initializers"></a>
<h3 class="section-name"><p>Initializers</p>
</h3>
</div>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A10AckEmitterC6socket6ackNumAcA0A8IOClientC_Sitcfc"></a>
<a name="//apple_ref/swift/Method/init(socket:ackNum:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A10AckEmitterC6socket6ackNumAcA0A8IOClientC_Sitcfc">init(socket:<wbr>ackNum:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Creates a new <code>SocketAckEmitter</code>.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="nf">init</span><span class="p">(</span><span class="nv">socket</span><span class="p">:</span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">,</span> <span class="nv">ackNum</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>socket</em>
</code>
</td>
<td>
<div>
<p>The socket for this emitter.</p>
</div>
</td>
</tr>
<tr>
<td>
<code>
<em>ackNum</em>
</code>
</td>
<td>
<div>
<p>The ack number for this emitter.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
</ul>
</div>
<div class="task-group">
<div class="task-name-container">
<a name="/Methods"></a>
<a name="//apple_ref/swift/Section/Methods" class="dashAnchor"></a>
<div class="section-name-container">
<a class="section-name-link" href="#/Methods"></a>
<h3 class="section-name"><p>Methods</p>
</h3>
</div>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A10AckEmitterC4withyyAA0A4Data_pd_tF"></a>
<a name="//apple_ref/swift/Method/with(_:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A10AckEmitterC4withyyAA0A4Data_pd_tF">with(_:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Call to ack receiving this event.</p>
<p>If an error occurs trying to transform <code>items</code> into their socket representation, a <code><a href="../Enums/SocketClientEvent.html#/s:8SocketIO0A11ClientEventO5erroryA2CmF">SocketClientEvent.error</a></code>
will be emitted. The structure of the error data is <code>[ackNum, items, theError]</code></p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">with</span><span class="p">(</span><span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="kt"><a href="../Protocols/SocketData.html">SocketData</a></span><span class="o">...</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>items</em>
</code>
</td>
<td>
<div>
<p>A variable number of items to send when acking.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketAckEmitter(im)with:"></a>
<a name="//apple_ref/swift/Method/with(_:)" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAckEmitter(im)with:">with(_:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Call to ack receiving this event.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">with</span><span class="p">(</span><span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">])</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>items</em>
</code>
</td>
<td>
<div>
<p>An array of items to send when acking. Use <code>[]</code> to send nothing.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,354 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SocketAnyEvent Class Reference</title>
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
<meta charset="utf-8">
<script src="../js/jquery.min.js" defer></script>
<script src="../js/jazzy.js" defer></script>
<script src="../js/lunr.min.js" defer></script>
<script src="../js/typeahead.jquery.js" defer></script>
<script src="../js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Class/SocketAnyEvent" class="dashAnchor"></a>
<a title="SocketAnyEvent Class Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="../index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="../search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
<img class="carat" src="../img/carat.png" />
SocketAnyEvent Class Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1>SocketAnyEvent</h1>
<div class="declaration">
<div class="language">
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketAnyEvent</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
<p>Represents some event that was received.</p>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<div class="task-name-container">
<a name="/Properties"></a>
<a name="//apple_ref/swift/Section/Properties" class="dashAnchor"></a>
<div class="section-name-container">
<a class="section-name-link" href="#/Properties"></a>
<h3 class="section-name"><p>Properties</p>
</h3>
</div>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)event"></a>
<a name="//apple_ref/swift/Property/event" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)event">event</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The event name.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="k">let</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)items"></a>
<a name="//apple_ref/swift/Property/items" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)items">items</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The data items for this event.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="k">let</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">]?</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)description"></a>
<a name="//apple_ref/swift/Property/description" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)description">description</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The description of this event.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">override</span> <span class="kd">public</span> <span class="k">var</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span></code></pre>
</div>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,472 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SocketClientManager Class Reference</title>
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
<meta charset="utf-8">
<script src="../js/jquery.min.js" defer></script>
<script src="../js/jazzy.js" defer></script>
<script src="../js/lunr.min.js" defer></script>
<script src="../js/typeahead.jquery.js" defer></script>
<script src="../js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Class/SocketClientManager" class="dashAnchor"></a>
<a title="SocketClientManager Class Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="../index.html">
SocketIO Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="../search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
<img class="carat" src="../img/carat.png" />
SocketClientManager Class Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SSLSecurity.html">SSLSecurity</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketClientManager.html">SocketClientManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientStatus.html">SocketIOClientStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content">
<h1>SocketClientManager</h1>
<div class="declaration">
<div class="language">
<pre class="highlight"><code><span class="n">open</span> <span class="kd">class</span> <span class="kt">SocketClientManager</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
<p>Experimental socket manager.</p>
<p>API subject to change.</p>
<p>Can be used to persist sockets across ViewControllers.</p>
<p>Sockets are strongly stored, so be sure to remove them once they are no
longer needed.</p>
<p>Example usage:</p>
<pre class="highlight plaintext"><code>let manager = SocketClientManager.sharedManager
manager["room1"] = socket1
manager["room2"] = socket2
manager.removeSocket(socket: socket2)
manager["room1"]?.emit("hello")
</code></pre>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<div class="task-name-container">
<a name="/Properties."></a>
<a name="//apple_ref/swift/Section/Properties." class="dashAnchor"></a>
<a href="#/Properties.">
<h3 class="section-name">Properties.</h3>
</a>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(cpy)sharedManager"></a>
<a name="//apple_ref/swift/Variable/sharedManager" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(cpy)sharedManager">sharedManager</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The shared manager.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="n">open</span> <span class="kd">static</span> <span class="k">let</span> <span class="nv">sharedManager</span> <span class="o">=</span> <span class="kt">SocketClientManager</span><span class="p">()</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A13ClientManagerC9subscriptAA0A8IOClientCSgSSci"></a>
<a name="//apple_ref/swift/Method/subscript(_:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A13ClientManagerC9subscriptAA0A8IOClientCSgSSci">subscript(_:)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Gets a socket by its name.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="n">open</span> <span class="nf">subscript</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">?</span></code></pre>
</div>
</div>
<div>
<h4>Return Value</h4>
<p>The socket, if one had the given name.</p>
</div>
</section>
</div>
</li>
</ul>
</div>
<div class="task-group">
<div class="task-name-container">
<a name="/Methods."></a>
<a name="//apple_ref/swift/Section/Methods." class="dashAnchor"></a>
<a href="#/Methods.">
<h3 class="section-name">Methods.</h3>
</a>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(im)addSocket:labeledAs:"></a>
<a name="//apple_ref/swift/Method/addSocket(_:labeledAs:)" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(im)addSocket:labeledAs:">addSocket(_:labeledAs:)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Adds a socket.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="n">open</span> <span class="kd">func</span> <span class="nf">addSocket</span><span class="p">(</span><span class="n">_</span> <span class="nv">socket</span><span class="p">:</span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">,</span> <span class="n">labeledAs</span> <span class="nv">label</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>socket</em>
</code>
</td>
<td>
<div>
<p>The socket to add.</p>
</div>
</td>
</tr>
<tr>
<td>
<code>
<em>labeledAs</em>
</code>
</td>
<td>
<div>
<p>The label for this socket.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSocketWithLabel:"></a>
<a name="//apple_ref/swift/Method/removeSocket(withLabel:)" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSocketWithLabel:">removeSocket(withLabel:)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Removes a socket by a given name.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="n">open</span> <span class="kd">func</span> <span class="nf">removeSocket</span><span class="p">(</span><span class="n">withLabel</span> <span class="nv">label</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">?</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>withLabel</em>
</code>
</td>
<td>
<div>
<p>The label of the socket to remove.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<h4>Return Value</h4>
<p>The socket for the given label, if one was present.</p>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSocket:"></a>
<a name="//apple_ref/swift/Method/removeSocket(_:)" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSocket:">removeSocket(_:)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Removes a socket.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="n">open</span> <span class="kd">func</span> <span class="nf">removeSocket</span><span class="p">(</span><span class="n">_</span> <span class="nv">socket</span><span class="p">:</span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">?</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>socket</em>
</code>
</td>
<td>
<div>
<p>The socket to remove.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<h4>Return Value</h4>
<p>The socket if it was in the manager.</p>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSockets"></a>
<a name="//apple_ref/swift/Method/removeSockets()" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSockets">removeSockets()</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Removes all the sockets in the manager.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="n">open</span> <span class="kd">func</span> <span class="nf">removeSockets</span><span class="p">()</span></code></pre>
</div>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2017 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2017-10-05)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.8.4</a>, a <a class="link" href="http://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,362 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SocketRawAckView Class Reference</title>
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
<meta charset="utf-8">
<script src="../js/jquery.min.js" defer></script>
<script src="../js/jazzy.js" defer></script>
<script src="../js/lunr.min.js" defer></script>
<script src="../js/typeahead.jquery.js" defer></script>
<script src="../js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Class/SocketRawAckView" class="dashAnchor"></a>
<a title="SocketRawAckView Class Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="../index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="../search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
<img class="carat" src="../img/carat.png" />
SocketRawAckView Class Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1>SocketRawAckView</h1>
<div class="declaration">
<div class="language">
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketRawAckView</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
<p>Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">ack</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">with</span><span class="p">(</span><span class="n">myObject</span><span class="p">)</span>
</code></pre>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A10RawAckViewC4withyyAA0A4Data_pd_tF"></a>
<a name="//apple_ref/swift/Method/with(_:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A10RawAckViewC4withyyAA0A4Data_pd_tF">with(_:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Call to ack receiving this event.</p>
<p>If an error occurs trying to transform <code>items</code> into their socket representation, a <code><a href="../Enums/SocketClientEvent.html#/s:8SocketIO0A11ClientEventO5erroryA2CmF">SocketClientEvent.error</a></code>
will be emitted. The structure of the error data is <code>[ackNum, items, theError]</code></p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">with</span><span class="p">(</span><span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="kt"><a href="../Protocols/SocketData.html">SocketData</a></span><span class="o">...</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>items</em>
</code>
</td>
<td>
<div>
<p>A variable number of items to send when acking.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketRawAckView(im)with:"></a>
<a name="//apple_ref/swift/Method/with(_:)" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawAckView(im)with:">with(_:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Call to ack receiving this event.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">with</span><span class="p">(</span><span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">])</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>items</em>
</code>
</td>
<td>
<div>
<p>An array of items to send when acking. Use <code>[]</code> to send nothing.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,532 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SocketRawView Class Reference</title>
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
<meta charset="utf-8">
<script src="../js/jquery.min.js" defer></script>
<script src="../js/jazzy.js" defer></script>
<script src="../js/lunr.min.js" defer></script>
<script src="../js/typeahead.jquery.js" defer></script>
<script src="../js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Class/SocketRawView" class="dashAnchor"></a>
<a title="SocketRawView Class Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="../index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="../search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
<img class="carat" src="../img/carat.png" />
SocketRawView Class Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1>SocketRawView</h1>
<div class="declaration">
<div class="language">
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketRawView</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
</div>
</div>
<p>Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">emit</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">,</span> <span class="n">myObject</span><span class="p">)</span>
</code></pre>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A7RawViewC4emityySS_AA0A4Data_pdtF"></a>
<a name="//apple_ref/swift/Method/emit(_:_:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A7RawViewC4emityySS_AA0A4Data_pdtF">emit(_:<wbr>_:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Send an event to the server, with optional data items.</p>
<p>If an error occurs trying to transform <code>items</code> into their socket representation, a <code><a href="../Enums/SocketClientEvent.html#/s:8SocketIO0A11ClientEventO5erroryA2CmF">SocketClientEvent.error</a></code>
will be emitted. The structure of the error data is <code>[eventName, items, theError]</code></p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">emit</span><span class="p">(</span><span class="n">_</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="kt"><a href="../Protocols/SocketData.html">SocketData</a></span><span class="o">...</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>event</em>
</code>
</td>
<td>
<div>
<p>The event to send.</p>
</div>
</td>
</tr>
<tr>
<td>
<code>
<em>items</em>
</code>
</td>
<td>
<div>
<p>The items to send with this event. May be left out.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketRawView(im)emit:with:"></a>
<a name="//apple_ref/swift/Method/emit(_:with:)" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawView(im)emit:with:">emit(_:<wbr>with:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Same as emit, but meant for Objective-C</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">emit</span><span class="p">(</span><span class="n">_</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="n">with</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">])</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>event</em>
</code>
</td>
<td>
<div>
<p>The event to send.</p>
</div>
</td>
</tr>
<tr>
<td>
<code>
<em>items</em>
</code>
</td>
<td>
<div>
<p>The items to send with this event. Send an empty array to send no data.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A7RawViewC11emitWithAckyAA02OnG8CallbackCSS_AA0A4Data_pdtF"></a>
<a name="//apple_ref/swift/Method/emitWithAck(_:_:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A7RawViewC11emitWithAckyAA02OnG8CallbackCSS_AA0A4Data_pdtF">emitWithAck(_:<wbr>_:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Sends a message to the server, requesting an ack.</p>
<p><strong>NOTE</strong>: 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&rsquo;s api will ack the event being sent.</p>
<p>If an error occurs trying to transform <code>items</code> into their socket representation, a <code><a href="../Enums/SocketClientEvent.html#/s:8SocketIO0A11ClientEventO5erroryA2CmF">SocketClientEvent.error</a></code>
will be emitted. The structure of the error data is <code>[eventName, items, theError]</code></p>
<p>Example:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">emitWithAck</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="nf">timingOut</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span> <span class="k">in</span>
<span class="o">...</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">emitWithAck</span><span class="p">(</span><span class="n">_</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="kt"><a href="../Protocols/SocketData.html">SocketData</a></span><span class="o">...</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt"><a href="../Classes/OnAckCallback.html">OnAckCallback</a></span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>event</em>
</code>
</td>
<td>
<div>
<p>The event to send.</p>
</div>
</td>
</tr>
<tr>
<td>
<code>
<em>items</em>
</code>
</td>
<td>
<div>
<p>The items to send with this event. May be left out.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<h4>Return Value</h4>
<p>An <code><a href="../Classes/OnAckCallback.html">OnAckCallback</a></code>. You must call the <code>timingOut(after:)</code> method before the event will be sent.</p>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@objc(cs)SocketRawView(im)emitWithAck:with:"></a>
<a name="//apple_ref/swift/Method/emitWithAck(_:with:)" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawView(im)emitWithAck:with:">emitWithAck(_:<wbr>with:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Same as emitWithAck, but for Objective-C</p>
<p><strong>NOTE</strong>: 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&rsquo;s api will ack the event being sent.</p>
<p>Example:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">emitWithAck</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">,</span> <span class="nv">with</span><span class="p">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">])</span><span class="o">.</span><span class="nf">timingOut</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span> <span class="k">in</span>
<span class="o">...</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">emitWithAck</span><span class="p">(</span><span class="n">_</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="n">with</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kt"><a href="../Classes/OnAckCallback.html">OnAckCallback</a></span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>event</em>
</code>
</td>
<td>
<div>
<p>The event to send.</p>
</div>
</td>
</tr>
<tr>
<td>
<code>
<em>items</em>
</code>
</td>
<td>
<div>
<p>The items to send with this event. Use <code>[]</code> to send nothing.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<h4>Return Value</h4>
<p>An <code><a href="../Classes/OnAckCallback.html">OnAckCallback</a></code>. You must call the <code>timingOut(after:)</code> method before the event will be sent.</p>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,453 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Enumerations Reference</title>
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
<meta charset="utf-8">
<script src="js/jquery.min.js" defer></script>
<script src="js/jazzy.js" defer></script>
<script src="js/lunr.min.js" defer></script>
<script src="js/typeahead.jquery.js" defer></script>
<script src="js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Section/Enumerations" class="dashAnchor"></a>
<a title="Enumerations Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="index.html">SocketIO Reference</a>
<img class="carat" src="img/carat.png" />
Enumerations Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1>Enumerations</h1>
<p>The following enumerations are available globally.</p>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A9AckStatusO"></a>
<a name="//apple_ref/swift/Enum/SocketAckStatus" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A9AckStatusO">SocketAckStatus</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The status of an ack.</p>
<a href="Enums/SocketAckStatus.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketAckStatus</span> <span class="p">:</span> <span class="kt">String</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A9IOVersionO"></a>
<a name="//apple_ref/swift/Enum/SocketIOVersion" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A9IOVersionO">SocketIOVersion</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The socket.io version being used.</p>
<a href="Enums/SocketIOVersion.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketIOVersion</span> <span class="p">:</span> <span class="kt">Int</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A14IOClientOptionO"></a>
<a name="//apple_ref/swift/Enum/SocketIOClientOption" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A14IOClientOptionO">SocketIOClientOption</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The options for a client.</p>
<a href="Enums/SocketIOClientOption.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketIOClientOption</span> <span class="p">:</span> <span class="kt">ClientOption</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO"></a>
<a name="//apple_ref/swift/Enum/SocketClientEvent" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO">SocketClientEvent</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The set of events that are generated by the client.</p>
<a href="Enums/SocketClientEvent.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketClientEvent</span> <span class="p">:</span> <span class="kt">String</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@E@SocketIOStatus"></a>
<a name="//apple_ref/swift/Enum/SocketIOStatus" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@E@SocketIOStatus">SocketIOStatus</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Represents state of a manager or client.</p>
<a href="Enums/SocketIOStatus.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketIOStatus</span> <span class="p">:</span> <span class="kt">Int</span><span class="p">,</span> <span class="kt">CustomStringConvertible</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@E@SocketEnginePacketType"></a>
<a name="//apple_ref/swift/Enum/SocketEnginePacketType" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@E@SocketEnginePacketType">SocketEnginePacketType</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Represents the type of engine.io packet types.</p>
<a href="Enums/SocketEnginePacketType.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">@objc</span>
<span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketEnginePacketType</span> <span class="p">:</span> <span class="kt">Int</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A13ParsableErrorO"></a>
<a name="//apple_ref/swift/Enum/SocketParsableError" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A13ParsableErrorO">SocketParsableError</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Errors that can be thrown during parsing.</p>
<a href="Enums/SocketParsableError.html" class="slightly-smaller">See more</a>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketParsableError</span> <span class="p">:</span> <span class="kt">Error</span></code></pre>
</div>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,352 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SocketAckStatus Enumeration Reference</title>
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
<meta charset="utf-8">
<script src="../js/jquery.min.js" defer></script>
<script src="../js/jazzy.js" defer></script>
<script src="../js/lunr.min.js" defer></script>
<script src="../js/typeahead.jquery.js" defer></script>
<script src="../js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Enum/SocketAckStatus" class="dashAnchor"></a>
<a title="SocketAckStatus Enumeration Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="../index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="../search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
<img class="carat" src="../img/carat.png" />
SocketAckStatus Enumeration Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1>SocketAckStatus</h1>
<div class="declaration">
<div class="language">
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketAckStatus</span> <span class="p">:</span> <span class="kt">String</span></code></pre>
</div>
</div>
<p>The status of an ack.</p>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<div class="task-name-container">
<a name="/Cases"></a>
<a name="//apple_ref/swift/Section/Cases" class="dashAnchor"></a>
<div class="section-name-container">
<a class="section-name-link" href="#/Cases"></a>
<h3 class="section-name"><p>Cases</p>
</h3>
</div>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A9AckStatusO02noC0yA2CmF"></a>
<a name="//apple_ref/swift/Element/noAck" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A9AckStatusO02noC0yA2CmF">noAck</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>The ack timed out.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">noAck</span> <span class="o">=</span> <span class="s">"NO ACK"</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A9AckStatusO2eeoiySbSS_ACtFZ"></a>
<a name="//apple_ref/swift/Method/==(_:_:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A9AckStatusO2eeoiySbSS_ACtFZ">==(_:<wbr>_:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Tests whether a string is equal to a given SocketAckStatus</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">func</span> <span class="o">==</span> <span class="p">(</span><span class="nv">lhs</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">rhs</span><span class="p">:</span> <span class="kt">SocketAckStatus</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Bool</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A9AckStatusO2eeoiySbAC_SStFZ"></a>
<a name="//apple_ref/swift/Method/==(_:_:)" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A9AckStatusO2eeoiySbAC_SStFZ">==(_:<wbr>_:<wbr>)</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Tests whether a string is equal to a given SocketAckStatus</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">func</span> <span class="o">==</span> <span class="p">(</span><span class="nv">lhs</span><span class="p">:</span> <span class="kt">SocketAckStatus</span><span class="p">,</span> <span class="nv">rhs</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Bool</span></code></pre>
</div>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

View File

@ -1,572 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SocketClientEvent Enumeration Reference</title>
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
<meta charset="utf-8">
<script src="../js/jquery.min.js" defer></script>
<script src="../js/jazzy.js" defer></script>
<script src="../js/lunr.min.js" defer></script>
<script src="../js/typeahead.jquery.js" defer></script>
<script src="../js/jazzy.search.js" defer></script>
</head>
<body>
<a name="//apple_ref/swift/Enum/SocketClientEvent" class="dashAnchor"></a>
<a title="SocketClientEvent Enumeration Reference"></a>
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="../index.html">
SocketIO 16.0.0 Docs
</a>
(100% documented)
</p>
<p class="header-col--secondary">
<form role="search" action="../search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</p>
</header>
<p class="breadcrumbs">
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
<img class="carat" src="../img/carat.png" />
SocketClientEvent Enumeration Reference
</p>
<div class="content-wrapper">
<nav class="navigation">
<ul class="nav-groups">
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html"> PacketType</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
</li>
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section class="section">
<div class="section-content top-matter">
<h1>SocketClientEvent</h1>
<div class="declaration">
<div class="language">
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketClientEvent</span> <span class="p">:</span> <span class="kt">String</span></code></pre>
</div>
</div>
<p>The set of events that are generated by the client.</p>
</div>
</section>
<section class="section">
<div class="section-content">
<div class="task-group">
<div class="task-name-container">
<a name="/Cases"></a>
<a name="//apple_ref/swift/Section/Cases" class="dashAnchor"></a>
<div class="section-name-container">
<a class="section-name-link" href="#/Cases"></a>
<h3 class="section-name"><p>Cases</p>
</h3>
</div>
</div>
<ul class="item-container">
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO7connectyA2CmF"></a>
<a name="//apple_ref/swift/Element/connect" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO7connectyA2CmF">connect</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Emitted when the client connects. This is also called on a successful reconnection. A connect event gets one
data item: the namespace that was connected to.</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">on</span><span class="p">(</span><span class="nv">clientEvent</span><span class="p">:</span> <span class="o">.</span><span class="n">connect</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span><span class="p">,</span> <span class="n">ack</span> <span class="k">in</span>
<span class="k">guard</span> <span class="k">let</span> <span class="nv">nsp</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">as?</span> <span class="kt">String</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>
<span class="c1">// Some logic using the nsp</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">connect</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO10disconnectyA2CmF"></a>
<a name="//apple_ref/swift/Element/disconnect" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO10disconnectyA2CmF">disconnect</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Emitted when the socket has disconnected and will not attempt to try to reconnect.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">on</span><span class="p">(</span><span class="nv">clientEvent</span><span class="p">:</span> <span class="o">.</span><span class="n">disconnect</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span><span class="p">,</span> <span class="n">ack</span> <span class="k">in</span>
<span class="c1">// Some cleanup logic</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">disconnect</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO5erroryA2CmF"></a>
<a name="//apple_ref/swift/Element/error" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO5erroryA2CmF">error</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Emitted when an error occurs.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">on</span><span class="p">(</span><span class="nv">clientEvent</span><span class="p">:</span> <span class="o">.</span><span class="n">error</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span><span class="p">,</span> <span class="n">ack</span> <span class="k">in</span>
<span class="c1">// Some logging</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">error</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO4pingyA2CmF"></a>
<a name="//apple_ref/swift/Element/ping" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO4pingyA2CmF">ping</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Emitted whenever the engine sends a ping.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">on</span><span class="p">(</span><span class="nv">clientEvent</span><span class="p">:</span> <span class="o">.</span><span class="n">ping</span><span class="p">)</span> <span class="p">{</span><span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="k">in</span>
<span class="c1">// Maybe keep track of latency?</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">ping</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO4pongyA2CmF"></a>
<a name="//apple_ref/swift/Element/pong" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO4pongyA2CmF">pong</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Emitted whenever the engine gets a pong.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">on</span><span class="p">(</span><span class="nv">clientEvent</span><span class="p">:</span> <span class="o">.</span><span class="n">pong</span><span class="p">)</span> <span class="p">{</span><span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="k">in</span>
<span class="c1">// Maybe keep track of latency?</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">pong</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO9reconnectyA2CmF"></a>
<a name="//apple_ref/swift/Element/reconnect" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO9reconnectyA2CmF">reconnect</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Emitted when the client begins the reconnection process.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">on</span><span class="p">(</span><span class="nv">clientEvent</span><span class="p">:</span> <span class="o">.</span><span class="n">reconnect</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span><span class="p">,</span> <span class="n">ack</span> <span class="k">in</span>
<span class="c1">// Some reconnect event logic</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">reconnect</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO16reconnectAttemptyA2CmF"></a>
<a name="//apple_ref/swift/Element/reconnectAttempt" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO16reconnectAttemptyA2CmF">reconnectAttempt</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Emitted each time the client tries to reconnect to the server.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">on</span><span class="p">(</span><span class="nv">clientEvent</span><span class="p">:</span> <span class="o">.</span><span class="n">reconnectAttempt</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span><span class="p">,</span> <span class="n">ack</span> <span class="k">in</span>
<span class="c1">// Some reconnect attempt logging</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">reconnectAttempt</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO12statusChangeyA2CmF"></a>
<a name="//apple_ref/swift/Element/statusChange" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO12statusChangeyA2CmF">statusChange</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Emitted every time there is a change in the client&rsquo;s status.</p>
<p>The payload for data is [SocketIOClientStatus, Int]. Where the second item is the raw value. Use the second one
if you are working in Objective-C.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">on</span><span class="p">(</span><span class="nv">clientEvent</span><span class="p">:</span> <span class="o">.</span><span class="n">statusChange</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span><span class="p">,</span> <span class="n">ack</span> <span class="k">in</span>
<span class="c1">// Some status changing logging</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">statusChange</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:8SocketIO0A11ClientEventO16websocketUpgradeyA2CmF"></a>
<a name="//apple_ref/swift/Element/websocketUpgrade" class="dashAnchor"></a>
<a class="token" href="#/s:8SocketIO0A11ClientEventO16websocketUpgradeyA2CmF">websocketUpgrade</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Emitted when when upgrading the http connection to a websocket connection.</p>
<p>Usage:</p>
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">on</span><span class="p">(</span><span class="nv">clientEvent</span><span class="p">:</span> <span class="o">.</span><span class="n">websocketUpgrade</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span><span class="p">,</span> <span class="n">ack</span> <span class="k">in</span>
<span class="k">let</span> <span class="nv">headers</span> <span class="o">=</span> <span class="p">(</span><span class="n">data</span> <span class="k">as</span> <span class="p">[</span><span class="kt">Any</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
<span class="c1">// Some header logic</span>
<span class="p">}</span>
</code></pre>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight swift"><code><span class="k">case</span> <span class="n">websocketUpgrade</span></code></pre>
</div>
</div>
</section>
</div>
</li>
</ul>
</div>
</div>
</section>
</article>
</div>
<section class="footer">
<p>&copy; 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
</div>
</html>

Some files were not shown because too many files have changed in this diff Show More